Compare commits

..

No commits in common. "main" and "feat/premiere-installer" have entirely different histories.

933 changed files with 229748 additions and 47211 deletions

View file

@ -22,56 +22,5 @@ SESSION_SECRET=changeme
# MAM API Configuration # MAM API Configuration
MAM_API_URL=http://mam-api:3000 MAM_API_URL=http://mam-api:3000
# Node Agent Authentication # Auth (set to 'true' to require login; false for open/dev mode)
# Bearer token for node-agent to authenticate with mam-api /driver/* endpoints. AUTH_ENABLED=false
# Generate with: openssl rand -hex 32
NODE_AGENT_TOKEN=changeme
# Auth — default to ON in production. Setting to 'false' is a dev-only escape
# hatch that disables all auth checks and attaches a synthetic 'dev' user to
# every request. Never run with AUTH_ENABLED=false on a network you don't control.
#
# RBAC v2 note: with AUTH_ENABLED=true, per-project access is enforced. Service
# API tokens (capture sidecar, Premiere panel, integrations) must belong to a
# user with the access they need — an 'admin' user (full access), or a user with
# the right project grants. A non-admin service token with no grants will get
# 403 on asset registration (ingest) and streaming. In dev mode the synthetic
# user is admin, so this only matters once auth is on.
AUTH_ENABLED=true
# CORS allowlist — comma-separated origins that may carry credentials to the API.
# Same-origin requests via the nginx reverse proxy do not need to be listed here.
# Leave empty to allow any origin (DEV ONLY).
ALLOWED_ORIGINS=
# Reverse-proxy trust — set 'true' when the API sits behind nginx terminating HTTPS,
# so secure-cookie + X-Forwarded-Proto behave correctly. ALSO required for accurate
# per-IP login rate-limiting (otherwise req.ip is always the nginx IP).
TRUST_PROXY=false
# Google OAuth (OIDC) sign-in — OPTIONAL. Leave the client id/secret blank to
# disable; the "Sign in with Google" button and the /auth/google routes only
# activate when all three of CLIENT_ID, CLIENT_SECRET, and REDIRECT_URL are set.
# Create an OAuth 2.0 Client (type: Web application) in Google Cloud Console and
# add OAUTH_REDIRECT_URL to its authorized redirect URIs.
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Must exactly match a redirect URI on the OAuth client, e.g.
# https://dragonflight.live/api/v1/auth/google/callback
OAUTH_REDIRECT_URL=
# Restrict sign-in to one Google Workspace domain (recommended). First login from
# an allowed-domain account auto-provisions a NEW 'viewer' account (matched only
# by Google's stable subject id, never by email — so a Google login can never
# seize a pre-existing local account). An admin then grants project access.
# Leave blank to allow any verified Google account to self-provision (NOT advised).
GOOGLE_ALLOWED_DOMAIN=
# Note: if a Google-linked account also has TOTP enabled, sign-in still requires
# the authenticator code (Google is treated as the first factor). Accounts without
# TOTP complete sign-in in one Google step.
# Playout / Master Control (MCR)
# Image tag the mam-api spawns when a channel starts. Build with:
# docker compose --profile build-only build playout
PLAYOUT_IMAGE=wild-dragon-playout:latest
# Base AMCP port — each channel binds to BASE + channel_id (in CasparCG terms).
PLAYOUT_AMCP_BASE_PORT=5250

4
.gitignore vendored
View file

@ -27,8 +27,8 @@ services/editor/**/node_modules
services/editor/**/dist services/editor/**/dist
services/editor/.pnpm-store services/editor/.pnpm-store
# Blackmagic DeckLink SDK headers are now committed (private/internal repo) under services/capture/sdk/. # Blackmagic DeckLink SDK + runtime libs (operator-supplied; see services/capture/build-with-decklink.sh)
# Runtime .so libs (libDeckLinkAPI.so) come from the DesktopVideo driver install and are not committed. services/capture/sdk/
services/capture/lib/ services/capture/lib/
# Editor backups # Editor backups

153
DESIGN.md
View file

@ -1,153 +0,0 @@
# Design system
Documented from the live tokens in `services/web-ui/public/styles.css` and the patterns used across `screens-*.jsx`. Treat this as the source of truth for shared primitives; pages may override locally but should not invent new color or type scales.
## Color
Dark theme only. Tokens live in `:root` in `styles.css`. Tinted neutrals — no `#000`, no `#fff`.
### Surfaces
| Token | Hex | Use |
|---|---|---|
| `--bg-0` | `#0B0D11` | Page background, deepest surface |
| `--bg-1` | `#14171E` | Panels, sidebars, primary chrome |
| `--bg-2` | `#1B1F27` | Panel headers, hover state |
| `--bg-3` | `#232833` | Inputs, raised buttons, badges |
| `--bg-4` | `#2D3340` | Strongly raised elements (rare) |
### Borders + overlays
| Token | Use |
|---|---|
| `--border` (rgba white 6%) | Default 1px separator |
| `--border-strong` (rgba white 10%) | Emphasized separator |
| `--border-stronger` (rgba white 14%) | Hover/active border |
| `--hover` (rgba white 4%) | Subtle hover fill |
| `--hover-strong` (rgba white 7%) | Stronger hover fill |
### Text
| Token | Hex | Use |
|---|---|---|
| `--text-1` | `#F2F3F6` | Primary content |
| `--text-2` | `#A8AEBC` | Secondary content |
| `--text-3` | `#6B7280` | Labels, metadata |
| `--text-4` | `#4B5260` | Section labels, off-month, disabled |
### Accent
`--accent: #5B7CFA` (Frame.io-ish blue). Soft variants `--accent-soft` (14%) and `--accent-soft-2` (22%) for fills. `--accent-text: #B4C3FF` for high-contrast accent text.
**Restrained strategy.** Accent is the only saturated color in chrome. Status colors below appear only where they reflect actual state. Project colors appear only on project chips.
### Status
| Token | Hex | Use |
|---|---|---|
| `--success` | `#2DD4A8` | Done, healthy, ready |
| `--warning` | `#F5A623` | Processing, attention-needed |
| `--danger` | `#FF5B5B` | Failed, error |
| `--live` | `#FF3B30` | Currently recording (broadcast red, intentionally hotter than `--danger`) |
| `--purple` | `#B57CFA` | Editor / dev tags |
Each has a `*-soft` variant at ~14% for background fills.
### Project palette
Six fixed colors cycled by index in `data.jsx` (`PROJECT_COLORS`):
`#5B7CFA · #2DD4A8 · #FF5B5B · #F5A623 · #B57CFA · #6B7280`
Used only on the project chip / rail dot. Do not reuse for status meaning.
## Typography
- **Sans:** Geist (with `cv11`, `ss01` features enabled). All UI text by default.
- **Mono:** Geist Mono. URLs, IDs, timestamps, durations, technical metadata.
Body scale runs small for density:
| Size | Use |
|---|---|
| 10.5px, 600, uppercase, 0.060.08em letterspacing | Column heads, section labels |
| 1111.5px | Metadata, secondary rows |
| 1212.5px | Body in lists/tables |
| 13px, 500600 | Row labels, button text |
| 14px | Default body |
| 15px, 600 | Modal titles, panel heads |
| 2228px, 600+ | Page H1 (`.page-header h1`) |
Never use `gradient text` (impeccable absolute ban). Emphasis via weight and size only.
## Layout
- Sidebar: 232px fixed (`--sidebar-w`).
- Topbar: 56px (`--topbar-h`).
- Row height: 44px default, 36px compact (`--row-h`, `data-density="compact"`).
- Gap unit: 16px default, 12px compact (`--gap`).
- Border radius scale: 4 / 6 / 8 / 12 / 16 px (`--r-xs` → `--r-xl`).
- Panels (`.panel`): `--bg-1` + 1px `--border` + `--r-lg`. Use for grouped lists, not for every section.
- Do NOT nest panels.
### Page header
Standard screens use `.page > .page-header > h1`. Three screens are documented exceptions because they need full-bleed layouts and their own top-chrome:
- **Home** uses `.launcher` (lobby pattern: hero logo + tile grid + status pip).
- **Library** uses `.library-layout` (dual-pane rail + main). The h1 sits inside `.library-toolbar` as `.toolbar-title`.
- **Editor** uses `.editor-shell` (NLE with timeline + monitors). The beta banner doubles as its top chrome.
All other screens should render `<div className="page"><div className="page-header"><h1>…</h1>…</div>…</div>` for consistent IA and screen-reader hierarchy.
## Shadow
Two tokens, used sparingly:
- `--shadow-card`: subtle inset highlight + soft outer. Default for raised inputs.
- `--shadow-pop`: modal / popover / context menu.
No drop shadows on flat surfaces. No glow effects (except: the EPG now-line uses a tight `box-shadow` for the broadcast-red glow, and live status dots have a pulse halo; these are state cues, not decoration).
## Motion
- Default transition: 80120ms on background/border (`transition: background 80ms, border 80ms`).
- Heavier reveals: 200ms.
- Easing: prefer ease-out (no bounce, no elastic).
- Don't animate layout (width/height/top); animate transforms and opacity.
## Patterns
### Status badges (`.badge`)
Variants: `live` (red, animated dot), `success`, `danger`, `warning`, `accent`, `neutral`, `outline`. Tiny — 910px font, ~2px vertical padding. Reserved for state, not labels.
### Row tables (`.user-row`, `.token-row`, `.job-row`, `.schedule-row`, etc.)
CSS-grid with explicit columns. Header row uses `.head` (uppercase 10.5px). No card stacking — these are dense data lists.
### Schedule EPG (`.epg-*`)
Broadcast timeline pattern. Recorder rows × time-of-day axis. Single scrolling container with sticky left gutter (220px) and sticky top ruler (32px). Hour rhythm via `repeating-linear-gradient`. Now-line is a 1px hot-red vertical bar with `--live` glow, animated by re-rendering the line component every second (transform-only positioning, no layout thrash). Event blocks are absolute-positioned within each row, colored via `--epg-block-color` set per recorder's project color. Live events get a red gradient + pulse; failures get a glyph + full red border; past events fade to 0.55 opacity.
### Inputs
`.field-input``--bg-3` fill, 1px `--border`, `--r-sm`, 12.5px font. Focus: `--border-strong`.
### Status dot (`.signal-dot`, `.rec-dot`, etc.)
Small (~68px) circle, used inline with text. Recording dots pulse with a keyframe animation.
## Impeccable absolute bans (apply project-wide)
- No `border-left` / `border-right` greater than 1px as a colored accent (rewrite with full borders, leading icons, or background tint).
- No `background-clip: text` gradient text.
- No glassmorphism (blur + translucent) decoratively.
- No hero-metric template (big number, small label, gradient accent, supporting stats).
- No identical card grids.
- Modal as last resort — exhaust inline alternatives first.
- No em dashes in code or copy. Use commas, colons, parentheses, periods.
## To extend
When a new design need arises, prefer adding a variant to an existing primitive over inventing a new token. New tokens land in `styles.css`. New components land in the relevant `screens-*.jsx` only if reused; otherwise keep them local.

View file

@ -1,61 +0,0 @@
# Product
## What it is
Dragonflight (codebase name; UI brand: "Dragonflight · Wild Dragon Broadcast") is an on-prem broadcast media asset manager and live ingest controller. Operators capture from SRT, RTMP, and SDI sources, schedule windowed recordings against named recorders, transcode/proxy in the background, browse and clip in a library, import from YouTube, and hand off to Premiere or an in-house editor.
The deployable surface is a React (Babel-in-browser) single-page app served by nginx, talking to a Node/Express API backed by Postgres + Redis + BullMQ, with capture and worker containers handling the actual media.
Stack lives at `services/web-ui` (UI), `services/mam-api` (API), `services/capture`, `services/worker`, `services/editor`.
## Register
**Product.** This is operator UI for a working broadcast tool, not a brand site or marketing surface. Design serves the operator's job, not the brand's identity.
## Users
Primary: broadcast operators and engineers running live productions. They schedule and supervise back-to-back recordings across multiple recorders in a single shift. They care about: what's recording right now, what's about to start, what failed, and which recorder is bound to what source.
Secondary: editors and producers who consume the resulting library, comment on assets, request proxy regeneration. They mostly live in the Library and Asset detail screens, not the scheduler.
Tertiary: admins managing recorders, users, cluster nodes, and storage. Live in the Admin screens.
## Product purpose
Replace a stack of one-trick tools (NewBlue scheduler, vMix capture, ad-hoc Premiere ingest, manual S3 syncs) with a single operator surface that supervises recorders, owns the asset catalog through proxy generation, and stays out of the editor's way once footage lands.
## Tone
Function-first. Dense. Operations-room. Mono fonts where data lives. Small type. Restrained chrome. The operator should be able to glance at any screen and read the state of the system in under a second; they should never wonder "is this still happening" or "did that finish."
Not: marketing-warm, conversational, gamified, congratulatory.
## Strategic principles
1. **Glance-readable status.** Every list, every cell, every badge must answer "what is the state of this thing right now" without a hover.
2. **Trust the operator.** No confirmation modals for reversible actions. No nag, no toasts for routine success. Errors stay visible until acknowledged.
3. **Time is the spine.** This product is about time-based events (recordings, schedules, jobs). UIs should privilege time as a primary axis, not bury it under categorical filters.
4. **Density over whitespace.** Operators run multi-monitor setups and want maximum signal per pixel. Generous whitespace is a brand-site reflex; reject it here.
5. **No half-states.** Pending UIs disable controls; live UIs show live data; failed UIs show the failure inline, not in a separate notification feed.
## Anti-references
Steer away from:
- **Linear-pastel SaaS aesthetics.** Purples, mint accents, friendly empty states with cartoon line illustrations.
- **Google-Calendar generic.** A neutral month grid with rounded event chips, no operational signal, optimized for "is Friday free" rather than "is recorder A in conflict at 14:00."
- **Gantt-chart project-management feel.** Implies long-horizon planning of tasks with dependencies; this product is hour-scale broadcast operations.
- **Cards-for-everything.** Identical card grids of icon+label+value. Particularly the SaaS hero-metric template.
- **Decorative blur / glassmorphism / gradient text.** Read as decorative AI slop in a broadcast-ops context.
- **NewBlue / Wirecast skinning.** Heavy bevels, gradient buttons, drop shadows. Read as outdated broadcast software.
## Decision context (Schedule v2)
The Schedule screen was rebuilt as an EPG (electronic program guide) timeline. Operator confirmed:
- Density: **heavy / back-to-back, many recorders all day** — month grid was the wrong primary.
- At-a-glance signals: now/next, recorder bookings (conflicts), project context, failure history.
- Aesthetic: **studio / cinematic — dark, type-led, accent moments.** DaVinci-Resolve-panel territory.
- Scope: full rethink — replace the primary view.
Implementation: recorder rows × time-of-day horizontal axis, sticky gutter + ruler, vertical hot-red now-line, event blocks colored by project, status pills in a top strip. Today / Week / List views.

250
README.md
View file

@ -1,128 +1,49 @@
# Dragonflight # Dragonflight
Self-hosted broadcast media-asset management system that replaces legacy tools like Grass Valley AMPP and FramelightX. Handles live ingest, growing-file editing, scheduling, transcoding, and asset management in a single operator-focused interface. Self-hosted broadcast media-asset management. Replaces Grass Valley AMPP
FramelightX. SDI / SRT / RTMP ingest, growing-file editing via Premiere
Pro, S3-compatible storage, scheduling, and a queue-driven proxy pipeline.
> Repo renamed from `wild-dragon``dragonflight` (2026-05-23). The old URL still redirects. > Repo renamed from `wild-dragon``dragonflight` (2026-05-23). The old
> URL still redirects.
## Home Dashboard ## Features
<img src="docs/screenshots/01-home.png" alt="Home Dashboard" width="800" /> - **Ingest** — SRT (caller + listener), RTMP, and SDI capture via
Blackmagic DeckLink cards (FFmpeg patched against SDK 16.x); per-recorder
codec settings (ProRes / H.264 / DNxHR / HEVC) and audio routing
- **Growing-file editing** — capture writes the hi-res master to a local
SMB landing zone; editors can mount the share in Premiere Pro and edit
the live file via the included CEP panel, then relink to the final S3
master after promotion
- **Recorder scheduler** — one-shot, daily, or weekly windows; a 15s tick
loop fires the existing /recorders/:id/start + /stop endpoints
- **Library** — projects, bins, asset detail with frame-anchored
persistent comments, right-click context menu (move-to-bin, rename,
delete), and a global cmd/ctrl-K search across assets / projects /
recorders / jobs / users
- **Jobs** — BullMQ-backed proxy + thumbnail queue with per-job retry,
bulk "retry all failed", and inline error messages
- **Settings** — S3 (with env-var fallback), global proxy encoder
(CPU/libx264 or GPU/NVENC/VAAPI), growing-files config, capture SDK
uploader (Blackmagic / AJA / Deltacast)
- **Cluster** — primary + worker topology with heartbeat health, remote
node-agent for off-host DeckLink capture
- **API**`deploy/api-smoke.sh` exercises every endpoint (27 routes,
pass/fail summary)
The home screen provides quick access to all major features and displays system status at a glance: ## Services
- **Library** — Browse projects, bins, and assets with hover-scrub previews
- **Recorders** — View configured capture devices and their status
- **Editor** — Timeline editor with cross-clip preview and render queue
- **Jobs** — Proxy and thumbnail queue with retry controls
- **Settings** — Configure storage, encoder, growing files, and capture SDK
- **Dashboard** — Operations view showing recent activity, job queue, and cluster health
--- | Service | Port | Description |
|---------|------|-------------|
| **web-ui** | 47434 | Browser SPA + capture controls |
| **mam-api** | 47432 | REST API + recorder orchestration + scheduler tick |
| **capture** | 47433 / 9000 / 1935 | DeckLink/SRT/RTMP capture sidecar |
| **worker** | — | BullMQ proxy + thumbnail workers |
| **db** | 5432 | PostgreSQL 16 |
| **queue** | 6379 | Redis 7 |
## Core Features ## Quick start
### 1. Live Ingest & Capture
**Multi-protocol source capture with per-recorder codec settings**
Dragonflight ingests from multiple sources simultaneously:
- **SRT** (Secure Reliable Transport) — caller and listener modes
- **RTMP** — standard streaming protocol
- **SDI** — via Blackmagic DeckLink cards with FFmpeg SDK 16.x patches
Each recorder can be configured with independent codec settings:
- ProRes (hi-res masters)
- H.264 / H.265 (proxies)
- DNxHR (Avid compatibility)
Audio routing and per-source configuration ensure flexibility for multi-camera productions.
### 2. Growing-File Editing
**Live editing in Premiere Pro while capture is still writing**
Editors mount the SMB landing zone directly in Premiere Pro and edit the live master file as it's being written. The included CEP (Custom Extension Panel) provides:
- Real-time clip detection and frame-accurate trimming
- One-click relink to final S3 master after promotion
- No waiting for capture to finish before editorial begins
### 3. Recorder Scheduler
**Time-windowed recording automation**
Schedule recordings with:
- One-shot, daily, or weekly recurrence
- Automatic start/stop via 15-second tick loop
- Conflict detection across recorders
- Project and bin assignment at schedule time
### 4. Library & Asset Management
**Browse, search, and organize captured footage**
The Library screen provides:
- Project and bin hierarchy
- Asset detail view with frame-anchored persistent comments
- Right-click context menu (move-to-bin, rename, delete)
- Global cmd/ctrl-K search across assets, projects, recorders, jobs, and users
- Hover-scrub preview with HLS playback
### 5. Jobs Queue
**BullMQ-backed proxy and thumbnail generation**
Automated background processing:
- Per-job retry logic with exponential backoff
- Bulk "retry all failed" for batch recovery
- Inline error messages with actionable diagnostics
- Status tracking: ingesting → processing → ready
Proxy encoder options:
- CPU-based: libx264 (H.264)
- GPU-accelerated: NVENC (NVIDIA) or VAAPI (AMD/Intel)
### 6. Timeline Conform & Export
**FCP XML export with server-side FFmpeg rendering**
The Premiere Pro panel exports FCP XML with:
- Server-side conform via FFmpeg
- Multiple output formats: H.264, H.265, ProRes
- Resolution presets: Broadcast, Web, Archive
- Batch processing with job queue integration
### 7. Hi-Res Auto-Relink
**One-click batch relink of proxy clips to frame-accurate server-trimmed masters**
After editing on proxies:
- Select clips in Premiere
- Trigger relink from the CEP panel
- Server trims hi-res segments to exact in/out points
- Concurrent trim worker pool for speed
- 24-hour TTL with automatic cleanup
### 8. Settings & Configuration
**Centralized control for storage, encoding, and capture**
Configure:
- **S3 Storage** — endpoint, bucket, credentials (with env-var fallback)
- **Proxy Encoder** — CPU vs GPU, bitrate, resolution
- **Growing Files** — SMB path, retention, auto-promotion
- **Capture SDK** — Blackmagic, AJA, or Deltacast uploader selection
### 9. Cluster & Distributed Capture
**Primary + worker topology with remote DeckLink nodes**
- Primary node runs API, scheduler, and web UI
- Worker nodes handle proxy/thumbnail jobs
- Remote capture nodes run DeckLink cards off-host
- Heartbeat health monitoring
- Automatic failover and recovery
### 10. Admin & User Management
**Role-based access, token auth, and cluster monitoring**
- User creation and role assignment
- API token generation for integrations
- Container and cluster node status
- System health dashboard
---
## Quick Start
```bash ```bash
# Clone (repo renamed; old URL still redirects) # Clone (repo renamed; old URL still redirects)
@ -160,98 +81,23 @@ assets POST ──► proxy job ──► worker
└─ status: ingesting → processing → ready └─ status: ingesting → processing → ready
``` ```
## Tech Stack ## Tech stack
- **Runtime:** Node.js 22, Docker Compose - **Runtime:** Node.js 22, Docker Compose
- **Backend:** Express, PostgreSQL 16, Redis 7 + BullMQ - **Backend:** Express, PostgreSQL 16, Redis 7 + BullMQ
- **Frontend:** Vanilla React via in-browser Babel (no bundler), hls.js - **Frontend:** Vanilla React via in-browser Babel (no bundler), hls.js
- **Media:** FFmpeg 7.1 with SDK 16 DeckLink patches - **Media:** FFmpeg 7.1 with SDK 16 DeckLink patches; ProRes, H.264, HEVC,
- **Codecs:** ProRes, H.264, H.265, DNxHR, MOV/MP4/MXF containers DNxHR, MOV/MP4/MXF containers
- **Storage:** S3-compatible (RustFS) for masters, proxies, thumbnails - **Storage:** S3-compatible (RustFS) for masters + proxies + thumbnails
## Services
| Service | Port | Purpose |
|---------|------|---------|
| **web-ui** | 47434 | Browser SPA + capture controls |
| **mam-api** | 47432 | REST API + recorder orchestration + scheduler |
| **capture** | 47433 / 9000 / 1935 | DeckLink/SRT/RTMP ingest sidecar |
| **worker** | — | BullMQ proxy + thumbnail workers |
| **db** | 5432 | PostgreSQL 16 |
| **queue** | 6379 | Redis 7 |
---
## Workflow Example: Live-to-Edit
1. **Operator** schedules a recording on Recorder A for 14:0015:30, assigns to "News/Segment-A" project
2. **Capture** starts at 14:00, writes ProRes master to SMB landing zone
3. **Editor** mounts SMB in Premiere, opens the live .mov file via the CEP panel
4. **Editor** trims and marks in/out points while capture is still writing
5. **Capture** finishes at 15:30, promotion worker uploads master to S3
6. **Editor** clicks "Relink to Master" in CEP panel
7. **Server** trims hi-res segment to exact in/out, stores for 24 hours
8. **Premiere** relinks proxy clips to trimmed master
9. **Editor** exports final timeline via FCP XML conform
Total time from end of capture to relinked master: ~2 minutes.
---
## Operations ## Operations
- `deploy/api-smoke.sh` — verify every API endpoint after deploy - `deploy/api-smoke.sh` — verify every API endpoint after a deploy
- `deploy/onboard-node.sh` — provision a remote worker host - `deploy/onboard-node.sh` — provision a remote worker host (DeckLink
- `deploy/test-cluster.sh` — primary↔worker connectivity smoke test cards on a separate machine)
- `docs/GROWING_FILES_QUICKSTART.md` — Premiere CEP panel install + growing-file flow - `deploy/test-cluster.sh` — primary↔worker connectivity smoke
- `docs/GROWING_FILES_QUICKSTART.md` — Premiere CEP panel install +
## Authentication growing-file capture flow
Dragonflight uses local username/password authentication with two transports:
- **Browser:** session cookie (`dragonflight.sid`), 8 hour absolute + 1 hour idle timeout.
- **Premiere panel / scripts:** SHA-256-hashed bearer tokens issued from `Settings → API Tokens`.
### First-run setup
On a fresh install with `AUTH_ENABLED=true`, navigate to the web UI in a browser.
With no users in the database, the login screen renders a "First-run setup" form
instead — fill it in to create the first admin and you are logged in immediately.
Subsequent users are created from `Settings → Users` (any signed-in user can
create others — flat access).
### Dev mode
Setting `AUTH_ENABLED=false` disables all auth checks; a synthetic `dev` user
is attached to every request. **Never deploy this way.** The dev user row is
seeded with a hash that no real password can match, so flipping
`AUTH_ENABLED=true` later does not expose the dev account.
### Recovering a forgotten admin password
Any signed-in user can reset another user's password from `Settings → Users`.
If no one can sign in (all admins forgot their passwords), reset directly in
Postgres:
```sql
-- generate a fresh bcrypt hash with:
-- node -e "import('bcrypt').then(b => b.default.hash(process.argv[1], 12).then(h => console.log(h)))" 'new-passphrase-here'
UPDATE users SET password_hash = '<bcrypt-hash>', password_updated_at = NOW()
WHERE username = 'admin';
```
### `AUTH_ENABLED` transition
When flipping `AUTH_ENABLED=false``true` on an existing install:
1. Ensure `SESSION_SECRET` is set to a stable value (rotating it logs everyone out).
2. Set `ALLOWED_ORIGINS` to the public origin(s) of the web UI.
3. Set `TRUST_PROXY=true` when behind nginx (required for rate-limit accuracy).
4. Restart `mam-api`.
5. Visit the UI — first-run setup will appear if no real users exist yet.
---
## License ## License

View file

@ -1,101 +0,0 @@
# Playout / Master Control — Implementation Work Log
**Branch:** `feat/playout-mcr` (off `main`)
**Started:** 2026-05-30
**Status:** Code complete, awaiting runtime validation
Tracks the build of the playout (MCR) subsystem against the design at
`docs/superpowers/specs/2026-05-30-playout-mcr-design.md`.
---
## Commit sequence
| # | Commit | Scope |
|---|--------|-------|
| 1 | `docs(playout)` | Design spec, §7 questions answered |
| 2 | `feat(mam-api): migration 029` | Six tables, failover columns, audio_normalized flag |
| 3 | `feat(worker): playout-stage` | S3 → /media + EBU R128 loudnorm + index.js wiring |
| 4 | `feat(playout): sidecar` | CasparCG image + AMCP shim, HLS preview consumer, fps-aware frame math |
| 5 | `feat(mam-api): /playout control plane + auto-failover` | Routes + scheduler health tick + restartChannel helper |
| 6 | `feat(web-ui): MCR page` | screens-playout, styles, app/shell/index.html wiring |
| 7 | `build(playout): compose wiring + .env knobs` | /media volume, queue addition, build-only service |
| 8 | `docs(playout): work log` | This file |
## Resolved §7 decisions (2026-05-30)
- **Audio loudness:** pre-normalize at stage time. ffmpeg `loudnorm` two-pass
(I=-23 LUFS, TP=-1 dBTP, LRA=11), linear mode preserves dynamics. Output
AAC 192k @ 48 kHz, video stream copied. Per-item `audio_normalized` flag
so re-stages of the same asset skip the pass.
- **Frame rate:** `1080p5994` default (was `1080i5994`). Per-channel
override allowed via `video_format`. `fpsFor(videoFormat)` helper in
the sidecar drives SEEK / LENGTH / transition-frames math.
- **Preview latency:** HLS v1. CasparCG runs a second FFMPEG consumer
alongside the primary output, writing `/media/live/<channel_id>/index.m3u8`
(~600 kbps, 2s segments, 6-window list). Web UI plays via the existing
HLS plumbing.
- **Failover:** auto-restart on healthy node for NDI/SRT/RTMP. Alert-only
for DeckLink (device-index pinning makes blind re-placement risky).
Scheduler tick (PG advisory lock, same lock as recorder schedules) polls
sidecar `/status`; ~3 missed checks → `restartChannel(id)` picks the most
recently-seen-online other node, bumps `restart_count`, calls `/start`.
## Architecture notes
**Sidecar model.** One CasparCG container per channel. Spawned by mam-api
via local Docker socket (primary node) or remote node-agent
`/sidecar/start`. Tracked in `playout_sidecars` plus `playout_channels.container_id`.
Killed on `/stop` or by `restartChannel` during failover.
**Media flow.**
```
S3 master/proxy → playout-stage worker → /media/playout/<assetId>.<ext>
(loudnormed, AAC@-23 LUFS)
CasparCG channel #1
primary consumer HLS consumer
(DeckLink/NDI/ ↓
SRT/RTMP) /media/live/<ch_id>/*.m3u8
```
**Port contention.** `assertDeckLinkFree()` blocks starting a SDI channel
when a recorder or another channel on the same node+device_index is active.
**Failover scope.** NDI/SRT/RTMP have no hardware tie, so any healthy
cluster_node is eligible. DeckLink channels surface an alert in the UI
(`status='error'` + `error_message`) and require operator intervention.
## Testing checklist
- [ ] Apply migration 029 on dev DB
- [ ] Build playout image: `docker compose --profile build-only build playout`
- [ ] Build web-ui (`screens-playout` joins the esbuild list automatically)
- [ ] Create channel via POST /api/v1/playout/channels (SRT first, no HW)
- [ ] Stage 2-3 assets to a playlist, verify loudnorm metadata in stderr
- [ ] Start channel → sidecar container appears in `docker ps`
- [ ] AMCP smoke: `telnet <host> 5250`, `VERSION`, `INFO`
- [ ] Play playlist; verify HLS at /media/live/<id>/index.m3u8
- [ ] Skip / pause / resume / stop
- [ ] As-run log: GET /api/v1/playout/channels/:id/asrun
- [ ] Kill sidecar container → scheduler should restart on another node
within ~3 ticks (~45s), restart_count increments
- [ ] DeckLink channel kill: status flips to 'error', NO restart attempt
- [ ] Try starting a decklink channel on a device_index already held by a
recorder → 409
- [ ] MCR UI smoke: nav entry visible, page renders, drag-drop adds items,
transport buttons hit the API
## Known gaps (deferred)
- No WebRTC preview (HLS-only v1 — 4-6s lag, fine for confidence monitor).
- No graphics/CG overlay layer in Phase A (templates land in Phase B).
- No Phase B scheduler / 24/7 wall-clock channel (schema is in place,
scheduler tick is not).
- No multi-channel grid view (one channel at a time per page).
- No timecode / remaining-duration overlay (would need CasparCG INFO poll).
- No audio level meters on the UI.
- `restartChannel` updates DB state and triggers `/start`; if the new node
also fails repeatedly, there's no exponential backoff yet — bounded only
by the manual stop button.

View file

@ -1,297 +0,0 @@
#!/usr/bin/env bash
# ============================================================================
# install-driver.sh <vendor>
# ----------------------------------------------------------------------------
# Idempotent HOST installer for capture-card runtime drivers / SDKs.
#
# Runs ON the cluster node's HOST kernel. The node-agent invokes it inside a
# one-shot PRIVILEGED ubuntu container that bind-mounts this repo plus the host
# paths needed to affect the host kernel (/lib/modules, /usr/src, /boot, /dev,
# and the host apt/dpkg via the mounted root). dkms / modprobe / ldconfig
# therefore operate against the running host kernel.
#
# Reads the proprietary vendor file(s) from sdk/<vendor>/ (in this repo).
# NO binaries are committed — if the expected file is missing the script exits
# non-zero with a clear message telling the operator what to drop in.
#
# Vendors (ALLOWLIST — nothing else is accepted):
# blackmagic Desktop Video .deb (DKMS kernel module)
# aja NTV2 driver source/SDK (built kernel module)
# deltacast VideoMaster installer (kernel module)
# ndi redistributable runtime libs (user-space only, no module)
#
# Exit codes:
# 0 installed (or already present / up to date)
# 2 bad usage / unknown vendor
# 3 expected vendor file missing in sdk/<vendor>/
# 4 missing kernel headers (cannot build DKMS / module)
# 5 build / install / module-load failure
#
# `bash -n` must pass. set -euo pipefail with `|| true` guarding every probe.
# ============================================================================
set -euo pipefail
# ---------------------------------------------------------------------------
# Resolve our own repo dir (deploy/ -> repo root), regardless of CWD.
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
REPO_DIR="$(cd "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
SDK_ROOT="$REPO_DIR/sdk"
VENDOR="${1:-}"
KVER="$(uname -r 2>/dev/null || echo unknown)"
REBOOT_REQUIRED=0
log() { echo "[install-driver] $*"; }
warn() { echo "[install-driver] WARN: $*" >&2; }
die() { echo "[install-driver] ERROR: $*" >&2; exit "${2:-5}"; }
usage() {
echo "Usage: install-driver.sh <blackmagic|aja|deltacast|ndi>" >&2
exit 2
}
[ -n "$VENDOR" ] || usage
case "$VENDOR" in
blackmagic|aja|deltacast|ndi) : ;;
*) echo "[install-driver] ERROR: unknown vendor '$VENDOR' (allowed: blackmagic aja deltacast ndi)" >&2; exit 2 ;;
esac
VENDOR_DIR="$SDK_ROOT/$VENDOR"
log "vendor=$VENDOR kernel=$KVER repo=$REPO_DIR"
log "reading vendor files from $VENDOR_DIR"
[ -d "$VENDOR_DIR" ] || die "vendor dir $VENDOR_DIR does not exist (repo not mounted?)" 3
# Pick the newest file matching a glob; echo its path or empty.
newest_match() {
# shellcheck disable=SC2012
ls -1t $1 2>/dev/null | head -n1 || true
}
ensure_headers() {
if [ -d "/lib/modules/$KVER/build" ] || dpkg -s "linux-headers-$KVER" >/dev/null 2>&1; then
log "kernel headers for $KVER present"
return 0
fi
log "installing linux-headers-$KVER ..."
apt-get update -y >/dev/null 2>&1 || true
if ! apt-get install -y "linux-headers-$KVER" >/dev/null 2>&1; then
# Fall back to the generic meta-package; still may not match a custom kernel.
apt-get install -y linux-headers-generic >/dev/null 2>&1 || true
fi
if [ -d "/lib/modules/$KVER/build" ] || dpkg -s "linux-headers-$KVER" >/dev/null 2>&1; then
log "kernel headers ready"
return 0
fi
die "kernel headers for $KVER unavailable — cannot build module. Install linux-headers-$KVER on the host." 4
}
# ===========================================================================
# blackmagic — Desktop Video .deb (DKMS) + modprobe + restart desktopvideo
# ===========================================================================
install_blackmagic() {
# Detect existing state first (idempotent skip).
if lsmod 2>/dev/null | grep -q '^blackmagic' && [ -e /dev/blackmagic ]; then
log "blackmagic module loaded and /dev/blackmagic present — already installed"
if command -v dkms >/dev/null 2>&1; then dkms status 2>/dev/null | grep -i blackmagic || true; fi
return 0
fi
local deb
deb="$(newest_match "$VENDOR_DIR/desktopvideo_*_amd64.deb")"
[ -n "$deb" ] && [ -f "$deb" ] || die \
"no desktopvideo_*_amd64.deb in $VENDOR_DIR — download Desktop Video for Ubuntu 22.04 and drop the .deb there (see sdk/blackmagic/README.md)." 3
log "using package: $(basename "$deb")"
ensure_headers
log "apt-get install (DKMS build) ..."
apt-get update -y >/dev/null 2>&1 || true
apt-get install -y "$deb" || die "apt-get install of $(basename "$deb") failed (DKMS build?)" 5
log "depmod + modprobe blackmagic ..."
depmod -a "$KVER" 2>/dev/null || true
if ! modprobe blackmagic 2>/dev/null; then
warn "modprobe blackmagic failed — a reboot may be required for the DKMS module to bind"
REBOOT_REQUIRED=1
fi
# Restart the DesktopVideoHelper daemon if present.
if command -v systemctl >/dev/null 2>&1; then
systemctl restart desktopvideo 2>/dev/null \
|| systemctl restart DesktopVideoHelper 2>/dev/null || true
fi
if lsmod 2>/dev/null | grep -q '^blackmagic' || [ -e /dev/blackmagic ]; then
log "blackmagic installed (module loaded / device present)"
else
warn "blackmagic installed but module not yet loaded — reboot required"
REBOOT_REQUIRED=1
fi
}
# ===========================================================================
# aja — build ntv2 kernel module from source archive + modprobe
# ===========================================================================
install_aja() {
if lsmod 2>/dev/null | grep -q 'ajantv2'; then
log "ajantv2 module already loaded — already installed"
return 0
fi
local src
src="$(newest_match "$VENDOR_DIR/ntv2sdk*.zip")"
[ -n "$src" ] || src="$(newest_match "$VENDOR_DIR/libajantv2*.tar.gz")"
[ -n "$src" ] && [ -f "$src" ] || die \
"no ntv2sdk*.zip / libajantv2*.tar.gz in $VENDOR_DIR — download the AJA NTV2 Linux SDK and drop it there (see sdk/aja/README.md)." 3
log "using source: $(basename "$src")"
ensure_headers
apt-get install -y build-essential unzip >/dev/null 2>&1 || true
local work; work="$(mktemp -d)"
log "extracting into $work ..."
case "$src" in
*.zip) unzip -q -o "$src" -d "$work" || die "failed to unzip $(basename "$src")" 5 ;;
*.tar.gz) tar -xzf "$src" -C "$work" || die "failed to untar $(basename "$src")" 5 ;;
esac
# Find the linux driver dir (contains a Makefile producing ajantv2.ko).
local drvdir
drvdir="$(dirname "$(find "$work" -type d -path '*driver/linux' -print -quit 2>/dev/null || true)/." 2>/dev/null)"
[ -d "$drvdir" ] || drvdir="$(dirname "$(find "$work" -name 'ajantv2.c' -print -quit 2>/dev/null || true)" 2>/dev/null)"
[ -n "$drvdir" ] && [ -d "$drvdir" ] || die "could not locate AJA driver/linux source inside the archive" 5
log "building module in $drvdir ..."
make -C "$drvdir" >/dev/null 2>&1 || die "AJA module build failed" 5
local ko
ko="$(find "$drvdir" -name 'ajantv2.ko' -print -quit 2>/dev/null || true)"
if [ -n "$ko" ]; then
install -D -m 0644 "$ko" "/lib/modules/$KVER/extra/ajantv2.ko" 2>/dev/null || true
depmod -a "$KVER" 2>/dev/null || true
fi
if ! modprobe ajantv2 2>/dev/null; then
# Fall back to the SDK's own load script if shipped.
local loader; loader="$(find "$work" -name 'load_ajantv2' -print -quit 2>/dev/null || true)"
if [ -n "$loader" ]; then bash "$loader" 2>/dev/null || true; fi
fi
rm -rf "$work" 2>/dev/null || true
if lsmod 2>/dev/null | grep -q 'ajantv2'; then
log "ajantv2 installed and loaded"
else
warn "ajantv2 built but not loaded — a reboot may be required (old in-tree module wedged?)"
REBOOT_REQUIRED=1
fi
}
# ===========================================================================
# deltacast — VideoMaster installer + module load
# ===========================================================================
install_deltacast() {
if lsmod 2>/dev/null | grep -q 'videomaster' || ls /dev/deltacast* >/dev/null 2>&1; then
log "Deltacast module loaded / device present — already installed"
return 0
fi
local pkg
pkg="$(newest_match "$VENDOR_DIR/VideoMaster*.run")"
[ -n "$pkg" ] || pkg="$(newest_match "$VENDOR_DIR/VideoMaster*.tar.gz")"
[ -n "$pkg" ] && [ -f "$pkg" ] || die \
"no VideoMaster*.run / VideoMaster*.tar.gz in $VENDOR_DIR — obtain the Deltacast VideoMaster Linux installer and drop it there (see sdk/deltacast/README.md)." 3
log "using installer: $(basename "$pkg")"
ensure_headers
apt-get install -y build-essential dkms >/dev/null 2>&1 || true
local work; work="$(mktemp -d)"
case "$pkg" in
*.run)
log "extracting self-extractor ..."
chmod +x "$pkg" 2>/dev/null || true
"$pkg" --noexec --target "$work" >/dev/null 2>&1 \
|| cp "$pkg" "$work/installer.run"
;;
*.tar.gz)
tar -xzf "$pkg" -C "$work" || die "failed to untar $(basename "$pkg")" 5
;;
esac
local installer
installer="$(find "$work" -name 'install.sh' -print -quit 2>/dev/null || true)"
[ -n "$installer" ] || installer="$(find "$work" -name 'installer.run' -print -quit 2>/dev/null || true)"
[ -n "$installer" ] && [ -f "$installer" ] || die "Deltacast installer (install.sh) not found inside the package" 5
log "running vendor installer: $(basename "$installer") ..."
chmod +x "$installer" 2>/dev/null || true
( cd "$(dirname "$installer")" && bash "$installer" ) || die "Deltacast VideoMaster installer failed" 5
depmod -a "$KVER" 2>/dev/null || true
modprobe videomasterhd 2>/dev/null || modprobe videomaster 2>/dev/null || true
rm -rf "$work" 2>/dev/null || true
if lsmod 2>/dev/null | grep -q 'videomaster' || ls /dev/deltacast* >/dev/null 2>&1; then
log "Deltacast VideoMaster installed"
fi
# First-time VideoMaster installs lay down udev rules + firmware that need a reboot.
warn "Deltacast: a REBOOT is recommended after a first-time VideoMaster install (udev + firmware)"
REBOOT_REQUIRED=1
}
# ===========================================================================
# ndi — copy redistributable runtime libs to /usr/local/lib + ldconfig
# ===========================================================================
install_ndi() {
local target="/opt/ndi-lib"
local found=0
# shellcheck disable=SC2231
for f in "$VENDOR_DIR"/libndi*.so*; do
[ -e "$f" ] || continue
found=1
break
done
[ "$found" = 1 ] || die \
"no libndi*.so* in $VENDOR_DIR — drop the NDI runtime redistributable libs there (see sdk/ndi/README.md)." 3
log "copying NDI runtime libs to $target ..."
mkdir -p "$target"
cp -av "$VENDOR_DIR"/libndi*.so* "$target"/ 2>/dev/null || die "failed copying NDI libs" 5
# Recreate the libndi.so dev symlink if only versioned libs were shipped.
if [ ! -e "$target/libndi.so" ]; then
local versioned
versioned="$(newest_match "$target/libndi.so.*")"
if [ -n "$versioned" ]; then
ln -sf "$(basename "$versioned")" "$target/libndi.so" 2>/dev/null || true
fi
fi
echo "$target" > /etc/ld.so.conf.d/ndi.conf
ldconfig 2>/dev/null || true
if ldconfig -p 2>/dev/null | grep -q 'libndi'; then
log "NDI runtime registered with the dynamic linker"
else
die "NDI libs copied but ldconfig did not resolve libndi" 5
fi
log "NDI: no kernel module and no reboot required."
log "NDI: restart any process that already loaded an older libndi to pick up the new version."
}
# ---------------------------------------------------------------------------
case "$VENDOR" in
blackmagic) install_blackmagic ;;
aja) install_aja ;;
deltacast) install_deltacast ;;
ndi) install_ndi ;;
esac
if [ "$REBOOT_REQUIRED" = 1 ]; then
log "RESULT: $VENDOR install completed — REBOOT REQUIRED"
echo "[install-driver] REBOOT_REQUIRED=1"
else
log "RESULT: $VENDOR install completed — no reboot required"
echo "[install-driver] REBOOT_REQUIRED=0"
fi
exit 0

View file

@ -16,12 +16,11 @@
# Environment variables: # Environment variables:
# MAM_API_URL REQUIRED Primary MAM API base URL # MAM_API_URL REQUIRED Primary MAM API base URL
# NODE_TOKEN API bearer token (required if AUTH_ENABLED=true) # NODE_TOKEN API bearer token (required if AUTH_ENABLED=true)
# NODE_ROLE Role tag reported to the cluster (default: auto-detect) # NODE_ROLE Role tag reported to the cluster (default: worker)
# NODE_IP Override the LAN IP reported back (default: auto-detect) # NODE_IP Override the LAN IP reported back (default: auto-detect)
# AGENT_PORT Host port for the node agent (default: 7436) # AGENT_PORT Host port for the node agent (default: 7436)
# INSTALL_DIR Where to clone/find the repo (default: /opt/wild-dragon) # INSTALL_DIR Where to clone/find the repo (default: /opt/wild-dragon)
# PROFILES Compose profiles, space-sep (default: auto-detect from hardware) # PROFILES Extra compose profiles, space-sep e.g. "worker capture"
# Override only to force, e.g. "worker capture"
# BMD_MODEL DeckLink card model name (e.g. "DeckLink Duo 2") # BMD_MODEL DeckLink card model name (e.g. "DeckLink Duo 2")
# REPO_URL Override the Forgejo clone URL # REPO_URL Override the Forgejo clone URL
# ============================================================================= # =============================================================================
@ -33,16 +32,8 @@ REPO_URL="${REPO_URL:-https://forge.wilddragon.net/zgaetano/wild-dragon.git}"
INSTALL_DIR="${INSTALL_DIR:-/opt/wild-dragon}" INSTALL_DIR="${INSTALL_DIR:-/opt/wild-dragon}"
MAM_API_URL="${MAM_API_URL:-}" MAM_API_URL="${MAM_API_URL:-}"
NODE_TOKEN="${NODE_TOKEN:-}" NODE_TOKEN="${NODE_TOKEN:-}"
# Track whether the caller pinned NODE_ROLE explicitly (manual override) vs.
# us defaulting it — so auto-detection only fills in an *unset* role.
[[ -n "${NODE_ROLE:-}" ]] && NODE_ROLE_EXPLICIT=1 || NODE_ROLE_EXPLICIT=""
NODE_ROLE="${NODE_ROLE:-worker}" NODE_ROLE="${NODE_ROLE:-worker}"
NODE_IP="${NODE_IP:-}" NODE_IP="${NODE_IP:-}"
# NODE_NAME pins this node's cluster identity (the heartbeat key). Default to the
# OS hostname, but ALWAYS write it explicitly so cloned VMs that share an
# /etc/hostname (e.g. two boxes both named "zampp1") don't collide on the same
# cluster_nodes row — which silently hides the capture node's DeckLink devices.
NODE_NAME="${NODE_NAME:-$(hostname)}"
AGENT_PORT="${AGENT_PORT:-7436}" AGENT_PORT="${AGENT_PORT:-7436}"
PROFILES="${PROFILES:-}" PROFILES="${PROFILES:-}"
BMD_MODEL="${BMD_MODEL:-}" BMD_MODEL="${BMD_MODEL:-}"
@ -74,37 +65,6 @@ detect_lan_ip() {
echo "$ip" echo "$ip"
} }
# ── Auto-detect hardware ─────────────────────────────────────────────────────
# Mirror detect_lan_ip's style: best-effort, guard every probe with `|| true`
# so a missing nvidia-smi/lspci never aborts under `set -euo pipefail`. The
# node self-describes its hardware here so the operator never has to pick a
# role — the right compose profiles are enabled automatically.
# GPU present? nvidia-smi is the strong signal; fall back to an lspci scan for
# NVIDIA or AMD VGA controllers (covers nodes where the driver isn't installed
# yet but the card is physically present).
detect_gpu() {
if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then
return 0
fi
if command -v lspci &>/dev/null; then
if lspci 2>/dev/null | grep -iE 'nvidia|vga.*amd' &>/dev/null; then
return 0
fi
fi
return 1
}
# SDI capture card present? Blackmagic DeckLink or Deltacast, via lspci.
detect_sdi() {
if command -v lspci &>/dev/null; then
if lspci 2>/dev/null | grep -iE 'blackmagic|deltacast' &>/dev/null; then
return 0
fi
fi
return 1
}
# ── Preflight ──────────────────────────────────────────────────────────────── # ── Preflight ────────────────────────────────────────────────────────────────
echo -e "\n${BLD}${CYN}Wild Dragon MAM — Cluster Node Onboarding${NC}\n" echo -e "\n${BLD}${CYN}Wild Dragon MAM — Cluster Node Onboarding${NC}\n"
@ -119,36 +79,6 @@ if [[ -z "$NODE_IP" ]]; then
fi fi
fi fi
# ── Auto-assign compose profiles from detected hardware ──────────────────────
# Operator never picks a role: the worker profile always runs, and we add the
# gpu / capture profiles only when the matching hardware is present. Explicit
# PROFILES / NODE_ROLE env vars are honoured as a manual override escape hatch.
HAS_GPU=false; HAS_SDI=false
detect_gpu && HAS_GPU=true || true
detect_sdi && HAS_SDI=true || true
DETECTED_DESC="CPU"
[[ "$HAS_GPU" == true ]] && DETECTED_DESC="$DETECTED_DESC, GPU"
[[ "$HAS_SDI" == true ]] && DETECTED_DESC="$DETECTED_DESC, SDI capture card"
if [[ -z "$PROFILES" ]]; then
AUTO_PROFILES="worker"
[[ "$HAS_GPU" == true ]] && AUTO_PROFILES="$AUTO_PROFILES gpu"
[[ "$HAS_SDI" == true ]] && AUTO_PROFILES="$AUTO_PROFILES capture"
PROFILES="$AUTO_PROFILES"
info "Detected: $DETECTED_DESC → profiles: $PROFILES"
else
info "Detected: $DETECTED_DESC (profiles overridden by env: $PROFILES)"
fi
# Derive a human-friendly role tag from detected hardware when not pinned.
# Capture cards win over GPU (an SDI ingest node is the more specific role).
if [[ -z "$NODE_ROLE_EXPLICIT" ]]; then
if [[ "$HAS_SDI" == true ]]; then NODE_ROLE="capture"
elif [[ "$HAS_GPU" == true ]]; then NODE_ROLE="gpu"
else NODE_ROLE="worker"; fi
fi
info "Primary API : $MAM_API_URL" info "Primary API : $MAM_API_URL"
info "Role : $NODE_ROLE" info "Role : $NODE_ROLE"
info "Agent port : $AGENT_PORT" info "Agent port : $AGENT_PORT"
@ -205,7 +135,6 @@ info "Writing $ENV_FILE"
echo "MAM_API_URL=$MAM_API_URL" echo "MAM_API_URL=$MAM_API_URL"
echo "NODE_TOKEN=$NODE_TOKEN" echo "NODE_TOKEN=$NODE_TOKEN"
echo "NODE_ROLE=$NODE_ROLE" echo "NODE_ROLE=$NODE_ROLE"
echo "NODE_NAME=$NODE_NAME"
echo "NODE_IP=$NODE_IP" echo "NODE_IP=$NODE_IP"
echo "AGENT_PORT=$AGENT_PORT" echo "AGENT_PORT=$AGENT_PORT"
echo "HEARTBEAT_MS=30000" echo "HEARTBEAT_MS=30000"

View file

@ -16,9 +16,7 @@
# Optional env vars (needed only if starting the worker or capture profiles): # Optional env vars (needed only if starting the worker or capture profiles):
# REDIS_URL, DATABASE_URL, S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY, S3_SECRET_KEY # REDIS_URL, DATABASE_URL, S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY, S3_SECRET_KEY
# BMD_DEVICE_0 DeckLink device path (default: /dev/blackmagic/dv0) # BMD_DEVICE_0 DeckLink device path (default: /dev/blackmagic/dv0)
# (DeckLink IO / Quad cards expose /dev/blackmagic/io* instead — set BMD_DEVICE_PREFIX=io)
# BMD_DEVICE_1 DeckLink device path (default: /dev/blackmagic/dv1) # BMD_DEVICE_1 DeckLink device path (default: /dev/blackmagic/dv1)
# BMD_DEVICE_PREFIX Naming prefix for synthesized BMD_COUNT-based devices (default: dv). Use 'io' for IO/Quad.
# LIVE_DIR Host path for HLS live segments (default: /mnt/NVME/MAM/wild-dragon-live) # LIVE_DIR Host path for HLS live segments (default: /mnt/NVME/MAM/wild-dragon-live)
# #
# Profiles: # Profiles:
@ -47,37 +45,16 @@ services:
MAM_API_URL: ${MAM_API_URL} MAM_API_URL: ${MAM_API_URL}
NODE_TOKEN: ${NODE_TOKEN:-} NODE_TOKEN: ${NODE_TOKEN:-}
NODE_ROLE: ${NODE_ROLE:-worker} NODE_ROLE: ${NODE_ROLE:-worker}
# NODE_NAME pins the cluster identity (heartbeat key). Set it per-node so
# cloned VMs that share /etc/hostname don't collide on the same
# cluster_nodes row. Falls back to the OS hostname when unset.
NODE_NAME: ${NODE_NAME:-}
NODE_IP: ${NODE_IP:-} NODE_IP: ${NODE_IP:-}
AGENT_PORT: ${AGENT_PORT:-7436} AGENT_PORT: ${AGENT_PORT:-7436}
HEARTBEAT_MS: ${HEARTBEAT_MS:-30000} HEARTBEAT_MS: ${HEARTBEAT_MS:-30000}
GPU_COUNT: ${GPU_COUNT:--1} GPU_COUNT: ${GPU_COUNT:--1}
BMD_COUNT: ${BMD_COUNT:--1} BMD_COUNT: ${BMD_COUNT:--1}
BMD_MODEL: ${BMD_MODEL:-} BMD_MODEL: ${BMD_MODEL:-}
BMD_DEVICE_PREFIX: ${BMD_DEVICE_PREFIX:-dv}
LIVE_DIR: ${LIVE_DIR:-/mnt/NVME/MAM/wild-dragon-live} LIVE_DIR: ${LIVE_DIR:-/mnt/NVME/MAM/wild-dragon-live}
# REPO_DIR: host path to the checked-out repo. The agent passes this to the
# one-shot driver-install container so install-driver.sh can read
# sdk/<vendor>/ and run deploy/install-driver.sh. Must match the host path
# bind-mounted below (onboard-node.sh clones to /opt/wild-dragon).
REPO_DIR: ${REPO_DIR:-/opt/wild-dragon}
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- /dev:/dev:ro - /dev:/dev:ro
- /mnt/NVME/MAM/wild-dragon-live:/mnt/NVME/MAM/wild-dragon-live:ro
# Capture-driver deployment ("Capture Drivers / SDKs" in the Cluster admin
# screen): the agent itself does NOT run dkms/modprobe — it spawns a
# separate privileged ubuntu container that bind-mounts these host paths.
# The agent only needs to *see* the repo path so it can pass it through as
# a bind to that container; no extra privileges are granted to the agent.
# /opt/wild-dragon → repo (sdk/<vendor>/ + deploy/install-driver.sh)
# The install container additionally mounts /lib/modules,/usr/src,/boot,
# /dev and /opt from the host (handled in the agent, not here) so DKMS /
# modprobe / ldconfig affect the host kernel.
- ${REPO_DIR:-/opt/wild-dragon}:${REPO_DIR:-/opt/wild-dragon}:ro
devices: devices:
- /dev/blackmagic:/dev/blackmagic - /dev/blackmagic:/dev/blackmagic
@ -119,32 +96,6 @@ services:
networks: networks:
- wild-dragon-worker - wild-dragon-worker
# worker-l4: HEAVY tier (proxy/conform/trim) on the L4 (NVENC). Talks to
# zampp1's Redis/Postgres/S3 over the LAN (.200). No promotion scanner here.
worker-l4:
profiles: [gpu]
build:
context: ./services/worker
dockerfile: Dockerfile.gpu
image: wild-dragon-worker-gpu:latest
runtime: nvidia
restart: unless-stopped
environment:
REDIS_URL: ${REDIS_URL}
DATABASE_URL: ${DATABASE_URL}
S3_ENDPOINT: ${S3_ENDPOINT}
S3_BUCKET: ${S3_BUCKET}
S3_ACCESS_KEY: ${S3_ACCESS_KEY}
S3_SECRET_KEY: ${S3_SECRET_KEY}
S3_REGION: ${S3_REGION:-us-east-1}
WORKER_QUEUES: proxy,conform,trim
PROXY_CONCURRENCY: "3"
NVIDIA_VISIBLE_DEVICES: GPU-13acf439-8bf4-a5e0-7804-c1071bca547a
WORKER_LABEL: "zampp2 / L4"
NVIDIA_DRIVER_CAPABILITIES: video,compute,utility
networks:
- wild-dragon-worker
networks: networks:
wild-dragon-worker: wild-dragon-worker:
driver: bridge driver: bridge

View file

@ -40,7 +40,6 @@ services:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- /mnt/NVME/MAM/wild-dragon-live:/live - /mnt/NVME/MAM/wild-dragon-live:/live
- /mnt/NVME/MAM/wild-dragon-growing:/growing - /mnt/NVME/MAM/wild-dragon-growing:/growing
- /mnt/NVME/MAM/wild-dragon-media:/media
- /mnt/NVME/MAM/sdk:/sdk - /mnt/NVME/MAM/sdk:/sdk
- /dev/shm:/dev/shm - /dev/shm:/dev/shm
- /run/dbus:/run/dbus - /run/dbus:/run/dbus
@ -56,19 +55,9 @@ services:
S3_REGION: ${S3_REGION:-us-east-1} S3_REGION: ${S3_REGION:-us-east-1}
SESSION_SECRET: ${SESSION_SECRET} SESSION_SECRET: ${SESSION_SECRET}
AUTH_ENABLED: ${AUTH_ENABLED:-false} AUTH_ENABLED: ${AUTH_ENABLED:-false}
TRUST_PROXY: ${TRUST_PROXY:-false}
ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-}
DOCKER_NETWORK: wild-dragon_wild-dragon DOCKER_NETWORK: wild-dragon_wild-dragon
NODE_IP: ${NODE_IP} NODE_IP: ${NODE_IP}
NODE_HOSTNAME: ${NODE_HOSTNAME:-} NODE_HOSTNAME: ${NODE_HOSTNAME:-}
# Bearer mam-api forwards to a node-agent when installing capture drivers
# ("Capture Drivers / SDKs" panel). Set to the same value as the agents'
# NODE_TOKEN. If empty, agents with an empty NODE_TOKEN accept the call
# (dev); agents with a token will reject it (401).
NODE_AGENT_TOKEN: ${NODE_AGENT_TOKEN:-}
CAPTURE_TOKEN: ${CAPTURE_TOKEN}
PLAYOUT_IMAGE: ${PLAYOUT_IMAGE:-wild-dragon-playout:latest}
PLAYOUT_AMCP_BASE_PORT: ${PLAYOUT_AMCP_BASE_PORT:-5250}
deploy: deploy:
resources: resources:
reservations: reservations:
@ -103,20 +92,8 @@ services:
networks: networks:
- wild-dragon - wild-dragon
# ── GPU worker pool (capability-routed) ────────────────────────────── worker:
# worker-p4: HEAVY tier (proxy/conform/trim) on the Tesla P4 (NVENC). build: ./services/worker
# Also runs the promotion scanner (RUN_PROMOTION) — exactly one worker must.
worker-p4:
build:
context: ./services/worker
dockerfile: Dockerfile.gpu
image: wild-dragon-worker-gpu:latest
runtime: nvidia
# Privileged so the promotion scanner can mount the growing-files CIFS share
# at /growing (same Approach A as the capture sidecar). Without the share
# mounted the scanner watches an empty local dir and never promotes growing
# captures to S3.
privileged: true
depends_on: depends_on:
- queue - queue
- db - db
@ -129,61 +106,8 @@ services:
S3_SECRET_KEY: ${S3_SECRET_KEY} S3_SECRET_KEY: ${S3_SECRET_KEY}
S3_REGION: ${S3_REGION:-us-east-1} S3_REGION: ${S3_REGION:-us-east-1}
GROWING_PATH: /growing GROWING_PATH: /growing
# Includes `import` (YouTube importer): the import queue had no consumer
# after the capability-routing split, so import jobs sat unprocessed and
# assets stayed `ingesting` forever. import is concurrency-1 + network-
# bound, so one consumer (this heavy/primary worker) is sufficient.
WORKER_QUEUES: proxy,conform,trim,import,playout-stage
RUN_PROMOTION: "true"
PROXY_CONCURRENCY: "2"
PLAYOUT_MEDIA_DIR: /media
NVIDIA_VISIBLE_DEVICES: GPU-79afca3e-2ab2-a6ea-1c44-706c1f0a26d6
WORKER_LABEL: "zampp1 / Tesla P4"
NVIDIA_DRIVER_CAPABILITIES: video,compute,utility
volumes: volumes:
# NOTE: /growing is NOT a host bind anymore — the promotion scanner mounts - /mnt/NVME/MAM/wild-dragon-growing:/growing
# the CIFS landing-zone share there itself (a bind would shadow it). The
# mount needs rshared propagation so the in-container CIFS mount is visible.
- /mnt/NVME/MAM/wild-dragon-media:/media
networks:
- wild-dragon
# worker-p400a/b: LIGHT tier (thumbnail/filmstrip) on the two Quadro P400s.
worker-p400a:
image: wild-dragon-worker-gpu:latest
runtime: nvidia
depends_on: [queue, db, worker-p4]
environment:
REDIS_URL: ${REDIS_URL}
DATABASE_URL: ${DATABASE_URL}
S3_ENDPOINT: ${S3_ENDPOINT}
S3_BUCKET: ${S3_BUCKET}
S3_ACCESS_KEY: ${S3_ACCESS_KEY}
S3_SECRET_KEY: ${S3_SECRET_KEY}
S3_REGION: ${S3_REGION:-us-east-1}
WORKER_QUEUES: thumbnail,filmstrip
NVIDIA_VISIBLE_DEVICES: GPU-331c53ea-2ed9-0007-e364-c1451775948f
WORKER_LABEL: "zampp1 / P400 #1"
NVIDIA_DRIVER_CAPABILITIES: video,compute,utility
networks:
- wild-dragon
worker-p400b:
image: wild-dragon-worker-gpu:latest
runtime: nvidia
depends_on: [queue, db, worker-p4]
environment:
REDIS_URL: ${REDIS_URL}
DATABASE_URL: ${DATABASE_URL}
S3_ENDPOINT: ${S3_ENDPOINT}
S3_BUCKET: ${S3_BUCKET}
S3_ACCESS_KEY: ${S3_ACCESS_KEY}
S3_SECRET_KEY: ${S3_SECRET_KEY}
S3_REGION: ${S3_REGION:-us-east-1}
WORKER_QUEUES: thumbnail,filmstrip
NVIDIA_VISIBLE_DEVICES: GPU-b514a592-9077-44bd-d9e8-9efa0591ef88
WORKER_LABEL: "zampp1 / P400 #2"
NVIDIA_DRIVER_CAPABILITIES: video,compute,utility
networks: networks:
- wild-dragon - wild-dragon
@ -193,21 +117,20 @@ services:
- "${PORT_WEB_UI:-7434}:80" - "${PORT_WEB_UI:-7434}:80"
volumes: volumes:
- /mnt/NVME/MAM/wild-dragon-live:/live - /mnt/NVME/MAM/wild-dragon-live:/live
- /mnt/NVME/MAM/wild-dragon-media:/media:ro
- /dev/shm:/dev/shm - /dev/shm:/dev/shm
- /run/dbus:/run/dbus - /run/dbus:/run/dbus
- /run/systemd:/run/systemd - /run/systemd:/run/systemd
networks: networks:
- wild-dragon - wild-dragon
# Build-only: the CasparCG sidecar image. mam-api spawns these on-demand per editor:
# channel (one container per playout channel), so this service is never up'd — build: ./services/editor
# it exists so `docker compose build playout` produces the image the API tags depends_on:
# via PLAYOUT_IMAGE. Profile excludes it from default `up`. - mam-api
playout: ports:
profiles: ["build-only"] - "${PORT_EDITOR:-7435}:80"
build: ./services/playout networks:
image: wild-dragon-playout:latest - wild-dragon
volumes: volumes:
postgres_data: postgres_data:

View file

@ -1,186 +0,0 @@
# Dragonflight · Feature Overview
Dragonflight is a self-hosted broadcast media-asset management system that replaces legacy tools like Grass Valley AMPP and FramelightX. It handles live ingest, growing-file editing, scheduling, transcoding, and asset management in a single operator-focused interface.
## Home Dashboard
![Home Dashboard](./screenshots/01-home.png)
The home screen provides quick access to all major features and displays system status at a glance:
- **Library** — Browse projects, bins, and assets with hover-scrub previews
- **Recorders** — View configured capture devices and their status
- **Editor** — Timeline editor with cross-clip preview and render queue
- **Jobs** — Proxy and thumbnail queue with retry controls
- **Settings** — Configure storage, encoder, growing files, and capture SDK
- **Dashboard** — Operations view showing recent activity, job queue, and cluster health
---
## Core Features
### 1. Live Ingest & Capture
**Multi-protocol source capture with per-recorder codec settings**
Dragonflight ingests from multiple sources simultaneously:
- **SRT** (Secure Reliable Transport) — caller and listener modes
- **RTMP** — standard streaming protocol
- **SDI** — via Blackmagic DeckLink cards with FFmpeg SDK 16.x patches
Each recorder can be configured with independent codec settings:
- ProRes (hi-res masters)
- H.264 / H.265 (proxies)
- DNxHR (Avid compatibility)
Audio routing and per-source configuration ensure flexibility for multi-camera productions.
### 2. Growing-File Editing
**Live editing in Premiere Pro while capture is still writing**
Editors mount the SMB landing zone directly in Premiere Pro and edit the live master file as it's being written. The included CEP (Custom Extension Panel) provides:
- Real-time clip detection and frame-accurate trimming
- One-click relink to final S3 master after promotion
- No waiting for capture to finish before editorial begins
### 3. Recorder Scheduler
**Time-windowed recording automation**
Schedule recordings with:
- One-shot, daily, or weekly recurrence
- Automatic start/stop via 15-second tick loop
- Conflict detection across recorders
- Project and bin assignment at schedule time
### 4. Library & Asset Management
**Browse, search, and organize captured footage**
The Library screen provides:
- Project and bin hierarchy
- Asset detail view with frame-anchored persistent comments
- Right-click context menu (move-to-bin, rename, delete)
- Global cmd/ctrl-K search across assets, projects, recorders, jobs, and users
- Hover-scrub preview with HLS playback
### 5. Jobs Queue
**BullMQ-backed proxy and thumbnail generation**
Automated background processing:
- Per-job retry logic with exponential backoff
- Bulk "retry all failed" for batch recovery
- Inline error messages with actionable diagnostics
- Status tracking: ingesting → processing → ready
Proxy encoder options:
- CPU-based: libx264 (H.264)
- GPU-accelerated: NVENC (NVIDIA) or VAAPI (AMD/Intel)
### 6. Timeline Conform & Export
**FCP XML export with server-side FFmpeg rendering**
The Premiere Pro panel exports FCP XML with:
- Server-side conform via FFmpeg
- Multiple output formats: H.264, H.265, ProRes
- Resolution presets: Broadcast, Web, Archive
- Batch processing with job queue integration
### 7. Hi-Res Auto-Relink
**One-click batch relink of proxy clips to frame-accurate server-trimmed masters**
After editing on proxies:
- Select clips in Premiere
- Trigger relink from the CEP panel
- Server trims hi-res segments to exact in/out points
- Concurrent trim worker pool for speed
- 24-hour TTL with automatic cleanup
### 8. Settings & Configuration
**Centralized control for storage, encoding, and capture**
Configure:
- **S3 Storage** — endpoint, bucket, credentials (with env-var fallback)
- **Proxy Encoder** — CPU vs GPU, bitrate, resolution
- **Growing Files** — SMB path, retention, auto-promotion
- **Capture SDK** — Blackmagic, AJA, or Deltacast uploader selection
### 9. Cluster & Distributed Capture
**Primary + worker topology with remote DeckLink nodes**
- Primary node runs API, scheduler, and web UI
- Worker nodes handle proxy/thumbnail jobs
- Remote capture nodes run DeckLink cards off-host
- Heartbeat health monitoring
- Automatic failover and recovery
### 10. Admin & User Management
**Role-based access, token auth, and cluster monitoring**
- User creation and role assignment
- API token generation for integrations
- Container and cluster node status
- System health dashboard
---
## Architecture
```
SDI / SRT / RTMP ──► capture (FFmpeg)
├─ HLS preview tee ──► /live/<assetId>/index.m3u8
└─ master output
├─ growing_enabled=true:
│ /growing/<projectId>/<clip>.mov
│ (Premiere mounts SMB, edits live)
│ └─► promotion worker uploads to S3
└─ growing_enabled=false:
multipart stream → S3
assets POST ──► proxy job ──► worker
├─ libx264 (CPU) or NVENC/VAAPI (GPU)
├─ thumbnail job
└─ status: ingesting → processing → ready
```
## Tech Stack
- **Runtime:** Node.js 22, Docker Compose
- **Backend:** Express, PostgreSQL 16, Redis 7 + BullMQ
- **Frontend:** Vanilla React via in-browser Babel (no bundler), hls.js
- **Media:** FFmpeg 7.1 with SDK 16 DeckLink patches
- **Codecs:** ProRes, H.264, H.265, DNxHR, MOV/MP4/MXF containers
- **Storage:** S3-compatible (RustFS) for masters, proxies, thumbnails
## Services
| Service | Port | Purpose |
|---------|------|---------|
| **web-ui** | 47434 | Browser SPA + capture controls |
| **mam-api** | 47432 | REST API + recorder orchestration + scheduler |
| **capture** | 47433 / 9000 / 1935 | DeckLink/SRT/RTMP ingest sidecar |
| **worker** | — | BullMQ proxy + thumbnail workers |
| **db** | 5432 | PostgreSQL 16 |
| **queue** | 6379 | Redis 7 |
---
## Workflow Example: Live-to-Edit
1. **Operator** schedules a recording on Recorder A for 14:0015:30, assigns to "News/Segment-A" project
2. **Capture** starts at 14:00, writes ProRes master to SMB landing zone
3. **Editor** mounts SMB in Premiere, opens the live .mov file via the CEP panel
4. **Editor** trims and marks in/out points while capture is still writing
5. **Capture** finishes at 15:30, promotion worker uploads master to S3
6. **Editor** clicks "Relink to Master" in CEP panel
7. **Server** trims hi-res segment to exact in/out, stores for 24 hours
8. **Premiere** relinks proxy clips to trimmed master
9. **Editor** exports final timeline via FCP XML conform
Total time from end of capture to relinked master: ~2 minutes.
---
## Operations
- `deploy/api-smoke.sh` — verify every API endpoint after deploy
- `deploy/onboard-node.sh` — provision a remote worker host
- `deploy/test-cluster.sh` — primary↔worker connectivity smoke test
- `docs/GROWING_FILES_QUICKSTART.md` — Premiere CEP panel install + growing-file flow

View file

@ -1,116 +0,0 @@
# Work Log — May 2026
## Summary
Session focused on auth system architecture, dashboard redesign, and audio track inspector. Multiple iterations on auth approach; settled on simplified local-account model with RBAC. Dashboard rebuilt as control-room status board. Audio tab completed with full metering and fader controls.
## Auth System Work
### Commits
- `002e5ac` — auth: top-to-bottom rework — local accounts, RBAC + client tag, audit log, env-bootstrap
- `d1f9557` — auth: park login flow — circle back
- `9726dbb` — Revert "auth: top-to-bottom rework..."
- `4172b0d` — rip out entire auth/login flow
### What Happened
Attempted comprehensive auth rewrite including:
- Local user account system with bcrypt hashing
- Role-based access control (admin/editor/viewer)
- Client tagging for audit trails
- Environment-based bootstrap (AUTH_ENABLED flag)
- Session management with PostgreSQL backing
**Decision**: Reverted entire auth work. Reason: complexity vs. current product stage. System was over-engineered for self-hosted use case where auth is optional.
**Current State**: Auth disabled by default (AUTH_ENABLED=false). When enabled, system returns synthetic /auth/me endpoint. No persistent user management yet.
### Related Fixes
- `cfcbec0` — fix(auth): make AUTH_ENABLED=true workable end-to-end
- `e71c330` — fix(auth): remove manual session.save() — was suppressing Set-Cookie header
- `65684aa` — fix(auth): ensure sessions table exists + log session.save errors
## Dashboard Redesign
### Commits
- `a48e1d9` — dashboard: rebuild as control-room status board (on air / up next / attention / work)
- `e5e0656` — dashboard: redesign stat cards, compress header, improve density
- `5de1e3d` — dashboard: add dense stat cards, cluster bars, job rows, sparkline fixes
- `48d54a3` — dashboard: add missing dash-* CSS classes; cluster: add stat-row/stat-card CSS
### What Changed
Transformed dashboard from generic metrics view to broadcast control-room interface:
- **On Air** section: live stream status, bitrate, duration
- **Up Next** section: queued clips/segments
- **Attention** section: warnings, errors, resource alerts
- **Work** section: active jobs, encoding progress
Added visual components:
- Dense stat cards with icon + value + trend
- Cluster health bars (CPU, memory, disk per node)
- Job progress rows with ETA
- Sparkline charts for trend visualization
CSS infrastructure added for consistent spacing/sizing across dashboard components.
## Audio Tab Implementation
### Commit
- `c48c7e6` — feat(audio-tab): full audio track inspector with meters, mute/solo, faders
### Features
- Per-track audio meters (VU-style, real-time)
- Mute/solo buttons per track
- Fader controls (0-100 dB range)
- Master output meter
- Track naming/labeling
- Visual feedback for clipping/peaks
## Other Work
### Storage & Admin
- `64d739b` — feat(admin): unified Storage settings page with mount/bucket health diagnostics
- `a44d8bd` — feat(admin): live video-presence indicators on cluster DeckLink ports
### Player & Streaming
- `a86c1c7` — fix(player): stitch S3 ranges around RustFS empty-body bug (#143)
- `d257a19` — fix(player): buffer indicator + 416 instead of 500 on out-of-range S3
- `37247fd` — fix(video): direct S3 signed URL for streaming + proxy bitrate 1.5Mbps
- `e4d4c00` — feat(proxy): VBR 500k-1M encoding for proxy generation
### Cluster & Hardware
- `55ff2e7` — feat(cluster): full hardware breakdown per node
- `5ff507b` — fix(node-agent): use nsenter to run nvidia-smi in host mount namespace
- `558c18e` — fix(node-agent): detect GPUs via docker run --gpus all ubuntu:22.04
- `a6f045b` — fix(node-agent): probe GPU via Docker API async at startup, cache result
### Release & Cleanup
- `04ce096` — chore: 1.2 ship-prep sweep — close 38 issues
- `f0f6156` — release: add v1.1.0 ZXP artifact (Growing tab + visual system alignment)
## Blockers / Open Questions
### Auth System
- **Decision needed**: Should auth be mandatory for production? Current design assumes optional.
- **API endpoints missing**: `/users`, `/auth/me`, `/groups` routes not yet implemented in mam-api
- **Frontend expects**: Users list, groups management, role-based UI filtering
### Dashboard
- Real data integration needed (currently mock data)
- Cluster stats endpoint integration
- Job queue polling/WebSocket updates
### Audio
- Backend audio processing pipeline not yet connected
- Metering data source undefined
- Fader changes need routing to encoder
## Next Steps (Recommended)
1. **Clarify auth requirements**: Is user management needed for v1.2? If yes, implement `/users` and `/groups` endpoints.
2. **Connect dashboard to live data**: Wire cluster stats, job queue, stream status to real endpoints.
3. **Audio backend integration**: Define audio processing pipeline and metering data flow.
4. **Testing**: Add integration tests for auth flow, dashboard data binding, audio control.
---
**Session ended**: 2026-05-27 06:31 CDT
**Status**: Work logged, auth decision documented, next steps identified

View file

@ -1,197 +0,0 @@
# All-Intra HEVC (NVENC) Growing-File Ingest
Date: 2026-05-29 | Status: design, pending validation gate (see §8)
Authors: Zac + Claude
## 1. Purpose
Replace the CPU-bound ProRes capture encode with **All-Intra HEVC on NVENC**
as the growing-file master codec, so we can:
- **Offload ingest encode from CPU to GPU** (the current scaling wall), and
- **Keep edit-while-record** (all-intra => growing file stays editable), and
- **Scale to up to 8 simultaneous signals per machine**, across Blackmagic
today and Deltacast + AJA later.
This doc captures the target design AND the current working system it builds on,
so it is self-contained for whoever implements it.
## 2. Why this codec
Growing-file editing (Premiere/Avid mounting a still-recording file over SMB)
requires two things: **intra-frame** (every frame a keyframe, so a partial file
is decodable to the last whole frame) and a **container whose index is not
deferred to EOF**. ProRes/DNxHR satisfy this but are CPU-only (NVIDIA has no
ProRes encoder). Long-GOP H.264/HEVC/AV1 do NOT work for edit-while-record.
**All-Intra HEVC (`-g 1 -bf 0`) via `hevc_nvenc`** is the one path that is both
GPU-accelerated AND all-intra: it breaks the "ProRes must be CPU" constraint
without losing edit-while-record. Trade-off: All-Intra bitrate approaches
ProRes, so the win is **CPU offload, not storage**. AV1 is rejected (no NLE
edit support; av1_nvenc absent from our ffmpeg builds).
## 3. Current working system (what we build on)
### Topology
- **zampp1** (172.18.91.200): primary. Runs db (postgres), queue (redis),
mam-api (:47432), web-ui (:47434), and the GPU worker pool. GPUs: Tesla P4 +
2x Quadro P400. Repo at /opt/wild-dragon (its own clone).
- **zampp2** (172.18.91.216): worker/capture node. 12-vCPU QEMU VM, NVIDIA L4,
4x Blackmagic DeckLink (exposed as /dev/blackmagic/io0..io3). Runs node-agent
(:7436). Repo at /opt/wild-dragon (separate clone).
- The repo is checked out independently on BOTH nodes; node-specific files
(node-agent, capture, worker overlay) are edited on the node that runs them.
### Capture (current)
mam-api `POST /recorders/:id/start` pre-creates a `live` asset and dispatches
`POST /sidecar/start` to the recorder's node-agent, which spawns a
`wild-dragon-capture:latest` container (host network, privileged,
/dev/blackmagic bound). The capture ffmpeg:
- input: `-f decklink -i "DeckLink Duo (N)"`
- filter: `yadif` (CPU deinterlace)
- output 0 (master): `prores_ks` (CPU) -> S3 (pipe) or growing SMB file
- output 1 (preview): `libx264` veryfast HLS -> /live/{assetId} (CPU)
DeckLink does capture (cheap); BOTH encodes are CPU. ~5 vCPU per 1080i signal
=> ~2 signals saturate the 12-vCPU VM. GPUs are idle during capture.
### Stop / finalize (working)
node-agent stops the sidecar with a **180s grace** (was 10s -> SIGKILL bug).
Capture's SIGTERM handler finalises the session and calls
`POST /assets/:id/finalize` (the live asset id passed as ASSET_ID), which flips
the asset out of `live`, records duration + S3 keys, and kicks the
proxy -> thumbnail -> filmstrip chain. (Earlier 409 bug: it used to POST a new
asset and collide with the live row.)
### Live monitor (working)
SDI HLS preview is a 2nd output of the capture ffmpeg (one DeckLink read ->
split -> ProRes + H.264 HLS), written to /live/{assetId} on the capture node.
node-agent serves GET /live/* over HTTP; mam-api proxies
GET /api/v1/recorders/:id/live/* to the recorder's node-agent; the web-ui
HlsPreview loads the proxied URL. Browser auth is the session cookie
(same-origin).
### GPU worker pool (working, post-capture)
BullMQ on shared Redis; queues are type-named (proxy/thumbnail/filmstrip/
conform/trim). Workers are capability-routed by `WORKER_QUEUES`, one GPU-pinned
container per card (`NVIDIA_VISIBLE_DEVICES` by UUID):
- HEAVY (proxy/conform/trim): Tesla P4 (zampp1) + L4 (zampp2), `h264_nvenc`.
- LIGHT (thumbnail/filmstrip): 2x Quadro P400 (zampp1).
DB setting `gpu_transcode_enabled=true` + `gpu_codec=h264_nvenc` enable NVENC.
Each worker stamps `WORKER_LABEL` onto job data -> Jobs UI "Node" column.
`RUN_PROMOTION=true` on exactly one worker runs the growing-files->S3 scan.
The worker GPU image is built from services/worker/Dockerfile.gpu (CUDA base +
Ubuntu ffmpeg with h264/hevc_nvenc; NO av1_nvenc).
### Deploy gotchas (learned)
- Service source is BAKED into images; edits need rebuild + recreate (or the
GPU image rebuild reuses cached layers so only final COPY changes -> fast).
- The capture image can only build on zampp2 (DeckLink SDK present there).
- Per-node `.env`: zampp2's REDIS_URL/DATABASE_URL/S3_* now point at zampp1
(.200); secrets live only in .env, never in committed compose.
- Clear all containers on both nodes before a full redeploy (user preference).
## 4. Target design
### 4.1 Capture ffmpeg gains NVENC
The capture image's custom FFmpeg 7.1 is currently built WITHOUT nvenc (only
prores_ks/dnxhd/libx264). Rebuild `services/capture/Dockerfile` ffmpeg with:
`--enable-cuda-nvcc --enable-libnpp --enable-nvenc --enable-cuvid` plus
nv-codec-headers (ffnvcodec) installed before configure. Keep `--enable-decklink`
and the existing codecs (ProRes stays available as a selectable fallback).
Verify `ffmpeg -encoders | grep nvenc` shows hevc_nvenc/h264_nvenc afterwards.
### 4.2 Capture sidecar gets a GPU
node-agent `handleSidecarStart` currently spawns the capture container with no
GPU. Add NVIDIA runtime + device pinning to the sidecar create spec:
`HostConfig.Runtime='nvidia'` (or DeviceRequests with the node's GPU) and env
`NVIDIA_VISIBLE_DEVICES=<uuid>` + `NVIDIA_DRIVER_CAPABILITIES=video,compute,utility`.
The capture node's GPU is shared with its worker-l4 (see capacity, §5).
### 4.3 Encode parameters (master)
All-Intra HEVC on NVENC:
`-c:v hevc_nvenc -preset p4 -rc vbr -g 1 -bf 0 -profile:v main10 -pix_fmt p010le` (10-bit 4:2:2 is not NVENC-native; NVENC HEVC is 4:2:0 8/10-bit.
If 4:2:2 mezzanine is required, that is a HARD blocker for NVENC and we stay on
ProRes for those feeds — see §8). Bitrate target tuned per format (1080i59.94
~100-160 Mbps to rival ProRes HQ). `-g 1 -bf 0` => every frame IDR (all-intra).
### 4.4 Container (growing-file)
Write the master to a growing file on the SMB share (GROWING_PATH), same path
the promotion worker already uploads on EOF. Container candidates, in order of
preference for Premiere growing-file mounts:
1. **MXF OP1a** (`-f mxf`) — broadcast standard, designed for growing/edit-while-
ingest; best Avid/Premiere support. HEVC-in-MXF support in Premiere is the
key unknown to validate (§8).
2. **Fragmented MOV/MP4** (`-movflags +frag_keyframe+empty_moov+default_base_moof`)
— no moov-at-EOF, readable while growing; fallback if MXF+HEVC is unsupported.
The HLS preview path is unchanged except it can also move to h264_nvenc now that
capture has NVENC (frees the last libx264 CPU cost).
## 5. Capacity & scaling (8 signals/machine)
After the move, per-signal CPU is just: DeckLink capture + yadif + mux + frame
upload to the GPU. The heavy HEVC encode is on NVENC. The constraint shifts from
CPU to **NVENC throughput + GPU memory + PCIe/host bandwidth**:
- The **L4 is a datacenter card => unlimited NVENC sessions** (no consumer
3-session cap). 8x 1080i HEVC-I encode sessions are well within an L4.
- GPU memory: ~8 concurrent 1080 NVENC sessions + frame buffers fit in 24 GB.
- The capture node's L4 is shared between capture (per-signal HEVC-I) and the
worker-l4 proxy jobs. Under 8-signal load, give capture priority; consider
moving worker-l4 (post-record proxies) to zampp1's P4 only, or gate worker-l4
intake while signals are live.
- yadif on CPU is still ~0.5-1 vCPU/signal; consider `yadif_cuda`/`bwdif_cuda`
(GPU deinterlace) once frames are uploaded to the GPU, keeping CPU near-idle.
**Node sizing:** a 12-vCPU VM was the ProRes wall; with GPU encode the same VM
should carry many more signals, but for 8x SDI + GPU + card passthrough prefer a
larger VM or bare metal with proper PCIe passthrough. Or spread signals across
multiple capture nodes (the node-agent model already supports N nodes; mam-api
routes each recorder to its node).
## 6. Multi-vendor capture (Blackmagic / Deltacast / AJA)
Today capture is hard-wired to `-f decklink`. Before three vendors accrue
special-cases, introduce a **source-backend abstraction** in capture-manager:
each backend returns ffmpeg input args + device discovery.
- **Blackmagic**: `-f decklink -i "<name>"` (current). Devices via
`ffmpeg -sources decklink`.
- **Deltacast**: VideoMaster SDK. No native ffmpeg demuxer upstream — needs an
SDK-backed capture (their SDK -> pipe to ffmpeg, or a small grabber). Plan a
`deltacast` backend that shells their tool into ffmpeg stdin (rawvideo).
- **AJA**: libajantv2. Also no upstream ffmpeg input; AJA ships `ntv2` capture
tools. Plan an `aja` backend feeding rawvideo into ffmpeg.
All backends converge on the SAME encode/output stage (HEVC-I NVENC + HLS), so
only the input differs. node-agent already binds the right /dev nodes per
sourceType (decklink/deltacast); extend for AJA.
## 7. Risks
- **4:2:2 / 10-bit chroma:** NVENC HEVC is 4:2:0 (8/10-bit). ProRes HQ is 4:2:2
10-bit. If a workflow REQUIRES 4:2:2 mezzanine, NVENC HEVC cannot match it and
those feeds stay on ProRes (CPU). Decide per-workflow.
- **Premiere growing HEVC support:** edit-while-record for HEVC-in-MXF (or frag
MOV) is unproven in our stack — this is the make-or-break validation (§8).
- **GPU contention** between live capture and post-record proxies on the same
L4; mitigate by prioritising capture / relocating proxy load.
- **Storage:** All-Intra HEVC bitrate ~ ProRes; expect similar disk usage.
- **Editor performance:** HEVC-I decode in Premiere is heavier than ProRes on
the edit workstation (decode cost moves to the editor). Validate scrubbing.
- **NVENC quality at all-intra** vs ProRes for archival; tune bitrate/preset.
## 8. Validation gate (do FIRST, before building the pipeline)
Prove the editor story on ONE channel before wiring 8:
1. Rebuild capture ffmpeg with NVENC; give the sidecar the L4.
2. Capture one DeckLink feed to All-Intra HEVC, writing a GROWING file to the
SMB share in (a) MXF OP1a, then (b) fragmented MOV.
3. While still recording, mount it in Premiere over SMB and confirm:
edit-while-record works, scrubbing is acceptable, audio in sync, file remains
valid after stop. Pick the container that works; if neither does, HEVC-I is
capture-only (no growing edit) and we keep ProRes for growing workflows.
## 9. Rollout
1. Validation gate (§8) on one channel.
2. Make capture codec/container a recorder setting; default growing feeds to
HEVC-I NVENC, keep ProRes selectable.
3. Move HLS preview to h264_nvenc.
4. Source-backend abstraction (§6) — land before Deltacast/AJA hardware.
5. GPU deinterlace + capacity test to 8 signals; finalise node sizing.

Binary file not shown.

View file

@ -1,73 +0,0 @@
# NLE Editor: React SPA Polish — Phases 13 Implementation Plan
> **Date:** 2026-05-24
> **Status:** Phase 1 IN PROGRESS
> **Progress:** Tasks 1.11.6 code-complete, pending test/deploy
---
## Phase 1 — Core Editor (IN PROGRESS)
### Task 1.1: Sequence API helpers in data.jsx ✅
- Added `getSequences`, `createSequence`, `getSequence`, `updateSequence`, `deleteSequence`, `syncSequenceClips`, `exportSequenceEDL` to `data.jsx`
- All exported on `window.ZAMPP_API`
### Task 1.2: Timecode.js wired into SPA ✅
- Added `<script src="js/timecode.js">` and `<script src="js/timeline.js">` to `index.html` before `screens-editor.jsx`
- `window.TC` available globally for 59.94 DF timecode math
### Task 1.3: TimelinePanel React component ✅
- `tlRef` container div in editor layout
- `useEffect` mounts `window.Timeline.init()` on first render
- `useEffect` pushes scale changes via `window.Timeline.setScale()`
- `onClipsChanged` / `onPlayheadMoved` callbacks connect timeline engine to React state
### Task 1.4: screens-editor.jsx rewrite ✅ (455 lines, was 162)
Full rewrite with:
- **App state**: `projectId`, `sequences`, `currentSeq`, `assets`, `sourceAsset`, `srcIn`/`srcOut`, `playheadFrames`, `history` (undo stack), `scale`, `tool`, `saveStatus`, `isDirty`
- **Source monitor**: `<video>` + `apiFetch('/assets/:id/stream')` + Mark In/Out + Insert button
- **Program monitor**: Virtual clip-by-clip playback — loads V1 clips sorted by `timeline_in_frames`, advances on `timeUpdate`/`ended` events
- **Media panel**: Asset list from `ZAMPP_DATA.ASSETS`, filter by bin, `AssetThumb` thumbnails, double-click loads source
- **Sequence management**: Picker `<select>`, "New sequence" modal, `openSequence()` loads via API
- **Auto-save**: `markDirty()` → debounce 2s → `syncSequenceClips()` → status updates
- **Undo/redo**: 50-step history stack, Ctrl+Z / Ctrl+Shift+Z
- **EDL export**: Button triggers `window.ZAMPP_API.exportSequenceEDL()`
- **Tool toolbar**: V/C/H buttons synced with `Timeline.setTool()`
- **Zoom slider**: Range input driving `window.Timeline.setScale()`
- **Keyboard handler**: I/O, V/C/H, Ctrl+Z/Shift+Z, Ctrl+S
### Task 1.5: "In Development" overlay removed ✅
- Deleted the `position: absolute; inset: 0; backdropFilter: blur(6px)` overlay div (was lines 98-117)
- Removed `FauxFrame` component reference
- All buttons are now functional
### Task 1.6: Editor nav badge removed ✅
- `shell.jsx`: `{ id: "editor", label: "Editor", icon: "editor" }` — no more `badge: { kind: "dev", text: "DEV" }`
### NEXT: Task 1.7 — Test & Deploy
1. `docker compose up -d --build web-ui`
2. Navigate to Editor route in browser
3. Verify: source monitor loads video, timeline renders with 4 track rows, Insert places clip, auto-save fires, EDL export downloads
---
## Phase 2 — UX Polish & Growing File (PENDING)
- [ ] 2.1 Multi-track refinements (ripple delete, snap, locking, overlap prevention)
- [ ] 2.2 Zoom slider + adaptive ruler
- [ ] 2.3 JKL transport + frame stepping
- [ ] 2.4 Waveform display on audio tracks
- [ ] 2.5 Inspector panel wiring
- [ ] 2.6 Style migration to Tailwind primitives
- [ ] 2.7 HLS live preview during capture
## Phase 3 — Export, Conform & Features (PENDING)
- [ ] 3.1 FCP XML export + conform queue
- [ ] 3.2 Hi-Res Auto-Relink
- [ ] 3.3 Timecoded Comments
- [ ] 3.4 Player Rebuild (P1)
- [ ] 3.5 Subclips (P2)
- [ ] 3.6 Multi-select & Bulk Ops (P3)
- [ ] 3.7 Smart Bins (P6)
- [ ] 3.8 Metadata Templates (P7)

File diff suppressed because it is too large Load diff

View file

@ -1,834 +0,0 @@
# Deltacast SDI Capture — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Wire up Deltacast VideoMaster SDI cards in the capture service using a C bridge binary that streams raw video to FFmpeg via pipe, with embedded audio via a named FIFO.
**Architecture:** A `deltacast-capture` C binary opens the VideoMaster board, waits for signal lock, emits a JSON format line to stderr, then streams raw UYVY video frames to stdout and 2-channel PCM audio to a named FIFO. `capture-manager.js` reads the JSON, spawns FFmpeg with `-f rawvideo -i pipe:0` for video and `-f s16le -i <fifo>` for audio, and pipes bridge stdout into FFmpeg stdin. Two concurrent SDK streams share the same board handle — `VHD_SDI_STPROC_DISJOINED_VIDEO` for video and `VHD_SDI_STPROC_DISJOINED_ANC` for audio.
**Tech Stack:** Deltacast VideoMaster C SDK 6.34.1 (`libvideomasterhd.so`, `libvideomasterhd_audio.so`), C17, CMake, Node.js ES modules, Docker multi-stage build.
---
## File Map
| Action | Path | Responsibility |
|---|---|---|
| Create | `services/capture/deltacast-bridge/CMakeLists.txt` | Build config for the bridge binary |
| Create | `services/capture/deltacast-bridge/main.c` | Bridge: board open, signal detect, video stream, audio thread |
| Modify | `services/capture/Dockerfile` | SDK extraction stage, bridge build stage, runtime .so install |
| Modify | `services/capture/src/capture-manager.js` | `readFirstStderrLine` helper, deltacast `_buildInputArgs`, bridge lifecycle in `start()`/`stop()` |
| Modify | `services/capture/src/routes/capture.js` | Accept `deltacast` as a valid `source_type` |
---
## Task 1: Bridge CMakeLists.txt
**Files:**
- Create: `services/capture/deltacast-bridge/CMakeLists.txt`
- [ ] **Step 1: Create the CMakeLists.txt**
```cmake
cmake_minimum_required(VERSION 3.16)
project(deltacast-bridge C)
set(CMAKE_C_STANDARD 17)
set(SDK_ROOT "/sdk" CACHE PATH "Path to extracted VideoMaster SDK")
add_executable(deltacast-capture main.c)
target_include_directories(deltacast-capture PRIVATE
${SDK_ROOT}/include/videomaster
)
target_link_directories(deltacast-capture PRIVATE
${SDK_ROOT}/lib
)
target_link_libraries(deltacast-capture PRIVATE
videomasterhd
videomasterhd_audio
pthread
)
# Embed the SDK RPATH so the binary finds the .so at runtime
set_target_properties(deltacast-capture PROPERTIES
INSTALL_RPATH "/usr/local/lib/deltacast"
BUILD_WITH_INSTALL_RPATH TRUE
)
```
- [ ] **Step 2: Commit**
```bash
git add services/capture/deltacast-bridge/CMakeLists.txt
git commit -m "build(capture): add CMakeLists for deltacast-capture bridge binary"
```
---
## Task 2: Bridge main.c
**Files:**
- Create: `services/capture/deltacast-bridge/main.c`
The binary: parses CLI args, opens the board, waits for signal lock, emits one JSON line to stderr, then spawns an audio thread writing to a FIFO and runs a video capture loop writing raw UYVY frames to stdout.
- [ ] **Step 1: Create the bridge source file**
```c
/* services/capture/deltacast-bridge/main.c
*
* Deltacast VideoMaster SDI capture bridge.
* Writes raw UYVY video to stdout and stereo PCM to a named FIFO.
* Emits one JSON line to stderr on signal lock before streaming starts.
*
* Usage:
* deltacast-capture --device <N> --port <N> --audio-pipe <path>
* [--signal-timeout <sec>]
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "VideoMasterHD_Core.h"
#include "VideoMasterHD_Sdi.h"
#include "VideoMasterHD_Sdi_Audio.h"
/* ── Globals ─────────────────────────────────────────────────────────── */
static atomic_int g_stop = 0;
static void on_signal(int s) { (void)s; atomic_store(&g_stop, 1); }
/* ── Stream type by port index ───────────────────────────────────────── */
static ULONG rx_streamtype(unsigned port) {
switch (port) {
case 0: return VHD_ST_RX0;
case 1: return VHD_ST_RX1;
case 2: return VHD_ST_RX2;
case 3: return VHD_ST_RX3;
default: return VHD_ST_RX0;
}
}
/* ── Loopback board property by port index ───────────────────────────── */
static ULONG loopback_prop(unsigned port) {
switch (port) {
case 0: return VHD_CORE_BP_PASSIVE_LOOPBACK_0;
case 1: return VHD_CORE_BP_PASSIVE_LOOPBACK_1;
case 2: return VHD_CORE_BP_PASSIVE_LOOPBACK_2;
case 3: return VHD_CORE_BP_PASSIVE_LOOPBACK_3;
default: return VHD_CORE_BP_PASSIVE_LOOPBACK_0;
}
}
/* ── Video standard → width/height/fps/interlaced ───────────────────── */
typedef struct { int width, height, fps_num, fps_den; int interlaced; } VideoInfo;
static VideoInfo video_info(VHD_VIDEOSTANDARD std, VHD_CLOCKDIVISOR div) {
int ntsc = (div == VHD_CLOCKDIV_1001);
switch (std) {
case VHD_VIDEOSTD_S274M_1080p_25Hz: return (VideoInfo){1920,1080,25,1,0};
case VHD_VIDEOSTD_S274M_1080p_30Hz: return (VideoInfo){1920,1080,ntsc?30000:30,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080p_24Hz: return (VideoInfo){1920,1080,ntsc?24000:24,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080p_50Hz: return (VideoInfo){1920,1080,50,1,0};
case VHD_VIDEOSTD_S274M_1080p_60Hz: return (VideoInfo){1920,1080,ntsc?60000:60,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080psf_24Hz: return (VideoInfo){1920,1080,ntsc?24000:24,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080psf_25Hz: return (VideoInfo){1920,1080,25,1,0};
case VHD_VIDEOSTD_S274M_1080psf_30Hz: return (VideoInfo){1920,1080,ntsc?30000:30,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080i_50Hz: return (VideoInfo){1920,1080,25,1,1};
case VHD_VIDEOSTD_S274M_1080i_60Hz: return (VideoInfo){1920,1080,ntsc?30000:30,ntsc?1001:1,1};
case VHD_VIDEOSTD_S296M_720p_50Hz: return (VideoInfo){1280,720,50,1,0};
case VHD_VIDEOSTD_S296M_720p_60Hz: return (VideoInfo){1280,720,ntsc?60000:60,ntsc?1001:1,0};
case VHD_VIDEOSTD_S296M_720p_25Hz: return (VideoInfo){1280,720,25,1,0};
case VHD_VIDEOSTD_S296M_720p_30Hz: return (VideoInfo){1280,720,ntsc?30000:30,ntsc?1001:1,0};
case VHD_VIDEOSTD_S296M_720p_24Hz: return (VideoInfo){1280,720,ntsc?24000:24,ntsc?1001:1,0};
case VHD_VIDEOSTD_3840x2160p_24Hz: return (VideoInfo){3840,2160,ntsc?24000:24,ntsc?1001:1,0};
case VHD_VIDEOSTD_3840x2160p_25Hz: return (VideoInfo){3840,2160,25,1,0};
case VHD_VIDEOSTD_3840x2160p_30Hz: return (VideoInfo){3840,2160,ntsc?30000:30,ntsc?1001:1,0};
case VHD_VIDEOSTD_3840x2160p_50Hz: return (VideoInfo){3840,2160,50,1,0};
case VHD_VIDEOSTD_3840x2160p_60Hz: return (VideoInfo){3840,2160,ntsc?60000:60,ntsc?1001:1,0};
case VHD_VIDEOSTD_S259M_NTSC_480: return (VideoInfo){720,480,ntsc?30000:30,ntsc?1001:1,1};
default: return (VideoInfo){1920,1080,25,1,0};
}
}
/* ── Audio thread ────────────────────────────────────────────────────── */
typedef struct {
HANDLE board;
unsigned port;
ULONG video_std;
ULONG clock_div;
const char *fifo_path;
} AudioArgs;
static void *audio_thread(void *arg) {
AudioArgs *a = (AudioArgs *)arg;
HANDLE stream = NULL;
ULONG r = VHD_OpenStreamHandle(a->board, rx_streamtype(a->port),
VHD_SDI_STPROC_DISJOINED_ANC,
NULL, &stream, NULL);
if (r != VHDERR_NOERROR) {
fprintf(stderr, "[audio] VHD_OpenStreamHandle failed: %lu\n", r);
return NULL;
}
VHD_SetStreamProperty(stream, VHD_SDI_SP_VIDEO_STANDARD, a->video_std);
VHD_SetStreamProperty(stream, VHD_SDI_SP_CLOCK_SYSTEM, a->clock_div);
VHD_SetStreamProperty(stream, VHD_CORE_SP_TRANSFER_SCHEME, VHD_TRANSFER_SLAVED);
/* Stereo pair, 16-bit, 48kHz on group 0 channel 0 */
ULONG max_samples = VHD_GetNbSamples((VHD_VIDEOSTANDARD)a->video_std,
(VHD_CLOCKDIVISOR)a->clock_div,
VHD_ASR_48000, 0);
ULONG block_size = VHD_GetBlockSize(VHD_AF_16, VHD_AM_STEREO);
ULONG buf_sz = (max_samples + 4) * block_size; /* +4 for 29.97 variation */
unsigned char *buf = calloc(1, buf_sz);
if (!buf) { VHD_CloseStreamHandle(stream); return NULL; }
VHD_AUDIOINFO ai;
memset(&ai, 0, sizeof(ai));
ai.pAudioGroups[0].pAudioChannels[0].Mode = VHD_AM_STEREO;
ai.pAudioGroups[0].pAudioChannels[0].BufferFormat = VHD_AF_16;
ai.pAudioGroups[0].pAudioChannels[0].pData = buf;
if (VHD_StartStream(stream) != VHDERR_NOERROR) {
free(buf); VHD_CloseStreamHandle(stream); return NULL;
}
/* Open FIFO for writing — blocks until FFmpeg opens the read end */
int fd = open(a->fifo_path, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "[audio] open FIFO failed: %s\n", strerror(errno));
VHD_StopStream(stream); VHD_CloseStreamHandle(stream); free(buf);
return NULL;
}
HANDLE slot = NULL;
while (!atomic_load(&g_stop)) {
r = VHD_LockSlotHandle(stream, &slot);
if (r == VHDERR_NOERROR) {
ai.pAudioGroups[0].pAudioChannels[0].DataSize = buf_sz;
if (VHD_SlotExtractAudio(slot, &ai) == VHDERR_NOERROR) {
ULONG sz = ai.pAudioGroups[0].pAudioChannels[0].DataSize;
if (sz > 0) write(fd, buf, sz);
}
VHD_UnlockSlotHandle(slot);
} else if (r != VHDERR_TIMEOUT) {
break;
}
}
close(fd);
VHD_StopStream(stream);
VHD_CloseStreamHandle(stream);
free(buf);
return NULL;
}
/* ── Main ────────────────────────────────────────────────────────────── */
int main(int argc, char *argv[]) {
unsigned device_id = 0;
unsigned port_id = 0;
int sig_timeout = 30;
const char *audio_pipe = NULL;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--device") && i+1 < argc) device_id = (unsigned)atoi(argv[++i]);
else if (!strcmp(argv[i], "--port") && i+1 < argc) port_id = (unsigned)atoi(argv[++i]);
else if (!strcmp(argv[i], "--audio-pipe") && i+1 < argc) audio_pipe = argv[++i];
else if (!strcmp(argv[i], "--signal-timeout") && i+1 < argc) sig_timeout = atoi(argv[++i]);
}
signal(SIGINT, on_signal);
signal(SIGTERM, on_signal);
/* ── Init API ─────────────────────────────────────────────────── */
ULONG dll_ver, nb_boards;
if (VHD_GetApiInfo(&dll_ver, &nb_boards) != VHDERR_NOERROR) {
fprintf(stderr, "{\"error\":\"VHD_GetApiInfo failed\"}\n");
return 1;
}
if (device_id >= nb_boards) {
fprintf(stderr, "{\"error\":\"board %u not found (%lu detected)\"}\n", device_id, nb_boards);
return 1;
}
/* ── Open board ───────────────────────────────────────────────── */
HANDLE board = NULL;
if (VHD_OpenBoardHandle(device_id, &board, NULL, 0) != VHDERR_NOERROR) {
fprintf(stderr, "{\"error\":\"VHD_OpenBoardHandle failed for board %u\"}\n", device_id);
return 1;
}
/* Disable passive (relay) loopback so RX is live */
VHD_SetBoardProperty(board, loopback_prop(port_id), FALSE);
/* ── Wait for signal lock ──────────────────────────────────────── */
ULONG video_std = (ULONG)NB_VHD_VIDEOSTANDARDS;
struct timespec deadline;
clock_gettime(CLOCK_MONOTONIC, &deadline);
deadline.tv_sec += sig_timeout;
while (!atomic_load(&g_stop)) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if (now.tv_sec > deadline.tv_sec ||
(now.tv_sec == deadline.tv_sec && now.tv_nsec >= deadline.tv_nsec)) break;
VHD_GetChannelProperty(board, VHD_RX_CHANNEL, port_id,
VHD_SDI_CP_VIDEO_STANDARD, &video_std);
if (video_std != (ULONG)NB_VHD_VIDEOSTANDARDS) break;
struct timespec ts = {0, 200000000L}; /* 200ms */
nanosleep(&ts, NULL);
}
if (atomic_load(&g_stop) || video_std == (ULONG)NB_VHD_VIDEOSTANDARDS) {
fprintf(stderr,
"{\"error\":\"no signal on board %u port %u within %ds\"}\n",
device_id, port_id, sig_timeout);
VHD_CloseBoardHandle(board);
return 1;
}
ULONG clock_div = VHD_CLOCKDIV_1;
VHD_GetChannelProperty(board, VHD_RX_CHANNEL, port_id,
VHD_SDI_CP_CLOCK_DIVISOR, &clock_div);
VideoInfo vi = video_info((VHD_VIDEOSTANDARD)video_std,
(VHD_CLOCKDIVISOR)clock_div);
/* ── Emit format JSON to stderr (one line, flushed) ─────────────── */
fprintf(stderr,
"{\"width\":%d,\"height\":%d,\"fps_num\":%d,\"fps_den\":%d,"
"\"interlaced\":%s,\"pix_fmt\":\"uyvy422\","
"\"audio_channels\":2,\"audio_rate\":48000,"
"\"device\":%u,\"port\":%u}\n",
vi.width, vi.height, vi.fps_num, vi.fps_den,
vi.interlaced ? "true" : "false",
device_id, port_id);
fflush(stderr);
/* ── Open video stream ───────────────────────────────────────────── */
HANDLE video_stream = NULL;
if (VHD_OpenStreamHandle(board, rx_streamtype(port_id),
VHD_SDI_STPROC_DISJOINED_VIDEO,
NULL, &video_stream, NULL) != VHDERR_NOERROR) {
fprintf(stderr, "{\"error\":\"VHD_OpenStreamHandle (video) failed\"}\n");
VHD_CloseBoardHandle(board);
return 1;
}
VHD_SetStreamProperty(video_stream, VHD_SDI_SP_VIDEO_STANDARD, video_std);
VHD_SetStreamProperty(video_stream, VHD_SDI_SP_CLOCK_SYSTEM, clock_div);
VHD_SetStreamProperty(video_stream, VHD_CORE_SP_TRANSFER_SCHEME, VHD_TRANSFER_SLAVED);
VHD_SetStreamProperty(video_stream, VHD_CORE_SP_SLOTS_QUEUE_DEPTH, 8);
/* ── Launch audio thread (FIFO open blocks until FFmpeg connects) ── */
pthread_t audio_tid = 0;
AudioArgs audio_args = { board, port_id, video_std, clock_div, audio_pipe };
if (audio_pipe) {
pthread_create(&audio_tid, NULL, audio_thread, &audio_args);
}
/* ── Start video stream ──────────────────────────────────────────── */
if (VHD_StartStream(video_stream) != VHDERR_NOERROR) {
atomic_store(&g_stop, 1);
if (audio_tid) pthread_join(audio_tid, NULL);
VHD_CloseStreamHandle(video_stream);
VHD_CloseBoardHandle(board);
return 1;
}
/* ── Video capture loop ──────────────────────────────────────────── */
HANDLE slot = NULL;
while (!atomic_load(&g_stop)) {
ULONG r = VHD_LockSlotHandle(video_stream, &slot);
if (r == VHDERR_NOERROR) {
BYTE *buf = NULL;
ULONG sz = 0;
if (VHD_GetSlotBuffer(slot, VHD_SDI_BT_VIDEO, &buf, &sz) == VHDERR_NOERROR) {
ULONG written = 0;
while (written < sz) {
ssize_t n = write(STDOUT_FILENO, buf + written, sz - written);
if (n <= 0) { atomic_store(&g_stop, 1); break; }
written += (ULONG)n;
}
}
VHD_UnlockSlotHandle(slot);
} else if (r != VHDERR_TIMEOUT) {
break;
}
}
/* ── Cleanup ─────────────────────────────────────────────────────── */
VHD_StopStream(video_stream);
VHD_CloseStreamHandle(video_stream);
if (audio_tid) pthread_join(audio_tid, NULL);
VHD_CloseBoardHandle(board);
return 0;
}
```
- [ ] **Step 2: Commit**
```bash
git add services/capture/deltacast-bridge/main.c
git commit -m "feat(capture): add deltacast-capture bridge binary source"
```
---
## Task 3: Dockerfile — SDK extraction + bridge build + runtime
**Files:**
- Modify: `services/capture/Dockerfile`
The existing Dockerfile has three logical sections: FFmpeg build, runtime. We add two new stages before FFmpeg and patch the runtime stage.
- [ ] **Step 1: Read the current Dockerfile**
Read `services/capture/Dockerfile` and verify it starts with `FROM debian:bookworm AS ffmpeg-builder`.
- [ ] **Step 2: Prepend two new stages and patch runtime**
The full new Dockerfile:
```dockerfile
# ── Stage 0: Extract Deltacast VideoMaster SDK ───────────────────────────
FROM debian:bookworm AS sdk-extractor
COPY videomaster-linux.x64-6.34.1-dev.tar.gz /tmp/
RUN mkdir -p /sdk && tar -xzf /tmp/videomaster-linux.x64-6.34.1-dev.tar.gz -C /sdk
# ── Stage 1: Build deltacast-capture bridge binary ───────────────────────
FROM debian:bookworm AS bridge-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=sdk-extractor /sdk /sdk
COPY deltacast-bridge/ /bridge/
RUN cmake -S /bridge -B /bridge/build \
-DCMAKE_BUILD_TYPE=Release \
-DSDK_ROOT=/sdk \
&& cmake --build /bridge/build -j$(nproc)
# ── Stage 2: Build FFmpeg with DeckLink + NVENC (HEVC/H264) support ──────
# (unchanged — keep original content here)
FROM debian:bookworm AS ffmpeg-builder
# ... (rest of the existing ffmpeg-builder stage unchanged) ...
# ── Stage 3: Runtime image ───────────────────────────────────────────────
FROM node:20-bookworm
# Runtime deps for compiled ffmpeg libs (unchanged)
RUN apt-get update && apt-get install -y --no-install-recommends \
libx264-164 libx265-199 libvpx7 libopus0 libmp3lame0 \
libsrt1.5-openssl libzmq5 libstdc++6 libc++1 libc++abi1 \
&& rm -rf /var/lib/apt/lists/*
# Copy compiled ffmpeg/ffprobe (unchanged)
COPY --from=ffmpeg-builder /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg
COPY --from=ffmpeg-builder /usr/local/bin/ffprobe /usr/local/bin/ffprobe
COPY --from=ffmpeg-builder /usr/local/lib/ /usr/local/lib/
# DeckLink runtime .so (unchanged)
COPY lib/libDeckLinkAPI.so /usr/lib/libDeckLinkAPI.so
COPY lib/libDeckLinkPreviewAPI.so /usr/lib/libDeckLinkPreviewAPI.so
# Deltacast bridge binary + SDK runtime libs
COPY --from=bridge-builder /bridge/build/deltacast-capture /usr/local/bin/deltacast-capture
COPY --from=sdk-extractor /sdk/lib/libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/
COPY --from=sdk-extractor /sdk/lib/libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/
RUN ln -sf libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd.so.6 \
&& ln -sf libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd.so \
&& ln -sf libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd_audio.so.6 \
&& ln -sf libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd_audio.so \
&& ldconfig /usr/local/lib/deltacast \
&& ldconfig
RUN mkdir -p /live /growing
WORKDIR /app
COPY package*.json ./
RUN npm install --omit=dev
COPY . .
EXPOSE 3001
CMD ["node", "src/index.js"]
```
**Implementation note:** Edit the existing Dockerfile. Prepend the two new FROM stages (sdk-extractor, bridge-builder) before the existing `FROM debian:bookworm AS ffmpeg-builder` line. Then in the final runtime stage, add the Deltacast `COPY` and `RUN` lines after the DeckLink `.so` lines (before the `RUN mkdir -p /live /growing` line).
- [ ] **Step 3: Commit**
```bash
git add services/capture/Dockerfile
git commit -m "build(capture): add Deltacast SDK extraction and bridge build stages to Dockerfile"
```
---
## Task 4: capture-manager.js — `readFirstStderrLine` helper
**Files:**
- Modify: `services/capture/src/capture-manager.js` (add helper near top, after imports)
- [ ] **Step 1: Add the helper function after the existing imports (after line 6 `import { v4 as uuidv4 } from 'uuid';`)**
```js
/**
* Reads the first line from a spawned process's stderr stream.
* Resolves with the parsed JSON object when the first '\n' arrives.
* Rejects if the process exits with a non-zero code before emitting a line,
* or if timeoutMs elapses.
*/
function readFirstStderrLine(proc, timeoutMs = 35_000) {
return new Promise((resolve, reject) => {
let buf = '';
let settled = false;
const settle = (fn) => { if (settled) return; settled = true; fn(); };
const timer = setTimeout(() => {
settle(() => reject(new Error(`deltacast-capture: timed out waiting for format JSON after ${timeoutMs}ms`)));
}, timeoutMs);
proc.stderr.setEncoding('utf8');
proc.stderr.on('data', (chunk) => {
buf += chunk;
const nl = buf.indexOf('\n');
if (nl === -1) return;
const line = buf.slice(0, nl).trim();
clearTimeout(timer);
try {
const parsed = JSON.parse(line);
if (parsed.error) {
settle(() => reject(new Error(`deltacast-capture: ${parsed.error}`)));
} else {
settle(() => resolve(parsed));
}
} catch (e) {
settle(() => reject(new Error(`deltacast-capture: invalid JSON on stderr: ${line}`)));
}
});
proc.on('exit', (code) => {
clearTimeout(timer);
settle(() => reject(new Error(`deltacast-capture: exited with code ${code} before emitting format JSON`)));
});
});
}
```
- [ ] **Step 2: Commit**
```bash
git add services/capture/src/capture-manager.js
git commit -m "feat(capture): add readFirstStderrLine helper for deltacast bridge handshake"
```
---
## Task 5: capture-manager.js — Deltacast `_buildInputArgs`
**Files:**
- Modify: `services/capture/src/capture-manager.js` — replace the `deltacast` branch of `_buildInputArgs` (currently lines 160191)
- [ ] **Step 1: Replace the existing deltacast branch**
Find the block starting with `// Deltacast SDI via VideoMaster SDK FFmpeg plugin.` and ending at the closing `}` of the `if (sourceType === 'deltacast')` block. Replace the entire `if (sourceType === 'deltacast') { ... }` block with:
```js
if (sourceType === 'deltacast') {
const idx = (typeof device === 'number' || /^\d+$/.test(String(device)))
? parseInt(device, 10) : 0;
const audioFifo = `/tmp/dc-audio-${this._sessionIdForBridge}`;
// Create the audio FIFO before spawning the bridge.
const { execSync: _exec } = await import('child_process');
try { _exec(`mkfifo ${audioFifo}`); } catch (_) { /* may already exist */ }
const bridge = spawn('deltacast-capture', [
'--device', String(idx),
'--port', String(idx),
'--audio-pipe', audioFifo,
'--signal-timeout', '30',
], { stdio: ['ignore', 'pipe', 'pipe'] });
// Log bridge stderr after the first line (non-JSON diagnostic output)
let firstLineDone = false;
bridge.stderr.on('data', (d) => {
if (firstLineDone) console.error(`[deltacast-bridge] ${d}`);
else if (d.toString().includes('\n')) firstLineDone = true;
});
const fmt = await readFirstStderrLine(bridge, 35_000);
// fmt: { width, height, fps_num, fps_den, interlaced, pix_fmt,
// audio_channels, audio_rate, device, port }
return {
inputArgs: [
'-f', 'rawvideo',
'-pix_fmt', fmt.pix_fmt,
'-video_size', `${fmt.width}x${fmt.height}`,
'-framerate', `${fmt.fps_num}/${fmt.fps_den}`,
'-i', 'pipe:0',
'-f', 's16le',
'-ar', String(fmt.audio_rate),
'-ac', String(fmt.audio_channels),
'-i', audioFifo,
],
isNetwork: false,
bridgeProcess: bridge,
audioFifo,
interlaced: !!fmt.interlaced,
};
}
```
- [ ] **Step 2: Commit**
```bash
git add services/capture/src/capture-manager.js
git commit -m "feat(capture): replace deltacast _buildInputArgs stub with real bridge spawn"
```
---
## Task 6: capture-manager.js — `start()` bridge lifecycle + `stop()` cleanup
**Files:**
- Modify: `services/capture/src/capture-manager.js`
Four changes to `start()` and one to `stop()`.
- [ ] **Step 1: Store session ID before `_buildInputArgs` call**
In `start()`, before the `const { inputArgs, isNetwork } = await this._buildInputArgs(...)` call (currently around line 307), add:
```js
this._sessionIdForBridge = sessionId;
```
- [ ] **Step 2: Store bridge state after `_buildInputArgs` returns**
After `const { inputArgs, isNetwork } = await this._buildInputArgs(...)`, change the destructuring to also capture `bridgeProcess` and `audioFifo`:
```js
const { inputArgs, isNetwork, bridgeProcess = null, audioFifo = null, interlaced = false } = await this._buildInputArgs({
sourceType, device, sourceUrl, listen, listenPort, streamKey,
});
```
- [ ] **Step 3: Pipe bridge stdout into FFmpeg stdin for deltacast**
After `const hiresProcess = spawn('ffmpeg', hiresArgs, { stdio: hiresStdio });`, add:
```js
// For deltacast, the bridge writes raw video to its stdout.
// Pipe it into FFmpeg's stdin so FFmpeg reads -i pipe:0.
if (bridgeProcess) {
bridgeProcess.stdout.pipe(hiresProcess.stdin);
}
```
- [ ] **Step 4: Add bridge to `processes` map and `audioFifo` to `currentSession`**
Change the existing `const processes = { hires: hiresProcess };` line to:
```js
const processes = { hires: hiresProcess };
if (bridgeProcess) processes.bridge = bridgeProcess;
```
And in the `this.state.currentSession = { ... }` object (near the end of `start()`), add:
```js
audioFifo,
```
to the object literal (alongside `sourceType`, `device`, etc.).
- [ ] **Step 5: Fix deinterlace filter to include deltacast interlaced signals**
Find the line (currently ~321):
```js
const sdiFilterArgs = (sourceType === 'sdi') ? ['-vf', 'yadif=mode=1:deint=1'] : [];
```
Replace with:
```js
const isInterlacedSource = sourceType === 'sdi' || (sourceType === 'deltacast' && interlaced);
const sdiFilterArgs = isInterlacedSource ? ['-vf', 'yadif=mode=1:deint=1'] : [];
```
- [ ] **Step 6: Include deltacast in the HLS split-output branch**
Find the line (currently ~334):
```js
if (sourceType === 'sdi' && this._assetIdForHls) {
```
Replace with:
```js
if ((sourceType === 'sdi' || sourceType === 'deltacast') && this._assetIdForHls) {
```
- [ ] **Step 7: Kill bridge in `stop()` and clean up FIFO**
In the `stop()` method, find the existing kill block:
```js
if (processes.hires) processes.hires.kill('SIGINT');
if (processes.proxy) processes.proxy.kill('SIGINT');
if (processes.hls) { try { processes.hls.kill('SIGINT'); } catch (_) {} }
```
Add a bridge kill and FIFO cleanup:
```js
if (processes.hires) processes.hires.kill('SIGINT');
if (processes.proxy) processes.proxy.kill('SIGINT');
if (processes.hls) { try { processes.hls.kill('SIGINT'); } catch (_) {} }
if (processes.bridge) { try { processes.bridge.kill('SIGINT'); } catch (_) {} }
```
Then after the existing `await Promise.all(uploadPromises);` block (around line 462), add FIFO cleanup:
```js
if (currentSession.audioFifo) {
try { (await import('node:fs')).unlinkSync(currentSession.audioFifo); } catch (_) {}
}
```
- [ ] **Step 8: Commit**
```bash
git add services/capture/src/capture-manager.js
git commit -m "feat(capture): wire bridge process lifecycle into start/stop for deltacast"
```
---
## Task 7: routes/capture.js — Accept `deltacast` source_type
**Files:**
- Modify: `services/capture/src/routes/capture.js` (line 329)
- [ ] **Step 1: Find the source_type validation block in `/start` handler (around line 318)**
Current code:
```js
} else {
return res.status(400).json({
error: `Unknown source_type: ${source_type}. Must be sdi, srt, or rtmp`,
});
}
```
This `else` branch fires when source_type isn't `sdi`, `srt`, or `rtmp`. Add `deltacast` to the accepted list.
- [ ] **Step 2: Add deltacast validation before the else block**
After the `} else if (source_type === 'srt' || source_type === 'rtmp') {` block, add:
```js
} else if (source_type === 'deltacast') {
if (device === undefined || device === null) {
return res.status(400).json({ error: 'deltacast source requires: device (board/port index)' });
}
} else {
return res.status(400).json({
error: `Unknown source_type: ${source_type}. Must be sdi, srt, rtmp, or deltacast`,
});
}
```
- [ ] **Step 3: Commit**
```bash
git add services/capture/src/routes/capture.js
git commit -m "feat(capture): accept deltacast as valid source_type in /start handler"
```
---
## Task 8: Smoke test — verify the build and Node.js changes
**Files:** None created.
- [ ] **Step 1: Verify the bridge compiles on the capture host (or in Docker)**
On the Deltacast machine (once it is available), run:
```bash
cd services/capture
tar -xzf ../../videomaster-linux.x64-6.34.1-dev.tar.gz -C /tmp/sdk
cmake -S deltacast-bridge -B /tmp/bridge-build -DSDK_ROOT=/tmp/sdk -DCMAKE_BUILD_TYPE=Release
cmake --build /tmp/bridge-build -j$(nproc)
ls -lh /tmp/bridge-build/deltacast-capture
```
Expected: binary present, size ~50200KB.
Until the hardware machine is available, verify the CMakeLists.txt syntax is correct by running the configure step only:
```bash
cmake -S services/capture/deltacast-bridge -B /tmp/bridge-test \
-DSDK_ROOT=C:/Users/zacga/Nextcloud/Claude/Projects/Dragonflight \
--check-system-vars 2>&1 | head -20
```
- [ ] **Step 2: Verify capture-manager.js has no syntax errors**
```bash
cd services/capture
node --input-type=module < src/capture-manager.js 2>&1 | head -5
```
Expected: no output (file imports fine) or a module-not-found error for uuid (acceptable — the file is correct).
- [ ] **Step 3: Verify routes/capture.js has no syntax errors**
```bash
node --input-type=module < services/capture/src/routes/capture.js 2>&1 | head -5
```
Expected: no output or dependency error only.
- [ ] **Step 4: Confirm deltacast recorder creation is rejected correctly without device param**
Start the capture service locally (if possible) and POST:
```bash
curl -s -X POST http://localhost:3001/capture/start \
-H 'Content-Type: application/json' \
-d '{"project_id":"test","clip_name":"test","source_type":"deltacast"}' | jq .
```
Expected response:
```json
{"error":"deltacast source requires: device (board/port index)"}
```
- [ ] **Step 5: Final commit if any fixups were needed**
```bash
git add -A
git commit -m "fix(capture): deltacast smoke-test fixups"
```
---
## Hardware Validation Checklist (run on the Deltacast machine)
After the hardware machine is available:
1. Build the Docker image: `docker compose build capture`
2. Create a recorder with `source_type=deltacast`, `device=0`
3. Confirm capture container logs show the JSON format line within 5s of feed going live
4. Confirm recorder status shows `signal: "receiving"`
5. Record a 30s clip → verify asset created, proxy + HLS generated
6. Test stop mid-record → file finalized correctly
7. Test no-signal path → recorder stays idle, no asset created
8. Test container restart mid-record → existing asset finalized via `/finalize` endpoint

View file

@ -1,272 +0,0 @@
# YouTube Importer — Design Spec
> Status: **design approved 2026-05-23**, awaiting user review of the spec before the implementation plan is written.
## Context
The Ingest group in Dragonflight today covers file Upload, Recorders (SRT/RTMP/SDI), Capture (DeckLink), Monitors, and Schedule. There is no path to bring in media that already lives on the public web. The frequent ask is: "I want to grab a YouTube link and have it become an asset in my project, with the same proxy/thumbnail pipeline as anything else." This spec adds a YouTube importer that mirrors the existing upload flow: paste a URL, pick a project, click Import, and the asset shows up in the Library once the worker is done.
The importer rides on the existing job pipeline. After the download lands in S3, the asset re-enters the same proxy → thumbnail → ready path as a regular upload, so there is no parallel "imported asset" lifecycle to maintain.
## Goals & non-goals
**Goals**
- Paste a public YouTube URL, end up with a `ready` asset in the chosen project.
- Reuse the existing `assets` table, S3 layout, BullMQ pipeline, and Jobs screen — no parallel state machine.
- Progress visible from both the import screen (queue rows) and the Jobs screen.
- Clear, actionable errors for the obvious failure modes (private, age-gated, removed, geo-blocked, network).
**Non-goals**
- Playlists, channels, or batch-paste of multiple URLs. Single URL per submission. (Easy to add later.)
- Cookies / login. Private, members-only, and age-gated videos are out of scope v1.
- Quality picker. Always grabs best MP4 (with M4A audio merge fallback).
- Non-YouTube sources (Vimeo, Twitch VODs, Dropbox links, etc.). The route is `/imports/youtube` precisely to leave room for siblings later.
- Auto-update of yt-dlp inside the running container. Updates land via image rebuild.
- Copyright enforcement. We surface a one-line "only import videos you have rights to use" note and stop there.
## Architecture
The importer threads through four existing layers:
```
[web-ui] YouTube screen ──POST /imports/youtube──▶ [mam-api]
assets row (status='ingesting')
jobs row (type='youtube_import')
BullMQ "import" queue
[worker]
yt-dlp download → S3 originals/
ffprobe metadata → assets row
status='processing'
BullMQ "proxy" queue ◀── existing path
proxy → thumbnail → ready
```
Once the worker hands off to the `proxy` queue, the asset is indistinguishable from one that came through Upload — same proxy worker, same thumbnail worker, same Library list.
## 1. UX
### Nav
A 6th child is added to the **Ingest** group in `shell.jsx`, between Upload and Recorders:
```js
{ id: "youtube", label: "YouTube", icon: "download" },
```
The `download` glyph already exists in `icons.jsx`. The matching `ingestChildren` array in `shell.jsx` and the crumbs map in `app.jsx` both gain `"youtube"`.
### Screen
A new `YouTubeImport` component lives in `screens-ingest.jsx` and is exported on `window` alongside `Upload`, `Recorders`, etc. It is registered as a route in `app.jsx`.
Layout — visually a sibling of the Upload screen:
- **Header**: title "YouTube", subtitle "Paste a link — we download and import the best available MP4."
- **Project selector**: same `select` element as Upload's, pre-selected to the first project.
- **URL input**: a single-line `field-input` with placeholder "Paste a YouTube URL (youtube.com/watch, youtu.be, or shorts)…" and an inline **Import** button. Enter submits. The button is disabled until a URL pattern matches.
- **Subtitle line under the input**: "Only import videos you have rights to use. Private, age-gated, and members-only videos are not supported."
- **Queue panel**: identical structure to Upload's queue — one row per submitted URL, showing:
- Source icon (use `link` glyph) and the URL (truncated middle, full URL in `title` tooltip).
- Title once known (filled in by a poll on the asset row).
- Progress bar tied to job `progress` (0100). The worker drives this between 5 and 60 % for download and 60 to 100 % for upload + DB writes.
- Status pill: queued → downloading → processing → done / failed.
- Error text if the job fails (red, one line).
- A "Clear done" button at the top of the queue.
The queue persists for the session in component state only — no separate UI table. Jobs screen remains the canonical history.
### URL validation (client-side, before POST)
Accept (case-insensitive) any of these patterns:
- `https?://(www\.|m\.)?youtube\.com/watch\?[^ ]*v=[A-Za-z0-9_-]{11}`
- `https?://youtu\.be/[A-Za-z0-9_-]{11}`
- `https?://(www\.)?youtube\.com/shorts/[A-Za-z0-9_-]{11}`
Anything else is rejected inline ("That doesn't look like a YouTube URL") without an API call. The server re-validates as a defense-in-depth check.
### Out-of-scope v1 (called out, not built)
- Pasting a playlist URL. Server returns 400 "Playlists aren't supported yet."
- Multi-line paste. Single URL only.
- Quality picker. yt-dlp format string is hard-coded.
- Cookies upload. Private videos fail with a clear message.
## 2. API
### Route
New file `services/mam-api/src/routes/imports.js`, mounted at `/api/v1/imports` in `services/mam-api/src/index.js`.
**`POST /api/v1/imports/youtube`**
Request body:
```json
{ "url": "https://youtu.be/dQw4w9WgXcQ", "projectId": "uuid", "binId": "uuid?" }
```
Behavior:
1. Validate `url` against the same three regexes as the client. 400 on miss.
2. Reject playlist URLs (URL contains `list=`) with 400 "Playlists aren't supported yet."
3. Generate `assetId = uuidv4()`.
4. Insert into `assets` with:
- `status='ingesting'`
- `media_type='video'`
- `filename = url` (placeholder; worker overwrites with the sanitized title once yt-dlp prints metadata — keeps the row queryable in the meantime)
- `display_name = url` (same; worker overwrites)
- `original_s3_key = NULL` (worker fills in)
- `source_url = url` (new column — see Schema)
- `project_id`, `bin_id`, timestamps.
5. Insert into `jobs` with `type='youtube_import'`, `asset_id`, `payload={ url }`, `status='queued'`, `progress=0`.
6. Enqueue BullMQ job on the `import` queue:
```js
await importQueue.add('youtube', { assetId, url });
```
7. Respond `200 { assetId, jobId }`.
Errors:
- Missing fields → 400.
- Bad URL → 400 with `error: 'Invalid YouTube URL'`.
- Playlist URL → 400 with `error: 'Playlists aren't supported yet'`.
- Project not found → 404.
- DB / queue failure → 500 (next(err)).
### Jobs screen integration
`services/web-ui/public/screens-jobs.jsx` already normalizes job types via a `kindMap`. Add one entry:
```js
const kindMap = { proxy: 'Proxy', thumbnail: 'Thumbnail', conform: 'Conform', transcode: 'Transcode', youtube_import: 'YouTube' };
```
Retry, delete, and the SSE event stream all work for the new type with no further changes because they key off `job.id`, not `job.type`.
## 3. Worker
### Container changes
`services/worker/Dockerfile` gains two packages:
```dockerfile
RUN apk add --no-cache ffmpeg yt-dlp python3
```
`yt-dlp` is in the Alpine `community` repo and pulls `python3` as a runtime dep — we list it explicitly for clarity. Image grows by ~25 MB.
### New worker
`services/worker/src/workers/youtube-import.js`, registered in `services/worker/src/index.js`:
```js
const workers = [
createWorker('proxy', proxyWorker),
createWorker('thumbnail', thumbnailWorker),
createWorker('conform', conformWorker),
createWorker('import', youtubeImportWorker),
];
```
### Job handler
For a job with `{ assetId, url }`:
1. `job.updateProgress(2)` — accepted.
2. Build a temp directory `tmpdir()/yt-${jobId}`.
3. Run yt-dlp:
```sh
yt-dlp \
--no-playlist \
--no-warnings \
--restrict-filenames \
-f "bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4]/b" \
--merge-output-format mp4 \
--print-json \
--newline \
-o "<tmpdir>/<assetId>.%(ext)s" \
"<url>"
```
- `--print-json` writes one JSON line at the end with title, duration, width, height, uploader, etc.
- `--newline` makes progress lines newline-terminated so we can parse them.
- `--restrict-filenames` prevents shell-special characters in temp paths.
4. Stream stdout line-by-line. Lines matching `r'\[download\]\s+(\d+(\.\d+)?)%'` map to `job.updateProgress(5 + Math.floor(pct * 0.55))` so download takes us from 5 to 60 %.
5. On yt-dlp non-zero exit: parse stderr for the first line containing `ERROR:` and use it as the job's error message. Mark the asset `status='error'`, mark the job failed, throw so BullMQ records it. Surface a friendly substitution for the common cases:
- "Private video" → "Private video — not supported."
- "Sign in to confirm your age" → "Age-restricted video — not supported."
- "Video unavailable" → "Video unavailable or removed."
- "This video is not available in your country" → "Video is geo-blocked from this region."
- HTTP 429 → "YouTube rate-limited the importer — try again later."
- Anything else → use yt-dlp's stderr line verbatim, truncated to 300 chars.
6. Parse the last stdout line as JSON to read metadata. The resulting file is `<tmpdir>/<assetId>.mp4`.
7. `getMediaInfo` (existing helper in `services/worker/src/ffmpeg/executor.js`) on that path. Use ffprobe's values for codec/fps/duration when yt-dlp's are missing or wrong.
8. Sanitize the title for the S3 filename: keep `[A-Za-z0-9 ._-]`, collapse runs of whitespace, trim, cap at 120 chars, append `.mp4`. If the sanitized title is empty, fall back to `youtube-<videoId>.mp4`.
9. Upload to `originals/{assetId}/{sanitized-title}.mp4` via the existing `uploadToS3` helper. Progress 60 → 90 %.
10. UPDATE the assets row with:
- `filename = <sanitized title>.mp4`
- `display_name = <yt-dlp title untouched>`
- `original_s3_key = originals/<assetId>/<sanitized-title>.mp4`
- `codec`, `resolution`, `fps`, `duration_ms`, `file_size` from ffprobe.
- `status = 'processing'`
- `updated_at = NOW()`
11. Enqueue a `proxy` job on the existing `proxy` queue with the same payload shape `upload.js` uses:
```js
await proxyQueue.add('generate', {
assetId,
inputKey: asset.original_s3_key,
outputKey: `proxies/${assetId}.mp4`,
});
```
12. `job.updateProgress(100)`. Return — BullMQ marks the import job done. The proxy job picks up the rest exactly like a regular upload.
13. Always `rm -rf` the temp directory in a `finally`.
### Concurrency & retries
- Default BullMQ concurrency for this queue: **1** per worker process. Two simultaneous yt-dlp invocations risk YouTube rate-limiting more than they help throughput. Configurable later via env if needed.
- No automatic BullMQ retry — yt-dlp failures are almost always permanent (private, geo, removed) and a silent retry storm would chew through quota. The Jobs screen's manual Retry button is the right knob for "this should be transient" cases.
## 4. Schema migration
New file `services/mam-api/src/db/migrations/011-youtube-import.sql`:
```sql
-- 1. Add the new job type to the enum.
-- Postgres requires ALTER TYPE ... ADD VALUE for enum changes.
ALTER TYPE job_type ADD VALUE IF NOT EXISTS 'youtube_import';
-- 2. Remember where an asset came from. NULL for everything that
-- pre-dates the importer; populated for any imported asset.
ALTER TABLE assets ADD COLUMN IF NOT EXISTS source_url TEXT;
```
`source_url` is exposed on the asset drawer as a "Source" line ("imported from youtu.be/…") in a follow-up PR — out of scope for this spec, but worth noting that the column exists for it.
## 5. Files touched
**New**
- `services/mam-api/src/routes/imports.js`
- `services/mam-api/src/db/migrations/011-youtube-import.sql`
- `services/worker/src/workers/youtube-import.js`
**Edited**
- `services/mam-api/src/index.js` — mount the new route.
- `services/web-ui/public/screens-ingest.jsx` — add `YouTubeImport`, export on `window`.
- `services/web-ui/public/shell.jsx` — add the nav child, extend `ingestChildren`.
- `services/web-ui/public/app.jsx` — register the route and the crumb.
- `services/web-ui/public/screens-jobs.jsx` — extend `kindMap` with `youtube_import: 'YouTube'`.
- `services/worker/src/index.js` — register the `import` queue worker.
- `services/worker/Dockerfile` — add `yt-dlp` and `python3` to the apk install line.
## 6. Risks & trade-offs
- **Worker egress**. The worker container needs outbound HTTPS to YouTube. Fine in the current homelab; will fail in a locked-down cluster. Documented in the implementation plan.
- **yt-dlp drift**. YouTube changes break old yt-dlp versions every few weeks. The Alpine package lags upstream by days. Fix is to rebuild the worker image. We do not auto-update inside the running container — too risky for an offline / locked-down deploy. If imports start failing en masse, the runbook is `docker compose build worker && docker compose up -d worker`.
- **Single-URL UX feels light**. That is deliberate for v1. Adding multi-URL paste and playlist expansion are both small follow-ups once the single-URL path is stable.
- **No copyright enforcement**. We rely on the one-line notice in the UI. If misuse becomes a real concern, the next step would be an admin allowlist of domains or a per-user import quota — not in this spec.
- **`filename = url` placeholder**. Briefly, the asset row in the Library shows the URL as the name. The worker overwrites it within seconds for a successful import. Acceptable; the Library already handles "ingesting" assets with placeholder names from the upload path.
## 7. Acceptance
The feature is done when:
- A user can navigate to **Ingest → YouTube**, paste a public YouTube URL, pick a project, click Import, and within a minute or two see the asset appear in the Library with proxy and thumbnail.
- A failed import (private video, removed video, bogus URL) shows a clear error message on both the YouTube screen's queue row and the Jobs screen.
- The Jobs screen lists "YouTube" jobs alongside Proxy / Thumbnail / Conform, with Retry working.
- `source_url` is populated on the imported asset row.
- Image rebuild + `docker compose up -d worker` is the documented recovery path if YouTube changes break yt-dlp.

View file

@ -1,269 +0,0 @@
# Dragonflight User Authentication — Design
**Status:** Approved, ready for implementation planning
**Date:** 2026-05-27
**Brainstormed with:** Zac
## Problem
Dragonflight has the skeleton of an auth system spread across the codebase:
- `users` table (`id`, `username`, `password_hash`, `display_name`, `role`)
- `sessions` table (`sid`, `sess`, `expire`) for `connect-pg-simple`
- `groups`, `user_groups`, `api_tokens` tables
- `SESSION_SECRET` env var
- `AUTH_ENABLED` env flag with boot-log toggle
- PR #26 frontend handler that bounces to `/login.html` on 401
- Issue #94 "session security fixes" deployed 2026-05-26 (commit `3ebe5d6`)
But the actual `express-session` middleware was never mounted in `services/mam-api/src/index.js`. There is no `/api/v1/auth/*` router. There is no `requireAuth` middleware. As a result, when `AUTH_ENABLED=true` was tried:
1. User submits login, server returns 200 OK from a stub endpoint.
2. No `Set-Cookie` is ever sent (no session middleware mounted).
3. The next request to a protected route returns 401.
4. Frontend bounces to `/login.html`.
5. **Infinite redirect loop.**
The prior attempts failed because auth was being built reactively in pieces, with no single source of truth for what "logged in" means.
## Goals
- One coherent, readable auth code path.
- Web UI logins survive page reloads and container restarts.
- Premiere panel can authenticate via long-lived bearer tokens.
- First-run setup works on a fresh install with no env var or CLI gymnastics.
- The whole auth flow can be exercised by automated tests, including a regression test for the redirect-loop failure mode.
## Non-goals (v1)
- MFA / TOTP.
- OAuth / OIDC delegation (Forgejo, Google, etc.).
- Per-project or per-recorder permissions. Flat access: logged in = full access.
- Email-based "forgot password" (no SMTP assumed; admin-reset only).
- Audit log of who-did-what (the `last_login_at` column is the minimum).
- Service-to-service auth for `node-agent` — keeps existing `019-node-token-binding` mechanism.
## Decisions
| Decision | Choice | Reasoning |
|---|---|---|
| Client surface | Web UI + Premiere panel | Two transports (cookies + bearer), one identity backend |
| Permission model | Flat (logged in = full access) | Small homogeneous operator population. `groups` / `user_groups` schemas stay inert. |
| Identity provider | Local username/password | On-prem broadcast operators won't tolerate OIDC roundtrips. Matches existing schema. |
| First-user bootstrap | First-run setup page | Hardest to mis-configure. No env vars to leak. No CLI to remember. |
| Session lifetime | 8h absolute + 1h sliding idle | Operator security posture, tighter than typical SaaS. |
| Auth library | Hand-rolled (`express-session` + `connect-pg-simple`) | Explicit, debuggable. Rejected JWT and Passport for this codebase. |
## Architecture
### Single source of truth
"Logged in" means exactly one of two things:
1. The request carries a valid `dragonflight.sid` cookie whose row in `sessions` hasn't expired and isn't past its 1h-idle or 8h-absolute window, OR
2. The request carries `Authorization: Bearer <token>` whose SHA-256 matches an `api_tokens` row that hasn't been revoked or expired.
Nothing else counts. No `localStorage` flags, no JWT, no client-side "I think I'm logged in" hints.
### One middleware, one check
`services/mam-api/src/middleware/auth.js` exposes a single `requireAuth` function:
```js
export async function requireAuth(req, res, next) {
// Dev mode preserved. The 'dev' user is a real row in `users` seeded at
// boot when AUTH_ENABLED !== 'true', so FK-bearing routes (api_tokens,
// future comments, audit fields) keep working without conditional logic.
if (process.env.AUTH_ENABLED !== 'true') {
req.user = DEV_USER; // { id: <UUID of seeded 'dev' user>, username: 'dev' }
return next();
}
// 1. Session check
if (req.session?.user_id) {
const now = Date.now();
if (now - req.session.first_seen_at > 8 * 3600 * 1000) return destroyAnd401(req, res);
if (now - req.session.last_seen_at > 1 * 3600 * 1000) return destroyAnd401(req, res);
req.session.last_seen_at = now;
req.user = await loadUser(req.session.user_id);
if (!req.user) return destroyAnd401(req, res);
return next();
}
// 2. Bearer check
const bearer = parseBearer(req.headers.authorization);
if (bearer) {
const hash = sha256hex(bearer);
const row = await pool.query(
`SELECT t.id, t.user_id, t.expires_at, u.username
FROM api_tokens t JOIN users u ON u.id = t.user_id
WHERE t.token_hash = $1`, [hash]);
if (row.rows.length && (!row.rows[0].expires_at || row.rows[0].expires_at > new Date())) {
pool.query(`UPDATE api_tokens SET last_used_at = NOW() WHERE id = $1`, [row.rows[0].id]).catch(() => {});
req.user = { id: row.rows[0].user_id, username: row.rows[0].username };
return next();
}
}
// 3. Otherwise
return res.status(401).json({ error: 'unauthorized' });
}
```
Mounted at the `/api/v1` level in `services/mam-api/src/index.js`, **before** the individual route mounts, with an allowlist for the three pre-login auth paths:
```js
app.use('/api/v1', (req, res, next) => {
const unauth = ['/auth/login', '/auth/setup', '/auth/setup-required'];
if (unauth.some(p => req.path === p)) return next();
return requireAuth(req, res, next);
});
// then: app.use('/api/v1/assets', assetsRouter), etc.
```
`/health` lives at the root, outside the `/api/v1` mount, so it's naturally unaffected. `/api/v1/cluster/*` keeps its existing `019-node-token-binding` service-auth path: requireAuth runs first, fails with 401 for an unauthenticated request, **but** the cluster routes themselves do their own token check on request bodies, so node-agent traffic must include a valid user session OR an api_token (which is the change — node-agent will need to be issued an api_token at install time). Alternative: carve `/api/v1/cluster/*` out of the requireAuth gate too, and keep node-agent on its existing binding token alone. Implementer should pick — flagged in the implementation order.
### Session middleware (actually wired this time)
In `services/mam-api/src/index.js`, **before any route**:
```js
import session from 'express-session';
import connectPgSimple from 'connect-pg-simple';
const PgStore = connectPgSimple(session);
if (process.env.TRUST_PROXY === 'true') app.set('trust proxy', 1);
app.use(session({
store: new PgStore({ pool, tableName: 'sessions', pruneSessionInterval: 60 * 15 }),
secret: process.env.SESSION_SECRET,
name: 'dragonflight.sid',
cookie: {
httpOnly: true,
sameSite: 'lax',
secure: process.env.TRUST_PROXY === 'true',
path: '/',
maxAge: 8 * 3600 * 1000,
},
rolling: false, // sliding renewal handled in requireAuth so we can enforce idle + absolute separately
resave: false,
saveUninitialized: false,
}));
```
### Auth router
`services/mam-api/src/routes/auth.js`:
| Method | Path | Auth | Description |
|---|---|---|---|
| `GET` | `/api/v1/auth/setup-required` | none | `{ required: bool }`. Cheap, no auth. |
| `POST` | `/api/v1/auth/setup` | none | Only succeeds if `users` is empty. Creates first user, logs them in. |
| `POST` | `/api/v1/auth/login` | none | `{ username, password }` -> 200 + cookie or 401 |
| `POST` | `/api/v1/auth/logout` | required | Destroys session row, clears cookie |
| `GET` | `/api/v1/auth/me` | required | `{ id, username, display_name }` |
| `POST` | `/api/v1/auth/password` | required | Change own password (requires current) |
| `GET/POST/DELETE` | `/api/v1/auth/users[/:id]` | required | User CRUD |
| `GET/POST/DELETE` | `/api/v1/auth/tokens[/:id]` | required | Current user's API tokens |
### Data model
Existing schema is almost right. One small migration:
```sql
-- services/mam-api/src/db/migrations/023-auth-session-timestamps.sql
ALTER TABLE users ADD COLUMN IF NOT EXISTS password_updated_at TIMESTAMPTZ DEFAULT NOW();
ALTER TABLE users ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMPTZ;
-- idle / absolute timestamps live inside session.sess JSONB; no schema change needed
```
`groups` and `user_groups` stay as-is, unused for v1. `api_tokens` is already correctly shaped.
## Flows
### Browser login (the one that broke last time)
1. SPA boots, `<AuthGate>` calls `GET /api/v1/auth/me`.
2. `requireAuth` returns 401.
3. AuthGate calls `GET /api/v1/auth/setup-required`. If `true`, render Setup screen. Otherwise, render Login screen.
4. User submits `POST /api/v1/auth/login`. Server `bcrypt.compare`s, sets `req.session.user_id`, `first_seen_at`, `last_seen_at`. **Critical:** `await new Promise(r => req.session.save(r))` before responding, so the cookie is persisted to Postgres before the next request can arrive.
5. AuthGate re-calls `/api/v1/auth/me`, gets 200, renders the app.
**Why this doesn't loop:** the explicit `req.session.save()` callback before response guarantees the cookie row exists before the SPA can fire its next request. `requireAuth` returns a clean 401 (not a redirect) so the SPA decides what to render. The static `/login.html` is deleted; there is no HTML bounce.
### Premiere panel bearer
1. Web UI -> Settings -> API Tokens -> "New token" named "Premiere panel".
2. `POST /api/v1/auth/tokens` returns `{ token: 'dfl_<32 hex>', prefix: 'dfl_a3f2', id }` **exactly once**.
3. Premiere panel sends `Authorization: Bearer dfl_<...>` on every request. `requireAuth` SHA-256s it, looks up `api_tokens.token_hash`, updates `last_used_at`.
### Idle + absolute timeout (inside `requireAuth`)
```
if session present:
if now - session.first_seen_at > 8h -> destroy session, 401
if now - session.last_seen_at > 1h -> destroy session, 401
session.last_seen_at = now
req.user = lookup(session.user_id)
next()
```
Bearer tokens have their own optional `expires_at` (`NULL` = never expires); checked the same way.
## Frontend
- **`services/web-ui/src/auth-gate.jsx`** — new component that wraps the SPA. On mount: `GET /me`. On 401: check `setup-required`, render either Setup or Login. On 200: render the app shell.
- **Login screen** — layout B from brainstorm: 22px wordmark over "WILD DRAGON BROADCAST" tagline above a `--bg-1` card containing username, password, "Sign in" button. Matches DESIGN.md tokens.
- **Setup screen** — same chrome; fields = username, password, confirm password; button = "Create admin".
- **Settings -> Account section** — change password.
- **Settings -> API Tokens section** — list / create / revoke. New token shown exactly once with a copy affordance.
- **Fetch wrapper** — the central `ZAMPP_API.fetch` (already exists) gains a 401 handler that re-mounts AuthGate's Login state with the current path saved as `last_path`, restored after re-auth.
### Removed
- The static `/login.html` page (PR #26's bounce target) is deleted. SPA handles login internally; no full-page reload.
## Error handling
| Case | Behavior |
|---|---|
| Wrong username or password | `401 { error: 'invalid credentials' }`. Same message either way, no user enumeration. |
| Login rate limiting | Per-IP exponential backoff (1s, 2s, 4s, 8s, max 30s). In-memory `Map`. Single-instance limitation documented. |
| Idle / absolute expiry | 401 -> AuthGate Login. Last path saved, restored on re-auth. |
| Setup after first user exists | `409 { error: 'setup already complete' }`. Permanently disabled. |
| Token revoke | `DELETE /api/v1/auth/tokens/:id` — only owner can revoke. Subsequent bearer requests 401. |
| Delete-self when only user | `409 { error: 'cannot delete last user' }`. |
| Forgot password | No self-serve. Any logged-in user can reset another via `POST /api/v1/auth/users/:id/password`. Documented as the recovery path. |
| Password rules | Min 12 chars, no max, no character class requirements (NIST SP 800-63B). `bcrypt` cost 12. |
| CSRF | `SameSite=Lax` + same origin + required `X-Requested-With: dragonflight-ui` header on mutating requests (belt-and-suspenders). |
| Session table growth | `connect-pg-simple` `pruneSessionInterval: 60 * 15` (every 15 min). |
## Testing
- **Unit — `services/mam-api/test/middleware/auth.test.js`**: requireAuth with (a) no creds, (b) valid session, (c) idle-expired session, (d) absolute-expired session, (e) valid bearer, (f) invalid bearer, (g) bearer matching a deleted user.
- **Integration — `services/mam-api/test/auth.integration.test.js`**: spin up Express + test Postgres. Walks: setup -> login -> /me -> mutating call -> logout -> /me 401. Second pass: idle timeout simulated by mutating `last_seen_at` in DB. Third pass: bearer issue -> use -> revoke -> 401.
- **Regression test for the redirect-loop bug:** explicit test that after `POST /auth/login` returns 200, a subsequent `GET /auth/me` with the returned cookie returns 200 in the same test client. This is the test that would have caught the original failure.
- **Manual smoke (documented in PR):** fresh install -> setup -> create admin -> land on dashboard -> reload (stays logged in) -> wait 1h idle -> reload -> bounce to login.
## Implementation order
Suggested sequencing for the implementation plan (writing-plans will refine):
1. Migration `023-auth-session-timestamps.sql`. Add idempotent seed of the dev user (`INSERT ... ON CONFLICT DO NOTHING` with a fixed UUID) so dev mode FK-bearing routes work out of the box.
2. `express-session` + `connect-pg-simple` wiring in `index.js`.
3. `requireAuth` middleware (with `DEV_USER` constant resolved from the seeded row).
4. Auth router (setup, login, logout, me, password).
5. Apply `requireAuth` to API router with allowlist. Decide cluster carve-out (see Architecture).
6. Auth tests (unit + integration + regression).
7. Frontend `<AuthGate>` + Login screen + Setup screen.
8. Frontend Settings -> Account + API Tokens.
9. Delete `/login.html`.
10. User CRUD + token CRUD routes.
11. Rate limiting + CSRF header.
12. Documentation: README updates, `AUTH_ENABLED` transition notes.
## Out-of-band notes for the implementer
- The current `cors({ origin: true, credentials: true })` in `index.js` is too permissive once cookies start carrying authority. Tighten to a specific origin list (driven by an `ALLOWED_ORIGINS` env var) at the same time as wiring the session middleware — otherwise we're undoing the `SameSite=Lax` protection from the other side.
- node-agent -> mam-api traffic on `/api/v1/cluster/*` must keep working. Add a route-level carve-out comment that this path uses the existing `019-node-token-binding` token, not the user-auth path.
- The boot log currently says `Authentication: ENABLED` / `DISABLED (set AUTH_ENABLED=true for production)`. Once this lands, the recommended default flips: `AUTH_ENABLED=true` becomes the documented default in `.env.example` and the README, and `AUTH_ENABLED=false` is documented as a dev-only escape hatch.

View file

@ -1,84 +0,0 @@
# HLS VOD Playback for Browser
Date: 2026-05-29 | Status: design → implementation
Authors: Zac + Claude
## Purpose
Replace the browser playback path for **recorded (VOD) assets** with HLS, retiring
the MP4 range-stitching workaround. The MP4 proxy is **kept** (supplements, not
replaces) because the Premiere UXP panel and conform pipeline consume it.
## Background — current state
- `GET /assets/:id/stream` returns `{ url: /api/v1/assets/:id/video, type: 'mp4' }`
for ready assets.
- `GET /assets/:id/video` streams `proxies/<id>.mp4` through Node with the
**RustFS range-stitching hack** (`stitchedS3Stream`): RustFS mis-serves ranged
GETs whose start offset is past ~5.8 MB, so the endpoint streams from byte 0 and
drops bytes. Works, but wastes bandwidth/CPU per seek and is fragile.
- **Live** assets already use HLS (`type: 'hls'`, `/live/<id>/index.m3u8`), and
`hls.js` is already loaded and wired in `screens-asset.jsx` for `type === 'hls'`.
- The proxy worker (`services/worker/src/workers/proxy.js`) produces a single
H.264/AAC/yuv420p MP4 — already HLS-compatible.
## Decisions
- **Supplement, not replace.** Keep `proxies/<id>.mp4`; add an HLS rendition.
- **Generate in the proxy worker** via fast remux (`-c copy`) — no re-encode.
- **Serve segments through mam-api** as whole-file GETs (no Range) — sidesteps the
RustFS range bug entirely and reuses session auth.
## Architecture
### 1. Generation (worker/proxy.js)
After uploading `proxies/<id>.mp4`, remux it to HLS into a temp dir:
```
ffmpeg -i <proxy.mp4> -c copy -f hls \
-hls_time 6 -hls_playlist_type vod -hls_flags independent_segments \
-hls_segment_filename <tmp>/seg_%03d.ts <tmp>/index.m3u8
```
Upload every file in the temp dir to `hls/<assetId>/` (playlist + `.ts`). Set
`assets.hls_s3_key = 'hls/<assetId>/index.m3u8'`. Remux is seconds; failure is
non-fatal (MP4 path still works as fallback).
### 2. Storage / schema
Migration adds `assets.hls_s3_key TEXT` (nullable). Presence = HLS available.
Segment objects live under `hls/<assetId>/seg_NNN.ts`; playlist references
**relative** segment names so the serving endpoint is path-agnostic.
### 3. Serving (mam-api)
New `GET /assets/:id/hls/:file` (file = `index.m3u8` or `seg_NNN.ts`):
- Validate `:file` against `^(index\.m3u8|seg_\d+\.ts)$` (no traversal).
- Whole-object GET of `hls/<id>/<file>` from S3 — **no Range handling**.
- Content-Type: `application/vnd.apple.mpegurl` (m3u8) / `video/mp2t` (ts).
- `Cache-Control: private, max-age=3600` for segments; `no-cache` for the playlist.
- Covered by the existing `requireAuth` gate; `hls.js` carries the same-origin
session cookie (same mechanism the live HLS path already relies on).
### 4. Stream selection (mam-api `/stream`)
For non-live assets: if `hls_s3_key` is set →
`{ url: '/api/v1/assets/:id/hls/index.m3u8', type: 'hls' }`. Else fall back to the
existing MP4 `/video` response. Live unchanged.
### 5. Backfill (existing assets)
Add an `hls` BullMQ job + `POST /assets/:id/reprocess?type=hls`: downloads the
existing `proxy_s3_key`, remuxes to HLS, uploads, sets `hls_s3_key`. No re-encode.
### 6. Frontend
No change required — `screens-asset.jsx` already plays `type: 'hls'` via `hls.js`.
Verify `hls.js` xhr carries credentials (same-origin cookie) for the proxied
segments; add `xhrSetup` withCredentials only if needed.
## Out of scope
- Multi-bitrate/ABR ladders (single rendition for now).
- Replacing the MP4 proxy or the `/video` endpoint (kept as fallback + for panel).
- Live-asset playback changes (already HLS).
## Test plan
1. Upload/capture an asset → proxy job produces MP4 **and** `hls/<id>/index.m3u8`.
2. `/stream` returns `type: 'hls'`; `/assets/:id/hls/index.m3u8` → 200 m3u8;
`/assets/:id/hls/seg_000.ts` → 200 `video/mp2t`, whole-file (no 206/Range).
3. Browser: asset plays + seeks via hls.js (no range-stitching path hit).
4. `reprocess?type=hls` backfills an older asset; it then plays via HLS.
5. MP4 proxy + `/hires` download still work (panel workflow intact).

View file

@ -1,235 +0,0 @@
# Wild Dragon MAM — Playout / Master Control (MCR)
**Date:** 2026-05-30 (revised 2026-05-30 — §7 closed)
**Status:** APPROVED — implementation in progress (code drafted but uncommitted; see WORK_LOG_PLAYOUT.md)
**Author:** Zac + Claude
---
## Resolved Decisions
| Question | Decision |
|----------|----------|
| Playout engine | **CasparCG Server** (orchestrated via AMCP), not ffmpeg-native |
| Channel count | **Multi-channel from start** — N independent channels, placed across cluster nodes by capability (mirrors recorders) |
| Scheduling model | **Phased** — Phase A: on-demand playlist player; Phase B: 24/7 continuous channel |
| Output targets | SDI (DeckLink), NDI, SRT, RTMP — all via CasparCG consumers |
| Media source | Assets live in **S3**; must be staged to a CasparCG-local media volume before play (see §4) |
| CasparCG packaging | **Build our own image** (like `capture/build-with-decklink.sh`) — GL context via GPU passthrough or Xvfb; NDI + DeckLink SDKs fetched at build time (not redistributable) |
| Master codec playability | Zac confirms current masters **play fine in CasparCG** — no transcode-for-playout step; staging is a plain S3→/media copy. Validate on hardware but do not gate on it |
| Management UI | **Single Dragonflight `playout.html` GUI** drives everything via AMCP; operator never touches CasparCG directly |
---
## Overview
Playout adds **master-control-room** capability to Dragonflight: take library assets, arrange them on a timeline / playlist, and play them out continuously to a broadcast output — SDI via DeckLink, or stream via SRT / RTMP / NDI. Drag-and-drop scheduling, a program/preview monitor, and as-run logging.
This is the **mirror image** of the existing capture path. Capture is `input → ffmpeg encode → S3`. Playout is `S3 asset → engine → output`. We reuse three things wholesale:
1. **Cluster node + capability model** — nodes already advertise DeckLink/Deltacast/GPU in `cluster_nodes.capabilities`; channels are placed on nodes that have a free output port, exactly as recorders claim input ports.
2. **Sidecar orchestration** — mam-api spawns containers via the local Docker socket or the remote `node-agent /sidecar/start`. A CasparCG channel is just a different sidecar image.
3. **Scheduler tick + PG advisory lock**`src/scheduler.js` already runs a single-leader tick over a schedule table. Phase B's wall-clock channel reuses this pattern.
### Why CasparCG over ffmpeg-native
The capture stack proves we can drive ffmpeg + DeckLink. But playout's hard part is **gapless, frame-accurate, clean transitions between clips** — every clip boundary in an ffmpeg-per-clip model is a black flash unless we engineer a concat-feeder. CasparCG solves this natively: a channel is a persistent output with a playlist, hard/mix/wipe transitions, layered graphics/logo (CG), and DeckLink/NDI/SRT/RTMP consumers built in. We orchestrate it over **AMCP** (its TCP control protocol) instead of reinventing a feeder. Trade: a new dependency + container image, and media must be on a CasparCG-visible disk (§4).
---
## 1. Data Model
New migration `029-playout.sql`. Five tables.
### 1.1 `playout_channels`
A logical output. One channel → one engine instance → one output target.
```
id uuid pk
name text -- "Channel 1", "Pop-up SDI"
node_id uuid -> cluster_nodes(id) -- where the engine runs (null = primary)
output_type text -- 'decklink' | 'ndi' | 'srt' | 'rtmp'
output_config jsonb -- { device_index } | { ndi_name } | { url, latency } | { url, key }
video_format text -- '1080i5994' | '1080p5994' | '720p5994' ...
status text -- 'stopped' | 'starting' | 'running' | 'error'
container_id text -- running CasparCG sidecar
project_id uuid -> projects(id) -- RBAC scoping (nullable = admin-only)
created_at / updated_at
```
`output_type` + `output_config` map straight to a CasparCG consumer:
- `decklink``ADD <ch> DECKLINK <device> ...`
- `ndi``ADD <ch> NDI ...`
- `srt`/`rtmp` → `ADD <ch> FFMPEG <url> -f mpegts ...` (CasparCG 2.3+ ffmpeg consumer)
### 1.2 `playout_playlists`
An ordered list of items bound to a channel. Phase A's primary object.
```
id, channel_id -> playout_channels(id)
name, loop boolean, created_at / updated_at
```
### 1.3 `playout_items`
One entry on a playlist OR one entry on the 24/7 timeline.
```
id
playlist_id uuid -> playout_playlists(id) -- Phase A
asset_id uuid -> assets(id)
sort_order int -- position in playlist (Phase A)
scheduled_at timestamptz -- wall-clock start (Phase B, null in A)
in_point numeric -- seconds, trim head (reuse subclip in/out from editor)
out_point numeric -- seconds, trim tail
transition text -- 'cut' | 'mix' | 'wipe'
transition_ms int
graphics jsonb -- optional CG/template overlay (Phase B+)
media_status text -- 'pending' | 'staging' | 'ready' | 'error' (see §4)
media_path text -- resolved path inside the CasparCG media volume
```
### 1.4 `playout_schedule` (Phase B)
Day-ahead, wall-clock-bound timeline rows. Same shape as `playout_items` but `scheduled_at` is authoritative and the scheduler tick (§5) drives transitions. Phase A can ignore this table.
### 1.5 `playout_as_run`
Append-only log: what actually played, when, for how long. Compliance / billing.
```
id, channel_id, asset_id, item_id
started_at, ended_at, duration_s, result -- 'played' | 'skipped' | 'error'
```
---
## 2. Services & Components
### 2.1 New sidecar: `services/playout/` (CasparCG wrapper)
A thin container: **CasparCG Server** + a small Node control shim exposing HTTP, the same way `capture` wraps ffmpeg.
- Base image: official/community `casparcg/server` (Linux build with DeckLink + NDI + FFmpeg producers/consumers).
- Node shim (`src/index.js`): opens an AMCP TCP socket to local CasparCG, exposes:
- `POST /channel/start``ADD <ch> <consumer>` for the channel's output target
- `POST /play``PLAY <ch>-<layer> <media> [transition]`
- `POST /loadbg` + `/play` → preview/cue then take (preview monitor)
- `POST /stop`, `GET /status``INFO <ch>` (current clip, position, fps)
- playlist load → translate `playout_items` rows into a sequence of AMCP `LOADBG`/`PLAY` calls, advancing on `OnTransition` / end-of-clip events.
- Mirrors capture's status-polling contract so the UI monitor reuses existing plumbing.
### 2.2 mam-api: `src/routes/playout.js`
CRUD + control, RBAC-scoped via the existing `assertProjectAccess` helper (channels carry `project_id`).
```
GET /playout/channels list (project-filtered)
POST /playout/channels create (edit on project)
POST /playout/channels/:id/start|stop spawn/kill CasparCG sidecar
GET /playout/channels/:id/status proxy engine INFO
POST /playout/channels/:id/play|pause|skip transport control
GET/POST/PUT/DELETE /playout/playlists... playlist + item CRUD, reorder
POST /playout/items/:id/stage kick S3→media-volume staging (§4)
GET /playout/channels/:id/asrun as-run log
```
Channel start/stop reuses `resolveNodeTarget()` + the Docker-socket / `node-agent /sidecar/start` split already in `recorders.js`. **Refactor opportunity:** lift that sidecar-spawn logic out of `recorders.js` into `src/orchestration/sidecar.js` so both recorders and playout share it (keep this small — only what both need).
### 2.3 web-ui: `playout.html` + `public/playout.jsx`
New MCR page. Layout:
```
┌─ PREVIEW ───────────┬─ PROGRAM (on air) ──────┐
│ [cued clip] │ [live output] ● ON AIR │
│ TC / duration │ TC / remaining │
│ [CUE] [TAKE] │ [PLAY][PAUSE][SKIP][STOP]│
├─ MEDIA BIN ─────────┴──────────────────────────┤
│ (draggable asset list, reuse asset browser) │
├─ PLAYLIST / TIMELINE ──────────────────────────┤
│ ▸ clip A ──▸ clip B ──▸ clip C (drag-drop) │ Phase A: ordered list
│ └ 24h time grid w/ now-bar │ Phase B: time-of-day grid
└────────────────────────────────────────────────┘
```
- Drag-drop: reuse whatever the NLE editor timeline uses (check `editor.jsx`); assets drag from the bin into the playlist/grid.
- API via existing `ZAMPP_API.fetch` wrapper.
- Program monitor: HLS preview of the output — CasparCG can emit a second low-bitrate FFmpeg consumer to HLS, reusing the `/live/<id>` HLS plumbing capture already uses.
---
## 3. Channel placement & ports
A DeckLink port is exclusive — same constraint capture already handles. A node's DeckLink port can be an **input (recorder)** or an **output (playout channel)**, never both at once. So:
- Extend the capability/port-claim check: when starting a channel on `output_type=decklink`, verify the target node has that device index free (no active recorder, no active channel).
- NDI / SRT / RTMP outputs have no hardware contention → can stack many per node (GPU/CPU-bound only).
- Surface a unified "device map" (extend the existing cluster DeckLink-status endpoint) showing each port's role: idle / recording / playing-out.
---
## 4. Media staging (the S3 ⇄ CasparCG gap)
**The crux.** Assets live in S3 (`original_s3_key` / `proxy_s3_key`). CasparCG plays from a **local media folder**. Options:
- **A — Pre-stage to a shared media volume (recommended).** Before a clip can go on air, download/symlink it from S3 to a CasparCG-visible volume (`/media`), set `playout_items.media_status='ready'` + `media_path`. A new BullMQ `playout-stage` job (reuses the worker pattern) does the pull. UI shows per-item readiness; TAKE is blocked until `ready`. Mirrors the growing-file SMB share already mounted for capture.
- **B — Stream from S3 via presigned URL.** CasparCG FFmpeg producer plays an HTTPS presigned URL directly. Zero staging, but seeking/trim and gapless transitions over network are fragile for broadcast. Acceptable as a fallback for SRT/RTMP, risky for SDI.
**Decision:** Phase A uses **A** (stage proxies for preview, masters for air) with **B** available as a per-channel "low-latency / no-stage" toggle. Zac confirms the current masters play fine in CasparCG, so staging is a **plain S3→/media copy — no transcode-for-playout step**. (Validate on hardware during implementation, but the model does not assume a transcode stage.)
---
## 5. Scheduling
### Phase A — playlist player
No wall clock. Operator builds a `playout_playlists` row, drags items in, hits PLAY. The playout sidecar walks `playout_items` by `sort_order`, cueing the next clip during the current one (`LOADBG`) and taking it at end-of-clip with the configured transition. `loop` repeats. As-run logged per item.
### Phase B — 24/7 continuous channel
Wall-clock timeline in `playout_schedule`. Reuse `src/scheduler.js`:
- Add a second tick (or extend the existing one) under the **same PG advisory lock pattern** — exactly-one-leader, so a multi-replica deploy doesn't double-fire.
- Tick responsibilities: stage upcoming items (look-ahead window), verify the on-air item matches the schedule, **fill gaps** (loop a filler/slate asset when the timeline has a hole — a channel must never go black), roll the day forward.
- As-run becomes the compliance record.
---
## 6. Phasing / Milestones
**Phase A — Playlist playout MVP**
1. Migration `029-playout.sql` (channels, playlists, items, as-run).
2. `services/playout/` sidecar: CasparCG image + AMCP control shim, single output target (start with **SRT or NDI** — no hardware needed for dev; DeckLink behind hardware check).
3. mam-api `routes/playout.js` — channel + playlist CRUD, start/stop, transport, RBAC.
4. `playout-stage` BullMQ job (S3 → /media).
5. web-ui `playout.html` — bin + drag-drop ordered playlist + program/preview monitors + transport.
6. DeckLink output on real hardware; port-contention check vs recorders.
**Phase B — 24/7 continuous channel**
7. `playout_schedule` + time-of-day grid UI.
8. Scheduler tick (advisory-locked) — look-ahead staging, gap-fill/slate, day-roll.
9. As-run reporting view.
10. Graphics/CG overlay (logo bug, lower-thirds) via CasparCG templates.
---
## 7. Open Questions (for review)
**Resolved (2026-05-30):**
- ~~CasparCG packaging~~**build our own image.** Fetch DeckLink + NDI SDKs at build time (not redistributable — same as capture's DeckLink build). GL context for the mixer comes from GPU passthrough on a real node, or **Xvfb** (virtual framebuffer) where there's no display — community images run `--privileged` + X11 socket. Pin the NDI SDK version to what the server expects (`.so` version mismatch is the common docker failure).
- ~~Master codec playability~~ → Zac confirms masters **play fine**; no transcode-for-playout. Staging = plain S3→/media copy.
- ~~Management GUI~~**single Dragonflight `playout.html`** drives everything via AMCP; operator never touches CasparCG.
- ~~Audio loudness~~**pre-normalize at stage time** (Zac, 2026-05-30). `playout-stage` job runs ffmpeg `loudnorm` (EBU R128, target 23 LUFS, true-peak 1 dBTP) once, on the S3→/media copy. Output is the cached version CasparCG plays. Staging is no longer a pure copy — staging cost ≈ realtime CPU per clip on first stage; results are reusable across channels. Override (`media_status='ready'` + raw copy) available for clips already mastered to spec.
- ~~Frame rate~~**`1080p5994`** default for new channels (Zac, 2026-05-30). Progressive 1080 @ 59.94 fps. Per-channel override allowed (`video_format` column). Streaming-friendly (SRT/RTMP/NDI) and current SDI gear accepts it; matches capture's 59.94 cadence.
- ~~Preview latency~~**HLS v1** (Zac, 2026-05-30). Reuse capture's `/live/<id>` HLS plumbing. CasparCG emits a second low-bitrate FFmpeg consumer to HLS. ~46s lag, fine for confidence monitor. Operator desk gets a real downstream monitor off the SDI/NDI output anyway. Revisit WebRTC if MCR operators complain.
- ~~Failover~~**auto-restart on healthy node** (Zac, 2026-05-30). Scheduler tick (§5) monitors `playout_sidecars` health (AMCP ping + container alive); on N missed checks marks the channel `error`, re-places it on another capability-matching node with a free output port, resumes the playlist from the next item after the as-run-logged on-air item. Gap = black/slate for ~530 s during respawn (operator sees a flag in the UI). **DeckLink channels are not auto-failed-over in v1** — device-index pinning makes the destination port non-trivial; v1 alerts and lets the operator move the channel. NDI/SRT/RTMP channels (no hardware contention) failover automatically. Tracked via `restart_count` + `last_restart_at` on `playout_channels`.
**Still open:**
- (none — all §7 questions resolved 2026-05-30)
---
## 8. Reused building blocks (already in the repo)
| Need | Existing piece |
|------|----------------|
| Spawn engine container local/remote | `recorders.js` Docker-socket + `node-agent /sidecar/start` |
| Node capability / port model | `cluster_nodes.capabilities`, cluster DeckLink-status endpoint |
| Single-leader scheduled transitions | `src/scheduler.js` + PG advisory lock |
| Background media jobs | BullMQ worker (`services/worker`) |
| RBAC scoping | `src/auth/authz.js` `assertProjectAccess` (channel/project_id) |
| HLS preview plumbing | capture's `/live/<id>` HLS output |
| Subclip in/out points | NLE editor in/out marking |
| API wrapper / SPA shell | `ZAMPP_API.fetch`, esbuild JSX pages |

View file

@ -1,148 +0,0 @@
# Storage Settings Warning + Growing-Files SMB Auth + Per-Recorder Growing Mode
**Date:** 2026-05-31
**Branch:** `feat/playout-mcr` (Forgejo: WildDragonLLC/dragonflight)
**Status:** Approved, ready for implementation plan
---
## Scope
Three related refinements to the Settings page and growing-files capture pipeline:
1. **Storage warning header** — a prominent set-once warning at the top of the Storage settings section.
2. **Growing-files SMB credentials + system CIFS mount** — store an SMB username/password and have the capture stack mount the growing share itself (Approach A).
3. **Per-recorder growing mode** — remove the global "capture writes to local SMB share first" toggle; make growing-files mode a per-recorder setting.
All changes live on the `growing-files` / storage-settings path. No playout changes (handled separately).
---
## Background (current state)
- **Settings storage:** single key/value `settings(key TEXT PRIMARY KEY, value TEXT, updated_at)` table (migration 006). Secrets like `s3_secret_key` are stored but `GET /settings/s3` returns only `s3_secret_key_exists` (never the value).
- **Growing settings UI:** `GrowingSettingsCard` in `services/web-ui/public/screens-admin.jsx` (rendered by `StorageSection` alongside `MountHealthStrip` and `S3SettingsCard`). Current keys: `growing_enabled`, `growing_path`, `growing_smb_url`, `growing_promote_after_seconds`.
- **Settings API:** `services/mam-api/src/routes/settings.js``GET/PUT /settings/growing` over `GROWING_KEYS`.
- **Global enable today:** the `growing_enabled` setting (checkbox labelled "Capture writes to the local SMB share first; Premier can edit while it's still growing"). `recorders.js` reads this global key at recorder-start and passes `GROWING_ENABLED=true/false` to the capture container.
- **Capture write path:** `services/capture/src/capture-manager.js` reads `process.env.GROWING_ENABLED` and `GROWING_PATH` (default `/growing`). When on, it writes the master to `/growing/{projectId}/{clipName}.{ext}` instead of streaming to S3; the promotion worker uploads to S3 after stop.
- **Current mount model:** `/growing` is a pre-mounted host bind-mount; the app never authenticates to SMB.
- **Per-recorder column already exists:** migration 014 added `recorders.growing_enabled BOOLEAN DEFAULT NULL` ("NULL = use global"), but recorder-start logic ignores it and the new-recorder modal does not expose it.
---
## Part 1 — Storage warning header
Add a danger-styled banner at the **top of `StorageSection()`**, above `MountHealthStrip`.
- Visual: full-width banner, danger token styling (`--danger` border + subtle danger background), alert icon, bold uppercase text.
- Exact copy:
> **⚠ WARNING — THESE SETTINGS ARE MEANT TO BE SET ONCE AT INITIAL DEPLOYMENT. CHANGING STORAGE PATHS MID-CYCLE CAN CAUSE DATABASE CORRUPTION AND FILE LOSS. PLEASE USE WITH CAUTION.**
- Pure presentational; no backend, no dismiss state (always visible).
**Files:** `services/web-ui/public/screens-admin.jsx` (and a small style rule in the appropriate CSS file if needed).
---
## Part 2 — Growing-files SMB credentials + system CIFS mount (Approach A)
The growing share is **shared infrastructure**, so the SMB connection config is global.
### New settings keys
| Key | Purpose | Notes |
|-----|---------|-------|
| `growing_smb_mount` | CIFS source for the system mount, e.g. `//10.0.0.25/mam-growing` | Distinct from `growing_smb_url` |
| `growing_smb_username` | SMB user | Returned in GET (not secret) |
| `growing_smb_password` | SMB password | **Write-only** — never returned |
| `growing_smb_vers` *(optional)* | CIFS protocol version, default `3.0` | Avoids mount negotiation failures |
`growing_smb_url` (the `smb://…` string) is retained unchanged as the **editor-facing** display value (Premiere connect string).
### Settings API (`settings.js`)
- Extend `GROWING_KEYS` with the new keys (except the password is handled specially).
- `GET /settings/growing`: return `growing_smb_mount`, `growing_smb_username`, `growing_smb_vers`, and `growing_smb_password_exists: boolean`**never** the password value. (Mirror the existing `s3_secret_key_exists` pattern.)
- `PUT /settings/growing`: upsert each provided key. For `growing_smb_password`, only write it when a non-empty value is provided (an empty/omitted field leaves the stored password unchanged). Provide a way to clear it (explicit empty sentinel or a "clear" affordance) — see Resolved decisions below.
### Settings UI (`GrowingSettingsCard`)
Add three fields to the card:
- **SMB mount (CIFS):** text input bound to `growing_smb_mount`, placeholder `//10.0.0.25/mam-growing`.
- **SMB username:** text input bound to `growing_smb_username`.
- **SMB password:** masked password input. Shows a "saved" indicator when `growing_smb_password_exists` is true; typing a new value replaces it; leaving it blank keeps the existing one. `autoComplete="new-password"`.
### Capture image (`services/capture/Dockerfile`)
Add `cifs-utils` to the installed packages so `mount -t cifs` is available inside the capture container.
### Capture-manager (`capture-manager.js`)
On capture start, when growing mode is active **and** `GROWING_SMB_MOUNT` is set:
1. Write a root-only credentials file (e.g. `/run/smb-creds`, mode `0600`) containing:
```
username=<GROWING_SMB_USERNAME>
password=<GROWING_SMB_PASSWORD>
```
(Credentials go in the file, **not** the mount command line, to avoid `ps`/log exposure.)
2. `mkdir -p $GROWING_PATH` then `mount -t cifs $GROWING_SMB_MOUNT $GROWING_PATH -o credentials=/run/smb-creds,uid=0,gid=0,file_mode=0664,dir_mode=0775,vers=$GROWING_SMB_VERS`.
3. If the mount succeeds → proceed writing the master to `$GROWING_PATH/...` (existing behaviour).
4. If the mount **fails** → log the error and fall back to S3 streaming (`growingPath = null`), so a recording is never lost.
5. On capture stop/cleanup, unmount `$GROWING_PATH` (best-effort; ignore "not mounted").
Mount isolation: each recorder runs in its **own** capture container, so each container mounts CIFS at its own private `/growing` — no cross-recorder mount conflicts, no ref-counting needed.
### Recorder start (`recorders.js`)
- Pass new env to the spawned capture container: `GROWING_SMB_MOUNT`, `GROWING_SMB_USERNAME`, `GROWING_SMB_PASSWORD`, `GROWING_SMB_VERS` (read from the `settings` table at start).
- The dynamically-spawned capture container must get `/growing` as an **empty mountpoint** (not a host bind-mount) so the in-container CIFS mount lands cleanly. Confirm/adjust the container spec accordingly. The container is already privileged (required for `mount`).
### Security notes
- The password is stored plaintext in the `settings` table, identical to the existing `s3_secret_key` handling — acceptable within this app's current secret model.
- The password reaches the capture container as an env var (visible via `docker inspect`), same as S3 keys already are. The credentials **file** (not the command line) is used for the actual mount.
---
## Part 3 — Per-recorder growing mode (remove the global toggle)
### Remove global enable
- Delete the global "Capture writes to the local SMB share first…" checkbox (`growing_enabled` key) from `GrowingSettingsCard`. The card no longer carries a global on/off — it is **infrastructure-only**: container mount path, SMB URL (editor), SMB mount + credentials, promote threshold.
- The `growing_enabled` settings *key* is retired from the UI. (It may remain in the table harmlessly; recorder-start no longer reads it.)
### Per-recorder semantics
- Reuse the existing `recorders.growing_enabled BOOLEAN` column. New semantics (no global to defer to): `TRUE` = this recorder uses growing-files mode; `NULL`/`FALSE` = off.
- `recorders.js` recorder-start: read the **recorder's own** `growing_enabled` (defaulting `NULL`→off) and set `GROWING_ENABLED` for the capture container from that, instead of the global setting.
- Add `growing_enabled` to `RECORDER_FIELDS` so create/update accept it.
### UI
- **New-recorder modal** (`modal-new-recorder.jsx`): add a "Growing-files mode" toggle that sets `growing_enabled` on the created recorder (default off).
- **Recorder edit** (wherever recorders are edited): same toggle.
- Helper text on the toggle notes that growing-files requires the SMB share to be configured in Settings → Storage.
### Fallback
If a recorder has `growing_enabled = true` but `growing_smb_mount` is not configured globally, capture logs a warning and falls back to S3 streaming (same fallback path as a failed mount). Recording is never blocked.
---
## Files changed
| File | Change |
|------|--------|
| `services/web-ui/public/screens-admin.jsx` | Storage warning banner; SMB mount/username/password fields in `GrowingSettingsCard`; remove global growing-enable checkbox |
| `services/web-ui/public/modal-new-recorder.jsx` | Per-recorder "Growing-files mode" toggle |
| `services/mam-api/src/routes/settings.js` | New growing SMB keys; write-only password (`growing_smb_password_exists`) |
| `services/mam-api/src/routes/recorders.js` | Read per-recorder `growing_enabled`; pass SMB env to capture; `RECORDER_FIELDS` += `growing_enabled`; empty `/growing` mountpoint |
| `services/capture/Dockerfile` | Add `cifs-utils` |
| `services/capture/src/capture-manager.js` | CIFS mount-on-start (creds file), unmount-on-stop, fallback to S3 on failure |
| CSS (storage warning / fields) | Minor styles if needed |
No DB migration required (the `recorders.growing_enabled` column already exists; new settings are key/value rows).
---
## Resolved decisions
- **Clearing the SMB password:** `PUT /settings/growing` treats a field value of the literal sentinel `""` with an explicit `growing_smb_password_clear: true` flag as "remove the stored password"; a blank field with no clear flag leaves it unchanged. (Keeps the common "don't retype the password on every save" UX while still allowing removal.)
- **CIFS version:** default `growing_smb_vers = 3.0`; overridable via settings to support older NAS targets.
- **Recorders already recording when the toggle changes:** the per-recorder `growing_enabled` is read at **start** only; changing it mid-recording has no effect on the active session (consistent with how all recorder encode settings already behave).
---
## Out of scope (deferred)
- Encrypting secrets at rest (the app's existing model stores `s3_secret_key` in plaintext; SMB password follows the same model).
- A global "growing-files master kill switch" (removed by design — control is now per-recorder).
- Exposing `growing_retention_days` in the UI (seeded in DB, still unsurfaced; unrelated to this work).
- Playout HLS preview fix (handled by a separate parallel effort).

View file

@ -1,231 +0,0 @@
# Deltacast SDI Capture — Design Spec
**Date:** 2026-06-01
**Status:** Approved
**Approach:** Bridge binary (Option B2)
---
## Problem
Dragonflight supports SDI ingest via Blackmagic DeckLink. Deltacast VideoMaster cards are a second hardware target. The VideoMaster SDK (v6.34.1) ships C++ headers and shared libraries but no FFmpeg demuxer plugin — there is no mainline FFmpeg `-f deltacast` input device. The `capture-manager.js` stub exists but falls back to a lavfi test card on all deployments.
---
## Approach
Write a small C++ bridge binary (`deltacast-capture`) using the VideoMaster C++ Wrapper SDK. The bridge:
1. Detects signal format on startup, writes one JSON line to stderr
2. Streams raw YUV video frames to stdout
3. Streams raw PCM audio to a named FIFO
`capture-manager.js` reads the JSON handshake, then spawns FFmpeg with `-f rawvideo -i pipe:0` (video from bridge stdout) and `-f s16le -i <fifo>` (audio from FIFO). The existing HEVC NVENC / ProRes encode pipeline is unchanged.
---
## Architecture
```
┌─────────────────────────────────────────────────────────┐
│ capture container │
│ │
│ capture-manager.js │
│ │ │
│ ├─ spawn deltacast-capture --device 0 --port 0 │
│ │ --audio-pipe /tmp/dc-audio-{sessionId} │
│ │ │ │
│ │ ├─ stderr: JSON format line (one-time handshake) │
│ │ ├─ stdout: raw YUV frames (continuous) │
│ │ └─ FIFO: raw PCM audio (continuous) │
│ │ │
│ └─ spawn ffmpeg │
│ -f rawvideo -pix_fmt uyvy422 -s WxH -r FPS/1 │
│ -i pipe:0 ← piped from bridge stdout │
│ -f s16le -ar 48000 -ac <N>
│ -i /tmp/dc-audio-{sessionId} │
<hevc_nvenc / prores / h264 encode args>
<S3 pipe or growing-file output>
└─────────────────────────────────────────────────────────┘
```
### New files
- `services/capture/deltacast-bridge/CMakeLists.txt`
- `services/capture/deltacast-bridge/main.cpp`
### Modified files
- `services/capture/src/capture-manager.js``_buildInputArgs()` deltacast branch; `start()` and `stop()` bridge lifecycle
- `services/capture/Dockerfile` — SDK extraction stage, bridge build stage, runtime `.so` install
---
## The `deltacast-capture` Binary
### CLI
```
deltacast-capture
--device <N> Board index (0-based)
--port <N> RX port index (0-based)
--audio-pipe <path> Named FIFO path for PCM audio output
[--signal-timeout <sec=30>]
[--audio-groups <N=2>] Number of SDI audio groups (2 groups = 8 channels)
```
### Startup sequence
1. `Board::open(device, loopback_restore_cb)`
2. Disable loopback on `port`
3. `board.sdi().open_stream(rx_streamtype(port), VHD_SDI_STPROC_DISJOINED_VIDEO)`
4. Poll `wait_for_input()` up to `--signal-timeout` seconds
5. On timeout → write `{"error":"no signal","device":N,"port":N}` to stderr, exit 1
6. Detect `video_standard`, `clock_divisor`, `interface` → map to width/height/fps/pix_fmt/interlaced
7. Write one JSON line to stderr (flushed):
```json
{"width":1920,"height":1080,"fps_num":25,"fps_den":1,"pix_fmt":"uyvy422","interlaced":false,"audio_channels":8,"audio_rate":48000,"device":0,"port":0}
```
8. Set queue depth = 8, `rx_stream.start()`
9. Capture loop: `pop_slot()` → write video buffer to stdout → extract audio → write PCM to FIFO (background thread)
10. SIGTERM/SIGINT → set stop flag → flush, close FIFO, close stream/board, exit 0
### Pixel format
Default: `uyvy422` (4:2:2 8-bit, `VHD_SDI_BUFTYPE_VIDEO`). 10-bit (`v210`) is a future follow-up via `--pix-fmt v210`.
### Audio
`sdi_slot.audio().extract(num_groups)` returns `std::vector<VHD_AUDIOGROUP>`. Samples are written to the FIFO as interleaved s16le PCM at 48000 Hz in a background thread so the video loop never blocks on audio consumers. Default `--audio-groups 2` yields 8 channels (standard embedded SDI stereo pairs 14).
---
## `capture-manager.js` Changes
### `_buildInputArgs()` — deltacast branch
Replace the existing lavfi-fallback stub with:
```js
if (sourceType === 'deltacast') {
const idx = parseInt(device, 10) || 0;
const audioFifo = `/tmp/dc-audio-${sessionId}`;
await execAsync(`mkfifo ${audioFifo}`);
const bridge = spawn('deltacast-capture', [
'--device', String(idx),
'--port', String(idx), // port == board index for single-port-per-recorder model
'--audio-pipe', audioFifo,
], { stdio: ['ignore', 'pipe', 'pipe'] });
const fmt = await readFirstStderrLine(bridge, 35_000); // 35s timeout
// fmt: { width, height, fps_num, fps_den, pix_fmt, interlaced, audio_channels, audio_rate }
return {
inputArgs: [
'-f', 'rawvideo',
'-pix_fmt', fmt.pix_fmt,
'-video_size', `${fmt.width}x${fmt.height}`,
'-framerate', `${fmt.fps_num}/${fmt.fps_den}`,
'-i', 'pipe:0',
'-f', 's16le',
'-ar', String(fmt.audio_rate),
'-ac', String(fmt.audio_channels),
'-i', audioFifo,
],
isNetwork: false,
bridgeProcess: bridge,
audioFifo,
interlaced: fmt.interlaced,
};
}
```
`readFirstStderrLine(proc, timeoutMs)` is a small helper that returns a parsed JSON object from the first line emitted on `proc.stderr`, or throws on timeout or non-zero exit.
### `start()` changes
- After `_buildInputArgs()` returns, store `bridgeProcess` and `audioFifo` on `this.state`
- Spawn FFmpeg with `stdio: ['pipe', ...]` for stdin
- `bridgeProcess.stdout.pipe(hiresProcess.stdin)`
- Deinterlace: if `interlaced === true`, add `-vf yadif=mode=1:deint=1` (already present for `sourceType === 'sdi'`; extend that check to include `deltacast`)
### `stop()` changes
- `if (processes.bridge) processes.bridge.kill('SIGINT')`
- After process cleanup: `if (this.state.audioFifo) { try { fs.unlinkSync(this.state.audioFifo); } catch (_) {} }`
### HLS preview
The existing `filter_complex split` SDI preview path works unchanged — the bridge→pipe is just a different `-i` source. Extend the `sourceType === 'sdi'` guard to `['sdi', 'deltacast'].includes(sourceType)`.
---
## Dockerfile Changes
```dockerfile
# ── Stage 0: Extract VideoMaster SDK ─────────────────────────────────────
FROM debian:bookworm AS sdk-extractor
COPY videomaster-linux.x64-6.34.1-dev.tar.gz /tmp/
RUN mkdir -p /sdk && tar -xzf /tmp/videomaster-linux.x64-6.34.1-dev.tar.gz -C /sdk
# ── Stage 1: Build deltacast-capture bridge ───────────────────────────────
FROM debian:bookworm AS bridge-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=sdk-extractor /sdk /sdk
COPY deltacast-bridge/ /bridge/
RUN cmake -S /bridge -B /bridge/build \
-DCMAKE_BUILD_TYPE=Release \
-DSDK_ROOT=/sdk \
&& cmake --build /bridge/build -j$(nproc)
# ── Stage 2: Build FFmpeg (unchanged) ─────────────────────────────────────
FROM debian:bookworm AS ffmpeg-builder
# ... existing content, no changes ...
# ── Stage 3: Runtime ──────────────────────────────────────────────────────
FROM node:20-bookworm
# ... existing runtime deps ...
COPY --from=bridge-builder /bridge/build/deltacast-capture /usr/local/bin/deltacast-capture
COPY --from=sdk-extractor /sdk/lib/ /usr/local/lib/deltacast/
RUN ldconfig /usr/local/lib/deltacast && ldconfig
```
SDK `.so` files total ~4MB. The bridge binary adds ~200KB.
---
## Error Handling
| Scenario | Bridge behavior | `capture-manager.js` response |
|---|---|---|
| No signal within timeout | Exit 1, `{"error":"no signal"}` on stderr | Throws — recorder stays idle, no asset created |
| Invalid board/port | Exit 1, `{"error":"board N not found"}` | Same as above |
| Bridge crash mid-capture | stdout closes → FFmpeg stdin EOF → FFmpeg exits cleanly | Existing stop handler fires; asset finalized with frames received so far |
| Audio FIFO open stall | Bridge blocks on FIFO write-open until FFmpeg opens read-end | Guarded by 10s watchdog on bridge spawn; if FFmpeg fails to start, bridge is SIGKILL'd |
| FIFO leftover on container crash | Stale file in `/tmp/` | Next `start()` uses a new `sessionId`-based path; harmless |
---
## Testing
### Without hardware (dev mode)
The lavfi fallback is **removed** from the deltacast branch — a missing `deltacast-capture` binary will throw at spawn time (clear error). Developers run the existing test card by using `sourceType = 'sdi'` with a DeckLink card or `sourceType = 'srt'` with a test stream.
The bridge binary can be tested standalone:
```bash
mkfifo /tmp/test-audio
deltacast-capture --device 0 --port 0 --audio-pipe /tmp/test-audio &
# watch stderr for JSON line, then:
cat /tmp/test-audio | ffprobe -f s16le -ar 48000 -ac 8 -i -
```
### With hardware (post-implementation)
1. Create recorder: `source_type=deltacast`, `device=0`, `port=0`
2. Verify JSON handshake in capture container logs within signal timeout
3. Verify `signal=receiving` in recorder status
4. Record 30s clip → asset created, proxy + HLS generated
5. Test stop mid-record → file finalized correctly
6. Test no-signal → recorder stays idle, no asset created
7. Test container restart mid-record → asset finalized on restart via existing `finalize` endpoint
---
## Out of Scope
- 10-bit (`v210`) pixel format — follow-up
- `--audio-groups` UI control — follow-up
- GPU extension SDK (`gpuextension-linux.x64-2.2.0-dev.zip`) — covers GPU-accelerated colorspace conversion on the card; not needed for basic capture
- IP virtual card SDK (`ipvirtualcard`) — separate feature
- Promoting bridge to a native FFmpeg `libavdevice` input device — future v2

View file

@ -1,42 +0,0 @@
# Capture-card SDK / driver file store
This directory holds the **proprietary, non-redistributable** vendor SDKs and
drivers used to enable SDI / NDI capture cards on cluster nodes.
> **INTERNAL ONLY.** These files are licensed by their respective vendors and
> must **not** be published, redistributed, or committed to any public mirror.
> This repository is private. Do not change that.
## Why these live in the repo
The cluster admin screen lets an operator install/update capture-card drivers on
a node from the web UI (no SSH). The node-agent spawns a one-shot privileged
container that bind-mounts this repository and runs
[`deploy/install-driver.sh <vendor>`](../deploy/install-driver.sh), which reads
the vendor files from `sdk/<vendor>/`. Because the install must work offline on
an isolated broadcast LAN, the binaries ship in-repo rather than being fetched at
install time.
## Layout
```
sdk/
README.md ← this file
blackmagic/ ← Blackmagic Desktop Video (DeckLink) .deb
aja/ ← AJA ntv2 driver source / installer
deltacast/ ← Deltacast VideoMaster installer
ndi/ ← NDI redistributable runtime libs
```
Each vendor directory has its own `README.md` listing **exactly** which files an
admin must drop in. A `.gitkeep` keeps the empty directory committed.
## Important
- **No binaries are committed by default.** The directory structure + READMEs
are the deliverable. An admin downloads the proprietary files from the vendor
(per their licence) and drops them in the matching `sdk/<vendor>/` directory.
- The install script **fails gracefully** with a clear message if the expected
file is absent — it never fabricates or downloads binaries.
- Target host OS for all install paths is **Ubuntu 22.04 LTS (jammy), x86_64**,
matching the cluster worker nodes.

View file

View file

@ -1,31 +0,0 @@
# AJA NTV2 driver
Drop the **AJA NTV2** driver source/SDK archive for Linux into this directory.
## Required file
| File | Notes |
|------|-------|
| `ntv2sdk*linux*.zip` **or** `libajantv2*.tar.gz` | The NTV2 SDK / open-source `libajantv2` source tree containing `driver/linux/` with the kernel-module `Makefile` and `load_ajantv2` / `unload_ajantv2` scripts. |
Example names: `ntv2sdklinux_17.0.1.zip`, `libajantv2-17.0.1.tar.gz`
The installer reads the **newest** matching archive.
## Where to get it
AJA → Support → Software & firmware → *NTV2 SDK* (Linux), or the public
`aja-video/libajantv2` source release. Download the Linux SDK zip / source
tarball and copy it here unmodified.
## What the install script does
1. Ensures `linux-headers-$(uname -r)`, `build-essential` are present.
2. Extracts the archive into a scratch build dir.
3. Builds the `ajantv2` kernel module from `driver/linux` (`make`).
4. Installs the module under `/lib/modules/$(uname -r)/extra`, runs `depmod`,
`modprobe ajantv2` (falls back to the SDK's `load_ajantv2` script).
5. Verifies the `ajantv2` module is loaded.
A **reboot is not normally required**; the module loads immediately after build.
The script reports if a reboot is needed (e.g. an old in-tree module is wedged).

View file

@ -1,35 +0,0 @@
# Blackmagic Desktop Video (DeckLink) driver
Drop the **Blackmagic Desktop Video** Debian package for **Ubuntu 22.04 (x86_64)**
into this directory.
## Required file
| File | Notes |
|------|-------|
| `desktopvideo_*_amd64.deb` | The `desktopvideo` package from the Desktop Video installer archive. Provides the `blackmagic` kernel module (built via DKMS) and the `DesktopVideoHelper` daemon. |
Example name: `desktopvideo_14.4.1a4_amd64.deb`
The installer reads the **newest** matching `desktopvideo_*_amd64.deb` if more
than one is present.
## Where to get it
Blackmagic Design → Support → *Desktop Video* (Linux). Download the
"Desktop Video x.y.z Linux" tarball, extract it, and copy the
`deb/<arch>/desktopvideo_*_amd64.deb` file here.
> Optional: `desktopvideo-gui_*_amd64.deb` is **not** required for headless
> capture and is not installed.
## What the install script does
1. Ensures `linux-headers-$(uname -r)` is present (needed for the DKMS build).
2. `apt-get install -y ./desktopvideo_*_amd64.deb` (pulls DKMS deps).
3. Triggers the DKMS build, `depmod`, `modprobe blackmagic`.
4. Restarts the `DesktopVideoHelper` daemon.
5. Verifies `/dev/blackmagic` appears.
A **reboot is usually not required** but a DKMS rebuild against a freshly
installed kernel may need one — the script reports this.

View file

View file

@ -1,31 +0,0 @@
# Deltacast VideoMaster driver / SDK
Drop the **Deltacast VideoMaster** Linux installer into this directory.
## Required file
| File | Notes |
|------|-------|
| `VideoMaster*.run` **or** `VideoMaster*linux*.tar.gz` | The VideoMaster SDK + driver installer for Linux. Contains the `videomasterhd` kernel module sources and the `install.sh` driver installer. |
Example names: `VideoMaster-6.25.0.run`, `VideoMaster_6_25_Linux.tar.gz`
The installer reads the **newest** matching file.
## Where to get it
Deltacast → Products → *SDK* (<https://www.deltacast.tv/products/sdk>). Request
the VideoMaster Linux package (licence-gated) and copy the `.run` self-extractor
or the `.tar.gz` here unmodified.
## What the install script does
1. Ensures `linux-headers-$(uname -r)`, `build-essential`, `dkms` are present.
2. Runs the vendor installer:
- `.run` → executed with `--noexec --target <dir>` then its `install.sh`,
- `.tar.gz` → extracted, then its bundled `install.sh` is run.
3. Loads the Deltacast module (`modprobe videomasterhd` / vendor load script).
4. Verifies a `/dev/deltacast*` device node appears.
A **reboot may be required** after a first-time VideoMaster install (udev rules
+ firmware). The script reports this explicitly.

View file

View file

@ -1,35 +0,0 @@
# NDI redistributable runtime
Drop the **NDI runtime redistributable** shared libraries into this directory.
NDI has **no kernel module** — it is purely user-space shared libraries, so this
is the lowest-risk install (no DKMS, no reboot).
## Required files
| File | Notes |
|------|-------|
| `libndi.so.*` | The versioned NDI runtime shared object, e.g. `libndi.so.6`. **Required.** |
| `libndi.so` *(optional)* | Dev symlink. The installer recreates it if absent. |
You may instead drop the whole **NDI SDK / Advanced SDK** `lib/x86_64-linux-gnu/`
directory contents here; the installer copies every `libndi*.so*` it finds.
Example name: `libndi.so.6.1.1`
## Where to get it
NDI → Tools / SDK download (NDI 6 SDK or NDI Advanced SDK for Linux). The
runtime libs live under `lib/x86_64-linux-gnu/` in the SDK. Per the NDI licence
the runtime is redistributable **within your own product** only — keep it in this
private repo, do not publish it.
## What the install script does
1. Copies every `libndi*.so*` from here into `/opt/ndi-lib`.
2. Writes `/etc/ld.so.conf.d/ndi.conf` pointing at `/opt/ndi-lib` and runs
`ldconfig`.
3. Recreates the `libndi.so``libndi.so.<N>` dev symlink if missing.
4. Verifies `ldconfig -p | grep libndi` resolves.
**No reboot required.** Running processes that already loaded an old `libndi`
must be restarted to pick up the new version — the script notes this.

View file

@ -1,27 +1,4 @@
# ── Stage 0: Extract Deltacast VideoMaster SDK ─────────────────────────── # ── Stage 1: Build FFmpeg with DeckLink support ─────────────────────────────
FROM debian:bookworm AS sdk-extractor
COPY videomaster-linux.x64-6.34.1-dev.tar.gz /tmp/
RUN mkdir -p /sdk && tar -xzf /tmp/videomaster-linux.x64-6.34.1-dev.tar.gz -C /sdk
# ── Stage 1: Build deltacast-capture bridge binary ───────────────────────
FROM debian:bookworm AS bridge-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=sdk-extractor /sdk /sdk
COPY deltacast-bridge/ /bridge/
RUN cmake -S /bridge -B /bridge/build \
-DCMAKE_BUILD_TYPE=Release \
-DSDK_ROOT=/sdk \
&& cmake --build /bridge/build -j$(nproc)
# ── Stage 2: Build FFmpeg with DeckLink + NVENC (HEVC/H264) support ─────────
# All-Intra HEVC NVENC is the master codec for growing-file ingest (see
# docs/design/2026-05-29-all-intra-hevc-ingest.md). This stage gets the
# nv-codec-headers (header-only, no driver / no full CUDA toolkit needed)
# so ffmpeg's configure can light up hevc_nvenc / h264_nvenc / cuvid.
# At runtime, /dev/nvidia* + the host driver libs (via the NVIDIA Container
# Toolkit) supply the actual encoder.
FROM debian:bookworm AS ffmpeg-builder FROM debian:bookworm AS ffmpeg-builder
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@ -36,11 +13,6 @@ COPY sdk/ /decklink-sdk/
COPY patch_decklink.py /patch_decklink.py COPY patch_decklink.py /patch_decklink.py
COPY decklink-sdk16.patch /decklink-sdk16.patch COPY decklink-sdk16.patch /decklink-sdk16.patch
# nv-codec-headers — just the ffnvcodec public headers + a pkg-config file.
# Pin to a tag known to work with FFmpeg 7.1 (n12.x series).
RUN git clone --depth=1 --branch n12.1.14.0 https://github.com/FFmpeg/nv-codec-headers.git /nv-codec-headers \
&& make -C /nv-codec-headers PREFIX=/usr/local install
# Pull FFmpeg 7.1 source # Pull FFmpeg 7.1 source
RUN git clone --depth=1 --branch release/7.1 https://git.ffmpeg.org/ffmpeg.git /ffmpeg RUN git clone --depth=1 --branch release/7.1 https://git.ffmpeg.org/ffmpeg.git /ffmpeg
@ -48,15 +20,8 @@ RUN git clone --depth=1 --branch release/7.1 https://git.ffmpeg.org/ffmpeg.git /
RUN python3 /patch_decklink.py RUN python3 /patch_decklink.py
WORKDIR /ffmpeg WORKDIR /ffmpeg
# NVENC adds: --enable-nvenc (encoder), --enable-cuvid (decoder), --enable-ffnvcodec.
# We deliberately do NOT enable --enable-cuda-nvcc / --enable-libnpp here — those
# require the full ~3GB CUDA toolkit and are only needed for GPU filters like
# yadif_cuda / scale_cuda. If §5's GPU deinterlace stretch goal goes ahead,
# rebuild this image off nvidia/cuda:12.x-devel and flip those flags on.
RUN ./configure \ RUN ./configure \
--prefix=/usr/local \ --prefix=/usr/local \
--extra-cflags="-I/decklink-sdk -I/usr/local/include" \
--extra-ldflags="-L/usr/local/lib" \
--enable-gpl \ --enable-gpl \
--enable-nonfree \ --enable-nonfree \
--enable-libx264 \ --enable-libx264 \
@ -67,60 +32,20 @@ RUN ./configure \
--enable-libsrt \ --enable-libsrt \
--enable-libzmq \ --enable-libzmq \
--enable-decklink \ --enable-decklink \
--enable-ffnvcodec \ --extra-cflags="-I/decklink-sdk" \
--enable-nvenc \
--enable-cuvid \
--disable-doc \ --disable-doc \
--disable-debug \ --disable-debug \
--disable-ffplay \ --disable-ffplay \
&& make -j$(nproc) \ && make -j$(nproc) \
&& make install && make install
# Sanity-check: hevc_nvenc and h264_nvenc must be present in the encoder list,
# otherwise the resulting image is useless for the All-Intra HEVC pipeline.
RUN /usr/local/bin/ffmpeg -hide_banner -encoders 2>&1 | grep -E 'nvenc' \
|| (echo 'FATAL: nvenc encoders missing from ffmpeg build' && exit 1)
# ── Stage 1b: Build bmx (raw2bmx / bmxtranswrap) from source ─────────────────
# bmx (bmxlib + libMXF + libMXF++) is the reference GROWING OP1a MXF writer. It
# writes a fresh IndexTableSegment (with an updated IndexDuration) into a new
# body partition at a periodic interval, so the recorded duration is readable —
# and INCREASES — from the header+index alone while the file is still being
# written (no footer needed). This is what makes the master a TRUE Premiere
# growing file. ffmpeg's MXF muxer cannot do this (its real duration/index lands
# only in the footer at av_write_trailer, so duration probes N/A until close).
#
# Debian/Ubuntu have no `bmxlib-tools` package (verified absent in bookworm), so
# we build from the BBC source. liburiparser/uuid/lzma/zlib/expat are the build
# deps; the runtime needs only libexpat1 + liburiparser1 + libuuid1 (added in
# the runtime stage below). Pinned to the bbc/bmx default branch (v1.6.x).
FROM debian:bookworm AS bmx-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake git ca-certificates pkg-config \
liburiparser-dev uuid-dev liblzma-dev zlib1g-dev libexpat1-dev \
&& rm -rf /var/lib/apt/lists/*
# Pin to a release tag so the produced soname (libMXF.so.1.6 etc.) stays stable
# for the COPY in the runtime stage. v1.6 is the BBC bmx series verified here.
RUN git clone --recursive --branch v1.6 https://github.com/bbc/bmx.git /bmx \
|| git clone --recursive https://github.com/bbc/bmx.git /bmx
WORKDIR /bmx/build
RUN cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local .. \
&& make -j"$(nproc)" && make install && ldconfig
# Sanity-check: raw2bmx must run, otherwise the growing-MXF pipeline is broken.
RUN /usr/local/bin/raw2bmx -h >/dev/null 2>&1 && echo 'raw2bmx OK'
# ── Stage 2: Runtime image ─────────────────────────────────────────────────── # ── Stage 2: Runtime image ───────────────────────────────────────────────────
FROM node:20-bookworm FROM node:20-bookworm
# Runtime deps for compiled ffmpeg libs. # Runtime deps for compiled ffmpeg libs
# cifs-utils provides mount.cifs so growing-files capture can mount the SMB
# landing-zone share inside the (privileged) container at start (Approach A).
# util-linux supplies mount/umount/mountpoint.
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
libx264-164 libx265-199 libvpx7 libopus0 libmp3lame0 \ libx264-164 libx265-199 libvpx7 libopus0 libmp3lame0 \
libsrt1.5-openssl libzmq5 libstdc++6 libc++1 libc++abi1 \ libsrt1.5-openssl libzmq5 libstdc++6 libc++1 libc++abi1 \
cifs-utils util-linux \
libexpat1 liburiparser1 libuuid1 \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Copy compiled ffmpeg/ffprobe # Copy compiled ffmpeg/ffprobe
@ -131,39 +56,7 @@ COPY --from=ffmpeg-builder /usr/local/lib/ /usr/local/lib/
# DeckLink runtime .so # DeckLink runtime .so
COPY lib/libDeckLinkAPI.so /usr/lib/libDeckLinkAPI.so COPY lib/libDeckLinkAPI.so /usr/lib/libDeckLinkAPI.so
COPY lib/libDeckLinkPreviewAPI.so /usr/lib/libDeckLinkPreviewAPI.so COPY lib/libDeckLinkPreviewAPI.so /usr/lib/libDeckLinkPreviewAPI.so
RUN ldconfig
# bmx (raw2bmx / bmxtranswrap / mxf2raw) — the growing OP1a MXF writer used for
# the edit-while-record master. Copy the built binaries + shared libs; runtime
# deps (libexpat1/liburiparser1/libuuid1) were installed above.
COPY --from=bmx-builder /usr/local/bin/raw2bmx /usr/local/bin/raw2bmx
COPY --from=bmx-builder /usr/local/bin/bmxtranswrap /usr/local/bin/bmxtranswrap
COPY --from=bmx-builder /usr/local/bin/mxf2raw /usr/local/bin/mxf2raw
COPY --from=bmx-builder /usr/local/lib/libMXF.so.1.6 /usr/local/lib/
COPY --from=bmx-builder /usr/local/lib/libMXF++.so.1.6 /usr/local/lib/
COPY --from=bmx-builder /usr/local/lib/libbmx.so.1.6 /usr/local/lib/
RUN cd /usr/local/lib \
&& ln -sf libMXF.so.1.6 libMXF.so.1 && ln -sf libMXF.so.1 libMXF.so \
&& ln -sf libMXF++.so.1.6 libMXF++.so.1 && ln -sf libMXF++.so.1 libMXF++.so \
&& ln -sf libbmx.so.1.6 libbmx.so.1 && ln -sf libbmx.so.1 libbmx.so \
&& ldconfig
# Verify raw2bmx resolves its libs and runs in the final image.
RUN raw2bmx -h >/dev/null 2>&1 && echo 'raw2bmx runtime OK'
# Deltacast bridge binary + SDK runtime libs
COPY --from=bridge-builder /bridge/build/deltacast-capture /usr/local/bin/deltacast-capture
COPY --from=sdk-extractor /sdk/lib/libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/
COPY --from=sdk-extractor /sdk/lib/libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/
RUN ln -sf libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd.so.6 \
&& ln -sf libvideomasterhd.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd.so \
&& ln -sf libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd_audio.so.6 \
&& ln -sf libvideomasterhd_audio.so.6.34.1 /usr/local/lib/deltacast/libvideomasterhd_audio.so \
&& ldconfig /usr/local/lib/deltacast \
&& ldconfig
# Mount points the recorder lifecycle expects to exist.
# /live — HLS preview output (bound from host LIVE_DIR by node-agent)
# /growing — growing-file master output (bound from host /mnt/NVME/MAM/growing)
RUN mkdir -p /live /growing
WORKDIR /app WORKDIR /app
COPY package*.json ./ COPY package*.json ./

View file

@ -1,27 +0,0 @@
cmake_minimum_required(VERSION 3.16)
project(deltacast-bridge C)
set(CMAKE_C_STANDARD 17)
set(SDK_ROOT "/sdk" CACHE PATH "Path to extracted VideoMaster SDK")
add_executable(deltacast-capture main.c)
target_include_directories(deltacast-capture PRIVATE
${SDK_ROOT}/include/videomaster
)
target_link_directories(deltacast-capture PRIVATE
${SDK_ROOT}/lib
)
target_link_libraries(deltacast-capture PRIVATE
videomasterhd
videomasterhd_audio
pthread
)
# Embed the SDK RPATH so the binary finds the .so at runtime
set_target_properties(deltacast-capture PROPERTIES
INSTALL_RPATH "/usr/local/lib/deltacast"
BUILD_WITH_INSTALL_RPATH TRUE
)

View file

@ -1,310 +0,0 @@
/* services/capture/deltacast-bridge/main.c
*
* Deltacast VideoMaster SDI capture bridge.
* Writes raw UYVY video to stdout and stereo PCM to a named FIFO.
* Emits one JSON line to stderr on signal lock before streaming starts.
*
* Usage:
* deltacast-capture --device <N> --port <N> --audio-pipe <path>
* [--signal-timeout <sec>]
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "VideoMasterHD_Core.h"
#include "VideoMasterHD_Sdi.h"
#include "VideoMasterHD_Sdi_Audio.h"
/* ── Globals ─────────────────────────────────────────────────────────── */
static atomic_int g_stop = 0;
static void on_signal(int s) { (void)s; atomic_store(&g_stop, 1); }
/* ── Stream type by port index ───────────────────────────────────────── */
static ULONG rx_streamtype(unsigned port) {
switch (port) {
case 0: return VHD_ST_RX0;
case 1: return VHD_ST_RX1;
case 2: return VHD_ST_RX2;
case 3: return VHD_ST_RX3;
default:
fprintf(stderr, "{\"error\":\"port %u not supported (max 3)\"}\n", port);
return VHD_ST_RX0; /* caller will fail on signal lock */
}
}
/* ── Loopback board property by port index ───────────────────────────── */
static ULONG loopback_prop(unsigned port) {
switch (port) {
case 0: return VHD_CORE_BP_PASSIVE_LOOPBACK_0;
case 1: return VHD_CORE_BP_PASSIVE_LOOPBACK_1;
case 2: return VHD_CORE_BP_PASSIVE_LOOPBACK_2;
case 3: return VHD_CORE_BP_PASSIVE_LOOPBACK_3;
default: return VHD_CORE_BP_PASSIVE_LOOPBACK_0;
}
}
/* ── Video standard → width/height/fps/interlaced ───────────────────── */
typedef struct { int width, height, fps_num, fps_den; int interlaced; } VideoInfo;
static VideoInfo video_info(VHD_VIDEOSTANDARD std, VHD_CLOCKDIVISOR div) {
int ntsc = (div == VHD_CLOCKDIV_1001);
switch (std) {
case VHD_VIDEOSTD_S274M_1080p_25Hz: return (VideoInfo){1920,1080,25,1,0};
case VHD_VIDEOSTD_S274M_1080p_30Hz: return (VideoInfo){1920,1080,ntsc?30000:30,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080p_24Hz: return (VideoInfo){1920,1080,ntsc?24000:24,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080p_50Hz: return (VideoInfo){1920,1080,50,1,0};
case VHD_VIDEOSTD_S274M_1080p_60Hz: return (VideoInfo){1920,1080,ntsc?60000:60,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080psf_24Hz: return (VideoInfo){1920,1080,ntsc?24000:24,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080psf_25Hz: return (VideoInfo){1920,1080,25,1,0};
case VHD_VIDEOSTD_S274M_1080psf_30Hz: return (VideoInfo){1920,1080,ntsc?30000:30,ntsc?1001:1,0};
case VHD_VIDEOSTD_S274M_1080i_50Hz: return (VideoInfo){1920,1080,25,1,1};
case VHD_VIDEOSTD_S274M_1080i_60Hz: return (VideoInfo){1920,1080,ntsc?30000:30,ntsc?1001:1,1};
case VHD_VIDEOSTD_S296M_720p_50Hz: return (VideoInfo){1280,720,50,1,0};
case VHD_VIDEOSTD_S296M_720p_60Hz: return (VideoInfo){1280,720,ntsc?60000:60,ntsc?1001:1,0};
case VHD_VIDEOSTD_S296M_720p_25Hz: return (VideoInfo){1280,720,25,1,0};
case VHD_VIDEOSTD_S296M_720p_30Hz: return (VideoInfo){1280,720,ntsc?30000:30,ntsc?1001:1,0};
case VHD_VIDEOSTD_S296M_720p_24Hz: return (VideoInfo){1280,720,ntsc?24000:24,ntsc?1001:1,0};
case VHD_VIDEOSTD_3840x2160p_24Hz: return (VideoInfo){3840,2160,ntsc?24000:24,ntsc?1001:1,0};
case VHD_VIDEOSTD_3840x2160p_25Hz: return (VideoInfo){3840,2160,25,1,0};
case VHD_VIDEOSTD_3840x2160p_30Hz: return (VideoInfo){3840,2160,ntsc?30000:30,ntsc?1001:1,0};
case VHD_VIDEOSTD_3840x2160p_50Hz: return (VideoInfo){3840,2160,50,1,0};
case VHD_VIDEOSTD_3840x2160p_60Hz: return (VideoInfo){3840,2160,ntsc?60000:60,ntsc?1001:1,0};
case VHD_VIDEOSTD_S259M_NTSC_480: return (VideoInfo){720,480,ntsc?30000:30,ntsc?1001:1,1};
default: return (VideoInfo){1920,1080,25,1,0};
}
}
/* ── Audio thread ────────────────────────────────────────────────────── */
typedef struct {
HANDLE board;
unsigned port;
ULONG video_std;
ULONG clock_div;
const char *fifo_path;
} AudioArgs;
static void *audio_thread(void *arg) {
AudioArgs *a = (AudioArgs *)arg;
HANDLE stream = NULL;
ULONG r = VHD_OpenStreamHandle(a->board, rx_streamtype(a->port),
VHD_SDI_STPROC_DISJOINED_ANC,
NULL, &stream, NULL);
if (r != VHDERR_NOERROR) {
fprintf(stderr, "[audio] VHD_OpenStreamHandle failed: %lu\n", r);
return NULL;
}
VHD_SetStreamProperty(stream, VHD_SDI_SP_VIDEO_STANDARD, a->video_std);
VHD_SetStreamProperty(stream, VHD_SDI_SP_CLOCK_SYSTEM, a->clock_div);
VHD_SetStreamProperty(stream, VHD_CORE_SP_TRANSFER_SCHEME, VHD_TRANSFER_SLAVED);
/* Stereo pair, 16-bit, 48kHz on group 0 channel 0 */
ULONG max_samples = VHD_GetNbSamples((VHD_VIDEOSTANDARD)a->video_std,
(VHD_CLOCKDIVISOR)a->clock_div,
VHD_ASR_48000, 0);
ULONG block_size = VHD_GetBlockSize(VHD_AF_16, VHD_AM_STEREO);
ULONG buf_sz = (max_samples + 4) * block_size; /* +4 for 29.97 variation */
unsigned char *buf = calloc(1, buf_sz);
if (!buf) { VHD_CloseStreamHandle(stream); return NULL; }
VHD_AUDIOINFO ai;
memset(&ai, 0, sizeof(ai));
ai.pAudioGroups[0].pAudioChannels[0].Mode = VHD_AM_STEREO;
ai.pAudioGroups[0].pAudioChannels[0].BufferFormat = VHD_AF_16;
ai.pAudioGroups[0].pAudioChannels[0].pData = buf;
if (VHD_StartStream(stream) != VHDERR_NOERROR) {
free(buf); VHD_CloseStreamHandle(stream); return NULL;
}
/* Open FIFO for writing — blocks until FFmpeg opens the read end */
int fd = open(a->fifo_path, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "[audio] open FIFO failed: %s\n", strerror(errno));
VHD_StopStream(stream); VHD_CloseStreamHandle(stream); free(buf);
return NULL;
}
HANDLE slot = NULL;
while (!atomic_load(&g_stop)) {
r = VHD_LockSlotHandle(stream, &slot);
if (r == VHDERR_NOERROR) {
ai.pAudioGroups[0].pAudioChannels[0].DataSize = buf_sz;
if (VHD_SlotExtractAudio(slot, &ai) == VHDERR_NOERROR) {
ULONG sz = ai.pAudioGroups[0].pAudioChannels[0].DataSize;
if (sz > 0) {
ULONG aw = 0;
while (aw < sz) {
ssize_t n = write(fd, buf + aw, sz - aw);
if (n <= 0) { atomic_store(&g_stop, 1); break; }
aw += (ULONG)n;
}
}
}
VHD_UnlockSlotHandle(slot);
} else if (r != VHDERR_TIMEOUT) {
break;
}
}
close(fd);
VHD_StopStream(stream);
VHD_CloseStreamHandle(stream);
free(buf);
return NULL;
}
/* ── Main ────────────────────────────────────────────────────────────── */
int main(int argc, char *argv[]) {
unsigned device_id = 0;
unsigned port_id = 0;
int sig_timeout = 30;
const char *audio_pipe = NULL;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--device") && i+1 < argc) device_id = (unsigned)atoi(argv[++i]);
else if (!strcmp(argv[i], "--port") && i+1 < argc) port_id = (unsigned)atoi(argv[++i]);
else if (!strcmp(argv[i], "--audio-pipe") && i+1 < argc) audio_pipe = argv[++i];
else if (!strcmp(argv[i], "--signal-timeout") && i+1 < argc) sig_timeout = atoi(argv[++i]);
}
signal(SIGINT, on_signal);
signal(SIGTERM, on_signal);
/* ── Init API ─────────────────────────────────────────────────── */
ULONG dll_ver, nb_boards;
if (VHD_GetApiInfo(&dll_ver, &nb_boards) != VHDERR_NOERROR) {
fprintf(stderr, "{\"error\":\"VHD_GetApiInfo failed\"}\n");
return 1;
}
if (device_id >= nb_boards) {
fprintf(stderr, "{\"error\":\"board %u not found (%lu detected)\"}\n", device_id, nb_boards);
return 1;
}
/* ── Open board ───────────────────────────────────────────────── */
HANDLE board = NULL;
if (VHD_OpenBoardHandle(device_id, &board, NULL, 0) != VHDERR_NOERROR) {
fprintf(stderr, "{\"error\":\"VHD_OpenBoardHandle failed for board %u\"}\n", device_id);
return 1;
}
/* Disable passive (relay) loopback so RX is live */
VHD_SetBoardProperty(board, loopback_prop(port_id), FALSE);
/* ── Wait for signal lock ──────────────────────────────────────── */
ULONG video_std = (ULONG)NB_VHD_VIDEOSTANDARDS;
struct timespec deadline;
clock_gettime(CLOCK_MONOTONIC, &deadline);
deadline.tv_sec += sig_timeout;
while (!atomic_load(&g_stop)) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if (now.tv_sec > deadline.tv_sec ||
(now.tv_sec == deadline.tv_sec && now.tv_nsec >= deadline.tv_nsec)) break;
VHD_GetChannelProperty(board, VHD_RX_CHANNEL, port_id,
VHD_SDI_CP_VIDEO_STANDARD, &video_std);
if (video_std != (ULONG)NB_VHD_VIDEOSTANDARDS) break;
struct timespec ts = {0, 200000000L}; /* 200ms */
nanosleep(&ts, NULL);
}
if (atomic_load(&g_stop) || video_std == (ULONG)NB_VHD_VIDEOSTANDARDS) {
fprintf(stderr,
"{\"error\":\"no signal on board %u port %u within %ds\"}\n",
device_id, port_id, sig_timeout);
VHD_CloseBoardHandle(board);
return 1;
}
ULONG clock_div = VHD_CLOCKDIV_1;
VHD_GetChannelProperty(board, VHD_RX_CHANNEL, port_id,
VHD_SDI_CP_CLOCK_DIVISOR, &clock_div);
VideoInfo vi = video_info((VHD_VIDEOSTANDARD)video_std,
(VHD_CLOCKDIVISOR)clock_div);
/* ── Emit format JSON to stderr (one line, flushed) ─────────────── */
fprintf(stderr,
"{\"width\":%d,\"height\":%d,\"fps_num\":%d,\"fps_den\":%d,"
"\"interlaced\":%s,\"pix_fmt\":\"uyvy422\","
"\"audio_channels\":2,\"audio_rate\":48000,"
"\"device\":%u,\"port\":%u}\n",
vi.width, vi.height, vi.fps_num, vi.fps_den,
vi.interlaced ? "true" : "false",
device_id, port_id);
fflush(stderr);
/* ── Open video stream ───────────────────────────────────────────── */
HANDLE video_stream = NULL;
if (VHD_OpenStreamHandle(board, rx_streamtype(port_id),
VHD_SDI_STPROC_DISJOINED_VIDEO,
NULL, &video_stream, NULL) != VHDERR_NOERROR) {
fprintf(stderr, "{\"error\":\"VHD_OpenStreamHandle (video) failed\"}\n");
VHD_CloseBoardHandle(board);
return 1;
}
VHD_SetStreamProperty(video_stream, VHD_SDI_SP_VIDEO_STANDARD, video_std);
VHD_SetStreamProperty(video_stream, VHD_SDI_SP_CLOCK_SYSTEM, clock_div);
VHD_SetStreamProperty(video_stream, VHD_CORE_SP_TRANSFER_SCHEME, VHD_TRANSFER_SLAVED);
VHD_SetStreamProperty(video_stream, VHD_CORE_SP_BUFFERQUEUE_DEPTH, 8);
/* ── Launch audio thread (FIFO open blocks until FFmpeg connects) ── */
pthread_t audio_tid = 0;
AudioArgs audio_args = { board, port_id, video_std, clock_div, audio_pipe };
if (audio_pipe) {
pthread_create(&audio_tid, NULL, audio_thread, &audio_args);
}
/* ── Start video stream ──────────────────────────────────────────── */
if (VHD_StartStream(video_stream) != VHDERR_NOERROR) {
atomic_store(&g_stop, 1);
if (audio_tid) pthread_join(audio_tid, NULL);
VHD_CloseStreamHandle(video_stream);
VHD_CloseBoardHandle(board);
return 1;
}
/* ── Video capture loop ──────────────────────────────────────────── */
HANDLE slot = NULL;
while (!atomic_load(&g_stop)) {
ULONG r = VHD_LockSlotHandle(video_stream, &slot);
if (r == VHDERR_NOERROR) {
BYTE *buf = NULL;
ULONG sz = 0;
if (VHD_GetSlotBuffer(slot, VHD_SDI_BT_VIDEO, &buf, &sz) == VHDERR_NOERROR) {
ULONG written = 0;
while (written < sz) {
ssize_t n = write(STDOUT_FILENO, buf + written, sz - written);
if (n <= 0) { atomic_store(&g_stop, 1); break; }
written += (ULONG)n;
}
}
VHD_UnlockSlotHandle(slot);
} else if (r != VHDERR_TIMEOUT) {
fprintf(stderr, "[video] VHD_LockSlotHandle error %lu — stopping\n", r);
break;
}
}
/* ── Cleanup ─────────────────────────────────────────────────────── */
VHD_StopStream(video_stream);
VHD_CloseStreamHandle(video_stream);
if (audio_tid) pthread_join(audio_tid, NULL);
VHD_CloseBoardHandle(board);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,338 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2026 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation covered by
** this license (the "Software") to use, reproduce, display, distribute,
** execute, and transmit the Software, and to prepare derivative works of the
** Software, and to permit third-parties to whom the Software is furnished to
** do so, all subject to the following:
**
** The copyright notices in the Software and this entire statement, including
** the above license grant, this restriction and the following disclaimer,
** must be included in all copies of the Software, in whole or in part, and
** all derivative works of the Software, unless such copies or derivative
** works are solely in the form of machine-executable object code generated by
** a source language processor.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
** -LICENSE-END-
*/
/*
* -- AUTOMATICALLY GENERATED - DO NOT EDIT ---
*/
#ifndef BMD_DECKLINKAPICONFIGURATION_H
#define BMD_DECKLINKAPICONFIGURATION_H
#ifndef BMD_CONST
#if defined(_MSC_VER)
#define BMD_CONST __declspec(selectany) static const
#else
#define BMD_CONST static const
#endif
#endif
#ifndef BMD_PUBLIC
#define BMD_PUBLIC
#endif
// Type Declarations
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkConfiguration = /* 5A68FFD4-1C12-4EDE-A6D2-45451D385FC1 */ { 0x5A,0x68,0xFF,0xD4,0x1C,0x12,0x4E,0xDE,0xA6,0xD2,0x45,0x45,0x1D,0x38,0x5F,0xC1 };
BMD_CONST REFIID IID_IDeckLinkEncoderConfiguration = /* 138050E5-C60A-4552-BF3F-0F358049327E */ { 0x13,0x80,0x50,0xE5,0xC6,0x0A,0x45,0x52,0xBF,0x3F,0x0F,0x35,0x80,0x49,0x32,0x7E };
/* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */
typedef uint32_t BMDDeckLinkConfigurationID;
enum _BMDDeckLinkConfigurationID {
/* Serial port Flags */
bmdDeckLinkConfigSwapSerialRxTx = /* 'ssrt' */ 0x73737274,
/* Video Input/Output Integers */
bmdDeckLinkConfigHDMI3DPackingFormat = /* '3dpf' */ 0x33647066,
bmdDeckLinkConfigBypass = /* 'byps' */ 0x62797073,
bmdDeckLinkConfigClockTimingAdjustment = /* 'ctad' */ 0x63746164,
bmdDeckLinkConfigAudioMeterType = /* 'aumt' */ 0x61756D74,
/* Audio Input/Output Flags */
bmdDeckLinkConfigAnalogAudioConsumerLevels = /* 'aacl' */ 0x6161636C,
bmdDeckLinkConfigSwapHDMICh3AndCh4OnInput = /* 'hi34' */ 0x68693334,
bmdDeckLinkConfigSwapHDMICh3AndCh4OnOutput = /* 'ho34' */ 0x686F3334,
bmdDeckLinkConfigAnalogAudioOutputChannelsMutedByHeadphone = /* 'amhp' */ 0x616D6870,
bmdDeckLinkConfigAnalogAudioOutputChannelsMutedBySpeaker = /* 'amsp' */ 0x616D7370,
/* Video Output Flags */
bmdDeckLinkConfigFieldFlickerRemoval = /* 'fdfr' */ 0x66646672,
bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = /* 'to59' */ 0x746F3539,
bmdDeckLinkConfig444SDIVideoOutput = /* '444o' */ 0x3434346F,
bmdDeckLinkConfigBlackVideoOutputDuringCapture = /* 'bvoc' */ 0x62766F63,
bmdDeckLinkConfigLowLatencyVideoOutput = /* 'llvo' */ 0x6C6C766F,
bmdDeckLinkConfigDownConversionOnAllAnalogOutput = /* 'caao' */ 0x6361616F,
bmdDeckLinkConfigSMPTELevelAOutput = /* 'smta' */ 0x736D7461,
bmdDeckLinkConfigRec2020Output = /* 'rec2' */ 0x72656332, // Ensure output is Rec.2020 colorspace
bmdDeckLinkConfigQuadLinkSDIVideoOutputSquareDivisionSplit = /* 'SDQS' */ 0x53445153,
bmdDeckLinkConfigOutput1080pAsPsF = /* 'pfpr' */ 0x70667072,
bmdDeckLinkConfigOutputValidateEDIDForDolbyVision = /* 'pred' */ 0x70726564,
bmdDeckLinkConfigExtendedDesktop = /* 'exdt' */ 0x65786474,
bmdDeckLinkConfigEthernetVideoOutputIP10 = /* 'IP10' */ 0x49503130,
/* Video Output Integers */
bmdDeckLinkConfigVideoOutputConnection = /* 'vocn' */ 0x766F636E,
bmdDeckLinkConfigVideoOutputConversionMode = /* 'vocm' */ 0x766F636D,
bmdDeckLinkConfigVideoOutputConversionColorspaceDestination = /* 'vccd' */ 0x76636364, // Parameter is of type BMDColorspace
bmdDeckLinkConfigVideoOutputConversionColorspaceSource = /* 'vccs' */ 0x76636373, // Parameter is of type BMDColorspace
bmdDeckLinkConfigAnalogVideoOutputFlags = /* 'avof' */ 0x61766F66,
bmdDeckLinkConfigReferenceInputTimingOffset = /* 'glot' */ 0x676C6F74,
bmdDeckLinkConfigReferenceOutputMode = /* 'glOm' */ 0x676C4F6D,
bmdDeckLinkConfigVideoOutputIdleOperation = /* 'voio' */ 0x766F696F,
bmdDeckLinkConfigDefaultVideoOutputMode = /* 'dvom' */ 0x64766F6D,
bmdDeckLinkConfigDefaultVideoOutputModeFlags = /* 'dvof' */ 0x64766F66,
bmdDeckLinkConfigSDIOutputLinkConfiguration = /* 'solc' */ 0x736F6C63,
bmdDeckLinkConfigHDMITimecodePacking = /* 'htpk' */ 0x6874706B,
bmdDeckLinkConfigPlaybackGroup = /* 'plgr' */ 0x706C6772,
/* Video Output Floats */
bmdDeckLinkConfigVideoOutputComponentLumaGain = /* 'oclg' */ 0x6F636C67,
bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = /* 'occb' */ 0x6F636362,
bmdDeckLinkConfigVideoOutputComponentChromaRedGain = /* 'occr' */ 0x6F636372,
bmdDeckLinkConfigVideoOutputCompositeLumaGain = /* 'oilg' */ 0x6F696C67,
bmdDeckLinkConfigVideoOutputCompositeChromaGain = /* 'oicg' */ 0x6F696367,
bmdDeckLinkConfigVideoOutputSVideoLumaGain = /* 'oslg' */ 0x6F736C67,
bmdDeckLinkConfigVideoOutputSVideoChromaGain = /* 'oscg' */ 0x6F736367,
bmdDeckLinkConfigDolbyVisionCMVersion = /* 'dvvr' */ 0x64767672,
bmdDeckLinkConfigDolbyVisionMasterMinimumNits = /* 'mnnt' */ 0x6D6E6E74,
bmdDeckLinkConfigDolbyVisionMasterMaximumNits = /* 'mxnt' */ 0x6D786E74,
/* Video Input Flags */
bmdDeckLinkConfigVideoInputScanning = /* 'visc' */ 0x76697363, // Applicable to H264 Pro Recorder only
bmdDeckLinkConfigUseDedicatedLTCInput = /* 'dltc' */ 0x646C7463, // Use timecode from LTC input instead of SDI stream
bmdDeckLinkConfigSDIInput3DPayloadOverride = /* '3dds' */ 0x33646473,
bmdDeckLinkConfigCapture1080pAsPsF = /* 'cfpr' */ 0x63667072,
/* Video Input Integers */
bmdDeckLinkConfigVideoInputConnection = /* 'vicn' */ 0x7669636E,
bmdDeckLinkConfigAnalogVideoInputFlags = /* 'avif' */ 0x61766966,
bmdDeckLinkConfigVideoInputConversionMode = /* 'vicm' */ 0x7669636D,
bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = /* 'pdif' */ 0x70646966,
bmdDeckLinkConfigVANCSourceLine1Mapping = /* 'vsl1' */ 0x76736C31,
bmdDeckLinkConfigVANCSourceLine2Mapping = /* 'vsl2' */ 0x76736C32,
bmdDeckLinkConfigVANCSourceLine3Mapping = /* 'vsl3' */ 0x76736C33,
bmdDeckLinkConfigCapturePassThroughMode = /* 'cptm' */ 0x6370746D,
bmdDeckLinkConfigCaptureGroup = /* 'cpgr' */ 0x63706772,
bmdDeckLinkConfigHANCInputFilter1 = /* 'hif1' */ 0x68696631,
bmdDeckLinkConfigHANCInputFilter2 = /* 'hif2' */ 0x68696632,
bmdDeckLinkConfigHANCInputFilter3 = /* 'hif3' */ 0x68696633,
bmdDeckLinkConfigHANCInputFilter4 = /* 'hif4' */ 0x68696634,
/* Video Input Floats */
bmdDeckLinkConfigVideoInputComponentLumaGain = /* 'iclg' */ 0x69636C67,
bmdDeckLinkConfigVideoInputComponentChromaBlueGain = /* 'iccb' */ 0x69636362,
bmdDeckLinkConfigVideoInputComponentChromaRedGain = /* 'iccr' */ 0x69636372,
bmdDeckLinkConfigVideoInputCompositeLumaGain = /* 'iilg' */ 0x69696C67,
bmdDeckLinkConfigVideoInputCompositeChromaGain = /* 'iicg' */ 0x69696367,
bmdDeckLinkConfigVideoInputSVideoLumaGain = /* 'islg' */ 0x69736C67,
bmdDeckLinkConfigVideoInputSVideoChromaGain = /* 'iscg' */ 0x69736367,
/* Keying Integers */
bmdDeckLinkConfigInternalKeyingAncillaryDataSource = /* 'ikas' */ 0x696B6173,
/* Audio Input Flags */
bmdDeckLinkConfigMicrophonePhantomPower = /* 'mphp' */ 0x6D706870,
/* Audio Input Integers */
bmdDeckLinkConfigAudioInputConnection = /* 'aicn' */ 0x6169636E,
/* Audio Input Floats */
bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = /* 'ais1' */ 0x61697331,
bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = /* 'ais2' */ 0x61697332,
bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = /* 'ais3' */ 0x61697333,
bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = /* 'ais4' */ 0x61697334,
bmdDeckLinkConfigDigitalAudioInputScale = /* 'dais' */ 0x64616973,
bmdDeckLinkConfigMicrophoneInputGain = /* 'micg' */ 0x6D696367,
bmdDeckLinkConfigAudioOutputXLRDelayFrames = /* 'xdfr' */ 0x78646672,
/* Audio Output Integers */
bmdDeckLinkConfigAudioOutputAESAnalogSwitch = /* 'aoaa' */ 0x616F6161,
bmdDeckLinkConfigAudioOutputXLRDelayTime = /* 'xdms' */ 0x78646D73,
bmdDeckLinkConfigAudioOutputXLRDelayType = /* 'xdty' */ 0x78647479,
/* Audio Output Floats */
bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = /* 'aos1' */ 0x616F7331,
bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = /* 'aos2' */ 0x616F7332,
bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = /* 'aos3' */ 0x616F7333,
bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = /* 'aos4' */ 0x616F7334,
bmdDeckLinkConfigDigitalAudioOutputScale = /* 'daos' */ 0x64616F73,
bmdDeckLinkConfigHeadphoneVolume = /* 'hvol' */ 0x68766F6C,
bmdDeckLinkConfigSpeakerVolume = /* 'svol' */ 0x73766F6C,
/* Ethernet Flags */
bmdDeckLinkConfigEthernetPTPFollowerOnly = /* 'PTPf' */ 0x50545066,
bmdDeckLinkConfigEthernetPTPUseUDPEncapsulation = /* 'PTPU' */ 0x50545055,
bmdDeckLinkConfigEthernetUseManualNMOSRegistry = /* 'nmrp' */ 0x6E6D7270,
/* Ethernet Integers */
bmdDeckLinkConfigEthernetPTPPriority1 = /* 'PTP1' */ 0x50545031,
bmdDeckLinkConfigEthernetPTPPriority2 = /* 'PTP2' */ 0x50545032,
bmdDeckLinkConfigEthernetPTPDomain = /* 'PTPD' */ 0x50545044,
bmdDeckLinkConfigEthernetPTPLogAnnounceInterval = /* 'PTPA' */ 0x50545041,
/* Ethernet Strings */
bmdDeckLinkConfigEthernetAudioOutputChannelOrder = /* 'caco' */ 0x6361636F,
bmdDeckLinkConfigEthernetNMOSRegistryAddress = /* 'nmre' */ 0x6E6D7265,
/* Parameterized Ethernet Flags */
bmdDeckLinkConfigParamEthernetUseDHCP = /* 'DHCP' */ 0x44484350,
/* Parameterized Ethernet Strings */
bmdDeckLinkConfigParamEthernetStaticLocalIPAddress = /* 'nsip' */ 0x6E736970,
bmdDeckLinkConfigParamEthernetStaticSubnetMask = /* 'nssm' */ 0x6E73736D,
bmdDeckLinkConfigParamEthernetStaticGatewayIPAddress = /* 'nsgw' */ 0x6E736777,
bmdDeckLinkConfigParamEthernetStaticPrimaryDNS = /* 'nspd' */ 0x6E737064,
bmdDeckLinkConfigParamEthernetStaticSecondaryDNS = /* 'nssd' */ 0x6E737364,
bmdDeckLinkConfigParamEthernetVideoOutputAddress = /* 'noav' */ 0x6E6F6176,
bmdDeckLinkConfigParamEthernetAudioOutputAddress = /* 'noaa' */ 0x6E6F6161,
bmdDeckLinkConfigParamEthernetAncillaryOutputAddress = /* 'noaA' */ 0x6E6F6141,
/* Device Information Strings */
bmdDeckLinkConfigDeviceInformationLabel = /* 'dila' */ 0x64696C61,
bmdDeckLinkConfigDeviceInformationSerialNumber = /* 'disn' */ 0x6469736E,
bmdDeckLinkConfigDeviceInformationCompany = /* 'dico' */ 0x6469636F,
bmdDeckLinkConfigDeviceInformationPhone = /* 'diph' */ 0x64697068,
bmdDeckLinkConfigDeviceInformationEmail = /* 'diem' */ 0x6469656D,
bmdDeckLinkConfigDeviceInformationDate = /* 'dida' */ 0x64696461,
/* Deck Control Integers */
bmdDeckLinkConfigDeckControlConnection = /* 'dcco' */ 0x6463636F,
/* UI/UX Integers */
bmdDeckLinkConfigDisplayLanguage = /* 'lang' */ 0x6C616E67
};
/* Enum BMDDeckLinkEncoderConfigurationID - DeckLink Encoder Configuration ID */
typedef uint32_t BMDDeckLinkEncoderConfigurationID;
enum _BMDDeckLinkEncoderConfigurationID {
/* Video Encoder Integers */
bmdDeckLinkEncoderConfigPreferredBitDepth = /* 'epbr' */ 0x65706272,
bmdDeckLinkEncoderConfigFrameCodingMode = /* 'efcm' */ 0x6566636D,
/* HEVC/H.265 Encoder Integers */
bmdDeckLinkEncoderConfigH265TargetBitrate = /* 'htbr' */ 0x68746272,
/* DNxHR/DNxHD Compression ID */
bmdDeckLinkEncoderConfigDNxHRCompressionID = /* 'dcid' */ 0x64636964,
/* DNxHR/DNxHD Level */
bmdDeckLinkEncoderConfigDNxHRLevel = /* 'dlev' */ 0x646C6576,
/* Encoded Sample Decriptions */
bmdDeckLinkEncoderConfigMPEG4SampleDescription = /* 'stsE' */ 0x73747345, // Full MPEG4 sample description (aka SampleEntry of an 'stsd' atom-box). Useful for MediaFoundation, QuickTime, MKV and more
bmdDeckLinkEncoderConfigMPEG4CodecSpecificDesc = /* 'esds' */ 0x65736473 // Sample description extensions only (atom stream, each with size and fourCC header). Useful for AVFoundation, VideoToolbox, MKV and more
};
#if defined(__cplusplus)
// Forward Declarations
class IDeckLinkConfiguration;
class IDeckLinkEncoderConfiguration;
/* Interface IDeckLinkConfiguration - DeckLink Configuration interface */
class BMD_PUBLIC IDeckLinkConfiguration : public IUnknown
{
public:
virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool* value) = 0;
virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t* value) = 0;
virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double* value) = 0;
virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char* value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char** value) = 0;
virtual HRESULT SetFlagWithParam (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ uint64_t param, /* in */ bool value) = 0;
virtual HRESULT GetFlagWithParam (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ uint64_t param, /* out */ bool* value) = 0;
virtual HRESULT SetIntWithParam (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ uint64_t param, /* in */ int64_t value) = 0;
virtual HRESULT GetIntWithParam (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ uint64_t param, /* out */ int64_t* value) = 0;
virtual HRESULT SetFloatWithParam (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ uint64_t param, /* in */ double value) = 0;
virtual HRESULT GetFloatWithParam (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ uint64_t param, /* out */ double* value) = 0;
virtual HRESULT SetStringWithParam (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ uint64_t param, /* in */ const char* value) = 0;
virtual HRESULT GetStringWithParam (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ uint64_t param, /* out */ const char** value) = 0;
virtual HRESULT WriteConfigurationToPreferences (void) = 0;
protected:
virtual ~IDeckLinkConfiguration () {} // call Release method to drop reference count
};
/* Interface IDeckLinkEncoderConfiguration - DeckLink Encoder Configuration interface. Obtained from IDeckLinkEncoderInput */
class BMD_PUBLIC IDeckLinkEncoderConfiguration : public IUnknown
{
public:
virtual HRESULT SetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ bool value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ bool* value) = 0;
virtual HRESULT SetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ int64_t value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ int64_t* value) = 0;
virtual HRESULT SetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ double value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ double* value) = 0;
virtual HRESULT SetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ const char* value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ const char** value) = 0;
virtual HRESULT GetBytes (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ void* buffer /* optional */, /* in, out */ uint32_t* bufferSize) = 0;
protected:
virtual ~IDeckLinkEncoderConfiguration () {} // call Release method to drop reference count
};
/* Functions */
extern "C" {
}
#endif /* defined(__cplusplus) */
#endif /* defined(BMD_DECKLINKAPICONFIGURATION_H) */

View file

@ -1,84 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2017 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPICONFIGURATION_v10_11_H
#define BMD_DECKLINKAPICONFIGURATION_v10_11_H
#include "DeckLinkAPIConfiguration.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkConfiguration_v10_11 = /* EF90380B-4AE5-4346-9077-E288E149F129 */ {0xEF,0x90,0x38,0x0B,0x4A,0xE5,0x43,0x46,0x90,0x77,0xE2,0x88,0xE1,0x49,0xF1,0x29};
/* Enum BMDDeckLinkConfigurationID_v10_11 - DeckLink Configuration ID */
typedef uint32_t BMDDeckLinkConfigurationID_v10_11;
enum _BMDDeckLinkConfigurationID_v10_11 {
/* Video Input/Output Integers */
bmdDeckLinkConfigDuplexMode_v10_11 = /* 'dupx' */ 0x64757078,
};
// Forward Declarations
class IDeckLinkConfiguration_v10_11;
/* Interface IDeckLinkConfiguration_v10_11 - DeckLink Configuration interface */
class BMD_PUBLIC IDeckLinkConfiguration_v10_11 : public IUnknown
{
public:
virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0;
virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0;
virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0;
virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0;
virtual HRESULT WriteConfigurationToPreferences (void) = 0;
protected:
virtual ~IDeckLinkConfiguration_v10_11 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPICONFIGURATION_v10_11_H) */

View file

@ -1,73 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2014 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPICONFIGURATION_v10_2_H
#define BMD_DECKLINKAPICONFIGURATION_v10_2_H
#include "DeckLinkAPIConfiguration.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkConfiguration_v10_2 = /* C679A35B-610C-4D09-B748-1D0478100FC0 */ {0xC6,0x79,0xA3,0x5B,0x61,0x0C,0x4D,0x09,0xB7,0x48,0x1D,0x04,0x78,0x10,0x0F,0xC0};
// Forward Declarations
class IDeckLinkConfiguration_v10_2;
/* Interface IDeckLinkConfiguration_v10_2 - DeckLink Configuration interface */
class BMD_PUBLIC IDeckLinkConfiguration_v10_2 : public IUnknown
{
public:
virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0;
virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0;
virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0;
virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0;
virtual HRESULT WriteConfigurationToPreferences (void) = 0;
protected:
virtual ~IDeckLinkConfiguration_v10_2 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPICONFIGURATION_v10_2_H) */

View file

@ -1,76 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2015 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPICONFIGURATION_v10_4_H
#define BMD_DECKLINKAPICONFIGURATION_v10_4_H
#include "DeckLinkAPIConfiguration.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkConfiguration_v10_4 = /* 1E69FCF6-4203-4936-8076-2A9F4CFD50CB */ {0x1E,0x69,0xFC,0xF6,0x42,0x03,0x49,0x36,0x80,0x76,0x2A,0x9F,0x4C,0xFD,0x50,0xCB};
//
// Forward Declarations
class IDeckLinkConfiguration_v10_4;
/* Interface IDeckLinkConfiguration_v10_4 - DeckLink Configuration interface */
class BMD_PUBLIC IDeckLinkConfiguration_v10_4 : public IUnknown
{
public:
virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0;
virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0;
virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0;
virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0;
virtual HRESULT WriteConfigurationToPreferences (void) = 0;
protected:
virtual ~IDeckLinkConfiguration_v10_4 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPICONFIGURATION_v10_4_H) */

View file

@ -1,73 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2015 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPICONFIGURATION_v10_5_H
#define BMD_DECKLINKAPICONFIGURATION_v10_5_H
#include "DeckLinkAPIConfiguration.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkEncoderConfiguration_v10_5 = /* 67455668-0848-45DF-8D8E-350A77C9A028 */ {0x67,0x45,0x56,0x68,0x08,0x48,0x45,0xDF,0x8D,0x8E,0x35,0x0A,0x77,0xC9,0xA0,0x28};
// Forward Declarations
class IDeckLinkEncoderConfiguration_v10_5;
/* Interface IDeckLinkEncoderConfiguration_v10_5 - DeckLink Encoder Configuration interface. Obtained from IDeckLinkEncoderInput */
class BMD_PUBLIC IDeckLinkEncoderConfiguration_v10_5 : public IUnknown
{
public:
virtual HRESULT SetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ bool value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ bool *value) = 0;
virtual HRESULT SetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ int64_t value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ int64_t *value) = 0;
virtual HRESULT SetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ double value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ double *value) = 0;
virtual HRESULT SetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* in */ const char *value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkEncoderConfigurationID cfgID, /* out */ const char **value) = 0;
virtual HRESULT GetDecoderConfigurationInfo (/* out */ void *buffer, /* in */ long bufferSize, /* out */ long *returnedSize) = 0;
protected:
virtual ~IDeckLinkEncoderConfiguration_v10_5 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPICONFIGURATION_v10_5_H) */

View file

@ -1,75 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2017 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPICONFIGURATION_v10_9_H
#define BMD_DECKLINKAPICONFIGURATION_v10_9_H
#include "DeckLinkAPIConfiguration.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkConfiguration_v10_9 = /* CB71734A-FE37-4E8D-8E13-802133A1C3F2 */ {0xCB,0x71,0x73,0x4A,0xFE,0x37,0x4E,0x8D,0x8E,0x13,0x80,0x21,0x33,0xA1,0xC3,0xF2};
//
// Forward Declarations
class IDeckLinkConfiguration_v10_9;
/* Interface IDeckLinkConfiguration_v10_9 - DeckLink Configuration interface */
class BMD_PUBLIC IDeckLinkConfiguration_v10_9 : public IUnknown
{
public:
virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0;
virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0;
virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0;
virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0;
virtual HRESULT WriteConfigurationToPreferences (void) = 0;
protected:
virtual ~IDeckLinkConfiguration_v10_9 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPICONFIGURATION_v10_9_H) */

View file

@ -1,84 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2026 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#pragma once
#include "DeckLinkAPIConfiguration.h"
/* Enum BMDDeckLinkConfigurationID_v15_3_1 - DeckLink Configuration ID */
typedef uint32_t BMDDeckLinkConfigurationID_v15_3_1;
enum _BMDDeckLinkConfigurationID_v15_3_1
{
/* Network Flags */
bmdDeckLinkConfigEthernetUseDHCP_v15_3_1 = /* 'DHCP' */ 0x44484350,
/* Network Strings */
bmdDeckLinkConfigEthernetStaticLocalIPAddress_v15_3_1 = /* 'nsip' */ 0x6E736970,
bmdDeckLinkConfigEthernetStaticSubnetMask_v15_3_1 = /* 'nssm' */ 0x6E73736D,
bmdDeckLinkConfigEthernetStaticGatewayIPAddress_v15_3_1 = /* 'nsgw' */ 0x6E736777,
bmdDeckLinkConfigEthernetStaticPrimaryDNS_v15_3_1 = /* 'nspd' */ 0x6E737064,
bmdDeckLinkConfigEthernetStaticSecondaryDNS_v15_3_1 = /* 'nssd' */ 0x6E737364,
bmdDeckLinkConfigEthernetVideoOutputAddress_v15_3_1 = /* 'noav' */ 0x6E6F6176,
bmdDeckLinkConfigEthernetAudioOutputAddress_v15_3_1 = /* 'noaa' */ 0x6E6F6161,
bmdDeckLinkConfigEthernetAncillaryOutputAddress_v15_3_1 = /* 'noaA' */ 0x6E6F6141,
};
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkConfiguration_v15_3_1 = /* 912F634B-2D4E-40A4-8AAB-8D80B73F1289 */ {0x91,0x2F,0x63,0x4B,0x2D,0x4E,0x40,0xA4,0x8A,0xAB,0x8D,0x80,0xB7,0x3F,0x12,0x89};
/* Interface IDeckLinkConfiguration_v15_3_1 - DeckLink Configuration interface */
class IDeckLinkConfiguration_v15_3_1 : public IUnknown
{
public:
virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0;
virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0;
virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0;
virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char* value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char* *value) = 0;
virtual HRESULT WriteConfigurationToPreferences (void) = 0;
protected:
virtual ~IDeckLinkConfiguration_v15_3_1 () {} // call Release method to drop reference count
};

View file

@ -1,227 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2026 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation covered by
** this license (the "Software") to use, reproduce, display, distribute,
** execute, and transmit the Software, and to prepare derivative works of the
** Software, and to permit third-parties to whom the Software is furnished to
** do so, all subject to the following:
**
** The copyright notices in the Software and this entire statement, including
** the above license grant, this restriction and the following disclaimer,
** must be included in all copies of the Software, in whole or in part, and
** all derivative works of the Software, unless such copies or derivative
** works are solely in the form of machine-executable object code generated by
** a source language processor.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
** -LICENSE-END-
*/
/*
* -- AUTOMATICALLY GENERATED - DO NOT EDIT ---
*/
#ifndef BMD_DECKLINKAPIDECKCONTROL_H
#define BMD_DECKLINKAPIDECKCONTROL_H
#ifndef BMD_CONST
#if defined(_MSC_VER)
#define BMD_CONST __declspec(selectany) static const
#else
#define BMD_CONST static const
#endif
#endif
#ifndef BMD_PUBLIC
#define BMD_PUBLIC
#endif
// Type Declarations
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkDeckControlStatusCallback = /* 53436FFB-B434-4906-BADC-AE3060FFE8EF */ { 0x53,0x43,0x6F,0xFB,0xB4,0x34,0x49,0x06,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF };
BMD_CONST REFIID IID_IDeckLinkDeckControl = /* 8E1C3ACE-19C7-4E00-8B92-D80431D958BE */ { 0x8E,0x1C,0x3A,0xCE,0x19,0xC7,0x4E,0x00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE };
/* Enum BMDDeckControlMode - DeckControl mode */
typedef uint32_t BMDDeckControlMode;
enum _BMDDeckControlMode {
bmdDeckControlNotOpened = /* 'ntop' */ 0x6E746F70,
bmdDeckControlVTRControlMode = /* 'vtrc' */ 0x76747263,
bmdDeckControlExportMode = /* 'expm' */ 0x6578706D,
bmdDeckControlCaptureMode = /* 'capm' */ 0x6361706D
};
/* Enum BMDDeckControlEvent - DeckControl event */
typedef uint32_t BMDDeckControlEvent;
enum _BMDDeckControlEvent {
bmdDeckControlAbortedEvent = /* 'abte' */ 0x61627465, // This event is triggered when a capture or edit-to-tape operation is aborted.
/* Export-To-Tape events */
bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback should be called at this point.
bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. Upon reception of this event the deck's control mode is set back to bmdDeckControlVTRControlMode.
/* Capture events */
bmdDeckControlPrepareForCaptureEvent = /* 'pfce' */ 0x70666365, // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid.
bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. Upon reception of this event the deck's control mode is set back to bmdDeckControlVTRControlMode.
};
/* Enum BMDDeckControlVTRControlState - VTR Control state */
typedef uint32_t BMDDeckControlVTRControlState;
enum _BMDDeckControlVTRControlState {
bmdDeckControlNotInVTRControlMode = /* 'nvcm' */ 0x6E76636D,
bmdDeckControlVTRControlPlaying = /* 'vtrp' */ 0x76747270,
bmdDeckControlVTRControlRecording = /* 'vtrr' */ 0x76747272,
bmdDeckControlVTRControlStill = /* 'vtra' */ 0x76747261,
bmdDeckControlVTRControlShuttleForward = /* 'vtsf' */ 0x76747366,
bmdDeckControlVTRControlShuttleReverse = /* 'vtsr' */ 0x76747372,
bmdDeckControlVTRControlJogForward = /* 'vtjf' */ 0x76746A66,
bmdDeckControlVTRControlJogReverse = /* 'vtjr' */ 0x76746A72,
bmdDeckControlVTRControlStopped = /* 'vtro' */ 0x7674726F
};
/* Enum BMDDeckControlStatusFlags - Deck Control status flags */
typedef uint32_t BMDDeckControlStatusFlags;
enum _BMDDeckControlStatusFlags {
bmdDeckControlStatusDeckConnected = 1 << 0,
bmdDeckControlStatusRemoteMode = 1 << 1,
bmdDeckControlStatusRecordInhibited = 1 << 2,
bmdDeckControlStatusCassetteOut = 1 << 3
};
/* Enum BMDDeckControlExportModeOpsFlags - Export mode flags */
typedef uint32_t BMDDeckControlExportModeOpsFlags;
enum _BMDDeckControlExportModeOpsFlags {
bmdDeckControlExportModeInsertVideo = 1 << 0,
bmdDeckControlExportModeInsertAudio1 = 1 << 1,
bmdDeckControlExportModeInsertAudio2 = 1 << 2,
bmdDeckControlExportModeInsertAudio3 = 1 << 3,
bmdDeckControlExportModeInsertAudio4 = 1 << 4,
bmdDeckControlExportModeInsertAudio5 = 1 << 5,
bmdDeckControlExportModeInsertAudio6 = 1 << 6,
bmdDeckControlExportModeInsertAudio7 = 1 << 7,
bmdDeckControlExportModeInsertAudio8 = 1 << 8,
bmdDeckControlExportModeInsertAudio9 = 1 << 9,
bmdDeckControlExportModeInsertAudio10 = 1 << 10,
bmdDeckControlExportModeInsertAudio11 = 1 << 11,
bmdDeckControlExportModeInsertAudio12 = 1 << 12,
bmdDeckControlExportModeInsertTimeCode = 1 << 13,
bmdDeckControlExportModeInsertAssemble = 1 << 14,
bmdDeckControlExportModeInsertPreview = 1 << 15,
bmdDeckControlUseManualExport = 1 << 16
};
/* Enum BMDDeckControlError - Deck Control error */
typedef uint32_t BMDDeckControlError;
enum _BMDDeckControlError {
bmdDeckControlNoError = /* 'noer' */ 0x6E6F6572,
bmdDeckControlModeError = /* 'moer' */ 0x6D6F6572,
bmdDeckControlMissedInPointError = /* 'mier' */ 0x6D696572,
bmdDeckControlDeckTimeoutError = /* 'dter' */ 0x64746572,
bmdDeckControlCommandFailedError = /* 'cfer' */ 0x63666572,
bmdDeckControlDeviceAlreadyOpenedError = /* 'dalo' */ 0x64616C6F,
bmdDeckControlFailedToOpenDeviceError = /* 'fder' */ 0x66646572,
bmdDeckControlInLocalModeError = /* 'lmer' */ 0x6C6D6572,
bmdDeckControlEndOfTapeError = /* 'eter' */ 0x65746572,
bmdDeckControlUserAbortError = /* 'uaer' */ 0x75616572,
bmdDeckControlNoTapeInDeckError = /* 'nter' */ 0x6E746572,
bmdDeckControlNoVideoFromCardError = /* 'nvfc' */ 0x6E766663,
bmdDeckControlNoCommunicationError = /* 'ncom' */ 0x6E636F6D,
bmdDeckControlBufferTooSmallError = /* 'btsm' */ 0x6274736D,
bmdDeckControlBadChecksumError = /* 'chks' */ 0x63686B73,
bmdDeckControlUnknownError = /* 'uner' */ 0x756E6572
};
#if defined(__cplusplus)
// Forward Declarations
class IDeckLinkDeckControlStatusCallback;
class IDeckLinkDeckControl;
/* Interface IDeckLinkDeckControlStatusCallback - Deck control state change callback. */
class BMD_PUBLIC IDeckLinkDeckControlStatusCallback : public IUnknown
{
public:
virtual HRESULT TimecodeUpdate (/* in */ BMDTimecodeBCD currentTimecode) = 0;
virtual HRESULT VTRControlStateChanged (/* in */ BMDDeckControlVTRControlState newState, /* in */ BMDDeckControlError error) = 0;
virtual HRESULT DeckControlEventReceived (/* in */ BMDDeckControlEvent event, /* in */ BMDDeckControlError error) = 0;
virtual HRESULT DeckControlStatusChanged (/* in */ BMDDeckControlStatusFlags flags, /* in */ uint32_t mask) = 0;
protected:
virtual ~IDeckLinkDeckControlStatusCallback () {} // call Release method to drop reference count
};
/* Interface IDeckLinkDeckControl - Deck Control main interface */
class BMD_PUBLIC IDeckLinkDeckControl : public IUnknown
{
public:
virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT Close (/* in */ bool standbyOn) = 0;
virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode* mode, /* out */ BMDDeckControlVTRControlState* vtrControlState, /* out */ BMDDeckControlStatusFlags* flags) = 0;
virtual HRESULT SetStandby (/* in */ bool standbyOn) = 0;
virtual HRESULT SendCommand (/* in */ uint8_t* inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t* outBuffer, /* out */ uint32_t* outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT Play (/* out */ BMDDeckControlError* error) = 0;
virtual HRESULT Stop (/* out */ BMDDeckControlError* error) = 0;
virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError* error) = 0;
virtual HRESULT Eject (/* out */ BMDDeckControlError* error) = 0;
virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT StepForward (/* out */ BMDDeckControlError* error) = 0;
virtual HRESULT StepBack (/* out */ BMDDeckControlError* error) = 0;
virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT GetTimecodeString (/* out */ const char** currentTimeCode, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode** currentTimecode, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD* currentTimecode, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT SetPreroll (/* in */ uint32_t prerollSeconds) = 0;
virtual HRESULT GetPreroll (/* out */ uint32_t* prerollSeconds) = 0;
virtual HRESULT SetExportOffset (/* in */ int32_t exportOffsetFields) = 0;
virtual HRESULT GetExportOffset (/* out */ int32_t* exportOffsetFields) = 0;
virtual HRESULT GetManualExportOffset (/* out */ int32_t* deckManualExportOffsetFields) = 0;
virtual HRESULT SetCaptureOffset (/* in */ int32_t captureOffsetFields) = 0;
virtual HRESULT GetCaptureOffset (/* out */ int32_t* captureOffsetFields) = 0;
virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT GetDeviceID (/* out */ uint16_t* deviceId, /* out */ BMDDeckControlError* error) = 0;
virtual HRESULT Abort (void) = 0;
virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError* error) = 0;
virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError* error) = 0;
virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback* callback) = 0;
protected:
virtual ~IDeckLinkDeckControl () {} // call Release method to drop reference count
};
/* Functions */
extern "C" {
}
#endif /* defined(__cplusplus) */
#endif /* defined(BMD_DECKLINKAPIDECKCONTROL_H) */

View file

@ -1,83 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2026 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation covered by
** this license (the "Software") to use, reproduce, display, distribute,
** execute, and transmit the Software, and to prepare derivative works of the
** Software, and to permit third-parties to whom the Software is furnished to
** do so, all subject to the following:
**
** The copyright notices in the Software and this entire statement, including
** the above license grant, this restriction and the following disclaimer,
** must be included in all copies of the Software, in whole or in part, and
** all derivative works of the Software, unless such copies or derivative
** works are solely in the form of machine-executable object code generated by
** a source language processor.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
** -LICENSE-END-
*/
/*
* -- AUTOMATICALLY GENERATED - DO NOT EDIT ---
*/
#ifndef BMD_DECKLINKAPIDISCOVERY_H
#define BMD_DECKLINKAPIDISCOVERY_H
#ifndef BMD_CONST
#if defined(_MSC_VER)
#define BMD_CONST __declspec(selectany) static const
#else
#define BMD_CONST static const
#endif
#endif
#ifndef BMD_PUBLIC
#define BMD_PUBLIC
#endif
// Type Declarations
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLink = /* C418FBDD-0587-48ED-8FE5-640F0A14AF91 */ { 0xC4,0x18,0xFB,0xDD,0x05,0x87,0x48,0xED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91 };
#if defined(__cplusplus)
// Forward Declarations
class IDeckLink;
/* Interface IDeckLink - Represents a DeckLink device */
class BMD_PUBLIC IDeckLink : public IUnknown
{
public:
virtual HRESULT GetModelName (/* out */ const char** modelName) = 0;
virtual HRESULT GetDisplayName (/* out */ const char** displayName) = 0;
protected:
virtual ~IDeckLink () {} // call Release method to drop reference count
};
/* Functions */
extern "C" {
}
#endif /* defined(__cplusplus) */
#endif /* defined(BMD_DECKLINKAPIDISCOVERY_H) */

View file

@ -1,188 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2009 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
**/
#include <stdio.h>
#include <pthread.h>
#include <dlfcn.h>
#include "DeckLinkAPI.h"
#define kDeckLinkAPI_Name "libDeckLinkAPI.so"
#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so"
typedef IDeckLinkIterator* (*CreateIteratorFunc)(void);
typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGL3ScreenPreviewHelperFunc)(void);
typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void);
typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void);
typedef IDeckLinkVideoFrameAncillaryPackets* (*CreateVideoFrameAncillaryPacketsInstanceFunc)(void);
static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT;
static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT;
static bool gLoadedDeckLinkAPI = false;
static CreateIteratorFunc gCreateIteratorFunc = NULL;
static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL;
static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL;
static CreateOpenGL3ScreenPreviewHelperFunc gCreateOpenGL3PreviewFunc = NULL;
static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL;
static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL;
static CreateVideoFrameAncillaryPacketsInstanceFunc gCreateVideoFrameAncillaryPacketsFunc = NULL;
static void InitDeckLinkAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gLoadedDeckLinkAPI = true;
gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0004");
if (!gCreateIteratorFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001");
if (!gCreateAPIInformationFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0003");
if (!gCreateVideoConversionFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0003");
if (!gCreateDeckLinkDiscoveryFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)dlsym(libraryHandle, "CreateVideoFrameAncillaryPacketsInstance_0002");
if (!gCreateVideoFrameAncillaryPacketsFunc)
fprintf(stderr, "%s\n", dlerror());
}
static void InitDeckLinkPreviewAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0002");
if (!gCreateOpenGLPreviewFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateOpenGL3PreviewFunc = (CreateOpenGL3ScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGL3ScreenPreviewHelper_0002");
if (!gCreateOpenGL3PreviewFunc)
fprintf(stderr, "%s\n", dlerror());
}
bool IsDeckLinkAPIPresent (void)
{
// If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller
return gLoadedDeckLinkAPI;
}
IDeckLinkIterator* CreateDeckLinkIteratorInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateIteratorFunc == NULL)
return NULL;
return gCreateIteratorFunc();
}
IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateAPIInformationFunc == NULL)
return NULL;
return gCreateAPIInformationFunc();
}
IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGLPreviewFunc == NULL)
return NULL;
return gCreateOpenGLPreviewFunc();
}
IDeckLinkGLScreenPreviewHelper* CreateOpenGL3ScreenPreviewHelper (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGL3PreviewFunc == NULL)
return NULL;
return gCreateOpenGL3PreviewFunc();
}
IDeckLinkVideoConversion* CreateVideoConversionInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoConversionFunc == NULL)
return NULL;
return gCreateVideoConversionFunc();
}
IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateDeckLinkDiscoveryFunc == NULL)
return NULL;
return gCreateDeckLinkDiscoveryFunc();
}
IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoFrameAncillaryPacketsFunc == NULL)
return NULL;
return gCreateVideoFrameAncillaryPacketsFunc();
}

View file

@ -1,173 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2019 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
**/
#include <stdio.h>
#include <pthread.h>
#include <dlfcn.h>
#include "DeckLinkAPI_v10_11.h"
#define kDeckLinkAPI_Name "libDeckLinkAPI.so"
#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so"
typedef IDeckLinkIterator* (*CreateIteratorFunc)(void);
typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void);
typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void);
typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void);
typedef IDeckLinkVideoFrameAncillaryPackets* (*CreateVideoFrameAncillaryPacketsInstanceFunc)(void);
static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT;
static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT;
static bool gLoadedDeckLinkAPI = false;
static CreateIteratorFunc gCreateIteratorFunc = NULL;
static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL;
static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL;
static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL;
static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL;
static CreateVideoFrameAncillaryPacketsInstanceFunc gCreateVideoFrameAncillaryPacketsFunc = NULL;
static void InitDeckLinkAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gLoadedDeckLinkAPI = true;
gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0003");
if (!gCreateIteratorFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001");
if (!gCreateAPIInformationFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001");
if (!gCreateVideoConversionFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0002");
if (!gCreateDeckLinkDiscoveryFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)dlsym(libraryHandle, "CreateVideoFrameAncillaryPacketsInstance_0001");
if (!gCreateVideoFrameAncillaryPacketsFunc)
fprintf(stderr, "%s\n", dlerror());
}
static void InitDeckLinkPreviewAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0001");
if (!gCreateOpenGLPreviewFunc)
fprintf(stderr, "%s\n", dlerror());
}
bool IsDeckLinkAPIPresent_v10_11 (void)
{
// If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller
return gLoadedDeckLinkAPI;
}
IDeckLinkIterator* CreateDeckLinkIteratorInstance_v10_11 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateIteratorFunc == NULL)
return NULL;
return gCreateIteratorFunc();
}
IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance_v10_11 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateAPIInformationFunc == NULL)
return NULL;
return gCreateAPIInformationFunc();
}
IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper_v10_11 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGLPreviewFunc == NULL)
return NULL;
return gCreateOpenGLPreviewFunc();
}
IDeckLinkVideoConversion* CreateVideoConversionInstance_v10_11 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoConversionFunc == NULL)
return NULL;
return gCreateVideoConversionFunc();
}
IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance_v10_11 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateDeckLinkDiscoveryFunc == NULL)
return NULL;
return gCreateDeckLinkDiscoveryFunc();
}
IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance_v10_11 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoFrameAncillaryPacketsFunc == NULL)
return NULL;
return gCreateVideoFrameAncillaryPacketsFunc();
}

View file

@ -1,159 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2009 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
**/
#include <stdio.h>
#include <pthread.h>
#include <dlfcn.h>
#include "DeckLinkAPI.h"
#define kDeckLinkAPI_Name "libDeckLinkAPI.so"
#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so"
typedef IDeckLinkIterator* (*CreateIteratorFunc)(void);
typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void);
typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void);
typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void);
static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT;
static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT;
static bool gLoadedDeckLinkAPI = false;
static CreateIteratorFunc gCreateIteratorFunc = NULL;
static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL;
static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL;
static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL;
static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL;
static void InitDeckLinkAPI(void)
{
void *libraryHandle;
libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW | RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gLoadedDeckLinkAPI = true;
gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0002");
if (!gCreateIteratorFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001");
if (!gCreateAPIInformationFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001");
if (!gCreateVideoConversionFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0001");
if (!gCreateDeckLinkDiscoveryFunc)
fprintf(stderr, "%s\n", dlerror());
}
static void InitDeckLinkPreviewAPI(void)
{
void *libraryHandle;
libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW | RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0001");
if (!gCreateOpenGLPreviewFunc)
fprintf(stderr, "%s\n", dlerror());
}
bool IsDeckLinkAPIPresent(void)
{
// If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller
return gLoadedDeckLinkAPI;
}
IDeckLinkIterator* CreateDeckLinkIteratorInstance(void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateIteratorFunc == NULL)
return NULL;
return gCreateIteratorFunc();
}
IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance(void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateAPIInformationFunc == NULL)
return NULL;
return gCreateAPIInformationFunc();
}
IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper(void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGLPreviewFunc == NULL)
return NULL;
return gCreateOpenGLPreviewFunc();
}
IDeckLinkVideoConversion* CreateVideoConversionInstance(void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoConversionFunc == NULL)
return NULL;
return gCreateVideoConversionFunc();
}
IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance(void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateDeckLinkDiscoveryFunc == NULL)
return NULL;
return gCreateDeckLinkDiscoveryFunc();
}

View file

@ -1,188 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2009 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
**/
#include <stdio.h>
#include <pthread.h>
#include <dlfcn.h>
#include "DeckLinkAPI_v14_2_1.h"
#define kDeckLinkAPI_Name "libDeckLinkAPI.so"
#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so"
typedef IDeckLinkIterator* (*CreateIteratorFunc)(void);
typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper_v14_2_1* (*CreateOpenGLScreenPreviewHelperFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper_v14_2_1* (*CreateOpenGL3ScreenPreviewHelperFunc)(void);
typedef IDeckLinkVideoConversion_v14_2_1* (*CreateVideoConversionInstanceFunc)(void);
typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void);
typedef IDeckLinkVideoFrameAncillaryPackets* (*CreateVideoFrameAncillaryPacketsInstanceFunc)(void);
static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT;
static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT;
static bool gLoadedDeckLinkAPI = false;
static CreateIteratorFunc gCreateIteratorFunc = NULL;
static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL;
static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL;
static CreateOpenGL3ScreenPreviewHelperFunc gCreateOpenGL3PreviewFunc = NULL;
static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL;
static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL;
static CreateVideoFrameAncillaryPacketsInstanceFunc gCreateVideoFrameAncillaryPacketsFunc = NULL;
static void InitDeckLinkAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gLoadedDeckLinkAPI = true;
gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0004");
if (!gCreateIteratorFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001");
if (!gCreateAPIInformationFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001");
if (!gCreateVideoConversionFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0003");
if (!gCreateDeckLinkDiscoveryFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)dlsym(libraryHandle, "CreateVideoFrameAncillaryPacketsInstance_0001");
if (!gCreateVideoFrameAncillaryPacketsFunc)
fprintf(stderr, "%s\n", dlerror());
}
static void InitDeckLinkPreviewAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0001");
if (!gCreateOpenGLPreviewFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateOpenGL3PreviewFunc = (CreateOpenGL3ScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGL3ScreenPreviewHelper_0001");
if (!gCreateOpenGL3PreviewFunc)
fprintf(stderr, "%s\n", dlerror());
}
bool IsDeckLinkAPIPresent_v14_2_1 (void)
{
// If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller
return gLoadedDeckLinkAPI;
}
IDeckLinkIterator* CreateDeckLinkIteratorInstance_v14_2_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateIteratorFunc == NULL)
return NULL;
return gCreateIteratorFunc();
}
IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance_v14_2_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateAPIInformationFunc == NULL)
return NULL;
return gCreateAPIInformationFunc();
}
IDeckLinkGLScreenPreviewHelper_v14_2_1* CreateOpenGLScreenPreviewHelper_v14_2_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGLPreviewFunc == NULL)
return NULL;
return gCreateOpenGLPreviewFunc();
}
IDeckLinkGLScreenPreviewHelper_v14_2_1* CreateOpenGL3ScreenPreviewHelper_v14_2_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGL3PreviewFunc == NULL)
return NULL;
return gCreateOpenGL3PreviewFunc();
}
IDeckLinkVideoConversion_v14_2_1* CreateVideoConversionInstance_v14_2_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoConversionFunc == NULL)
return NULL;
return gCreateVideoConversionFunc();
}
IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance_v14_2_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateDeckLinkDiscoveryFunc == NULL)
return NULL;
return gCreateDeckLinkDiscoveryFunc();
}
IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance_v14_2_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoFrameAncillaryPacketsFunc == NULL)
return NULL;
return gCreateVideoFrameAncillaryPacketsFunc();
}

View file

@ -1,188 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2009 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
**/
#include <stdio.h>
#include <pthread.h>
#include <dlfcn.h>
#include "DeckLinkAPI_v15_2.h"
#define kDeckLinkAPI_Name "libDeckLinkAPI.so"
#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so"
typedef IDeckLinkIterator* (*CreateIteratorFunc)(void);
typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGL3ScreenPreviewHelperFunc)(void);
typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void);
typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void);
typedef IDeckLinkVideoFrameAncillaryPackets_v15_2* (*CreateVideoFrameAncillaryPacketsInstanceFunc)(void);
static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT;
static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT;
static bool gLoadedDeckLinkAPI = false;
static CreateIteratorFunc gCreateIteratorFunc = NULL;
static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL;
static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL;
static CreateOpenGL3ScreenPreviewHelperFunc gCreateOpenGL3PreviewFunc = NULL;
static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL;
static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL;
static CreateVideoFrameAncillaryPacketsInstanceFunc gCreateVideoFrameAncillaryPacketsFunc = NULL;
static void InitDeckLinkAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gLoadedDeckLinkAPI = true;
gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0004");
if (!gCreateIteratorFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001");
if (!gCreateAPIInformationFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0002");
if (!gCreateVideoConversionFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0003");
if (!gCreateDeckLinkDiscoveryFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)dlsym(libraryHandle, "CreateVideoFrameAncillaryPacketsInstance_0001");
if (!gCreateVideoFrameAncillaryPacketsFunc)
fprintf(stderr, "%s\n", dlerror());
}
static void InitDeckLinkPreviewAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0002");
if (!gCreateOpenGLPreviewFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateOpenGL3PreviewFunc = (CreateOpenGL3ScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGL3ScreenPreviewHelper_0002");
if (!gCreateOpenGL3PreviewFunc)
fprintf(stderr, "%s\n", dlerror());
}
bool IsDeckLinkAPIPresent_v15_2 (void)
{
// If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller
return gLoadedDeckLinkAPI;
}
IDeckLinkIterator* CreateDeckLinkIteratorInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateIteratorFunc == NULL)
return NULL;
return gCreateIteratorFunc();
}
IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateAPIInformationFunc == NULL)
return NULL;
return gCreateAPIInformationFunc();
}
IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGLPreviewFunc == NULL)
return NULL;
return gCreateOpenGLPreviewFunc();
}
IDeckLinkGLScreenPreviewHelper* CreateOpenGL3ScreenPreviewHelper (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGL3PreviewFunc == NULL)
return NULL;
return gCreateOpenGL3PreviewFunc();
}
IDeckLinkVideoConversion* CreateVideoConversionInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoConversionFunc == NULL)
return NULL;
return gCreateVideoConversionFunc();
}
IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateDeckLinkDiscoveryFunc == NULL)
return NULL;
return gCreateDeckLinkDiscoveryFunc();
}
IDeckLinkVideoFrameAncillaryPackets_v15_2* CreateVideoFrameAncillaryPacketsInstance_v15_2 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoFrameAncillaryPacketsFunc == NULL)
return NULL;
return gCreateVideoFrameAncillaryPacketsFunc();
}

View file

@ -1,188 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2009 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
**/
#include <stdio.h>
#include <pthread.h>
#include <dlfcn.h>
#include "DeckLinkAPI_v15_3_1.h"
#define kDeckLinkAPI_Name "libDeckLinkAPI.so"
#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so"
typedef IDeckLinkIterator* (*CreateIteratorFunc)(void);
typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void);
typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGL3ScreenPreviewHelperFunc)(void);
typedef IDeckLinkVideoConversion_v15_3_1* (*CreateVideoConversionInstanceFunc)(void);
typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void);
typedef IDeckLinkVideoFrameAncillaryPackets* (*CreateVideoFrameAncillaryPacketsInstanceFunc)(void);
static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT;
static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT;
static bool gLoadedDeckLinkAPI = false;
static CreateIteratorFunc gCreateIteratorFunc = NULL;
static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL;
static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL;
static CreateOpenGL3ScreenPreviewHelperFunc gCreateOpenGL3PreviewFunc = NULL;
static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL;
static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL;
static CreateVideoFrameAncillaryPacketsInstanceFunc gCreateVideoFrameAncillaryPacketsFunc = NULL;
static void InitDeckLinkAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gLoadedDeckLinkAPI = true;
gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0004");
if (!gCreateIteratorFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001");
if (!gCreateAPIInformationFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0002");
if (!gCreateVideoConversionFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0003");
if (!gCreateDeckLinkDiscoveryFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateVideoFrameAncillaryPacketsFunc = (CreateVideoFrameAncillaryPacketsInstanceFunc)dlsym(libraryHandle, "CreateVideoFrameAncillaryPacketsInstance_0001");
if (!gCreateVideoFrameAncillaryPacketsFunc)
fprintf(stderr, "%s\n", dlerror());
}
static void InitDeckLinkPreviewAPI (void)
{
void *libraryHandle;
libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL);
if (!libraryHandle)
{
fprintf(stderr, "%s\n", dlerror());
return;
}
gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0002");
if (!gCreateOpenGLPreviewFunc)
fprintf(stderr, "%s\n", dlerror());
gCreateOpenGL3PreviewFunc = (CreateOpenGL3ScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGL3ScreenPreviewHelper_0002");
if (!gCreateOpenGL3PreviewFunc)
fprintf(stderr, "%s\n", dlerror());
}
bool IsDeckLinkAPIPresent (void)
{
// If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller
return gLoadedDeckLinkAPI;
}
IDeckLinkIterator* CreateDeckLinkIteratorInstance_v15_3_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateIteratorFunc == NULL)
return NULL;
return gCreateIteratorFunc();
}
IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance_v15_3_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateAPIInformationFunc == NULL)
return NULL;
return gCreateAPIInformationFunc();
}
IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper_v15_3_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGLPreviewFunc == NULL)
return NULL;
return gCreateOpenGLPreviewFunc();
}
IDeckLinkGLScreenPreviewHelper* CreateOpenGL3ScreenPreviewHelper_v15_3_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
if (gCreateOpenGL3PreviewFunc == NULL)
return NULL;
return gCreateOpenGL3PreviewFunc();
}
IDeckLinkVideoConversion_v15_3_1* CreateVideoConversionInstance_v15_3_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoConversionFunc == NULL)
return NULL;
return gCreateVideoConversionFunc();
}
IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance_v15_3_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateDeckLinkDiscoveryFunc == NULL)
return NULL;
return gCreateDeckLinkDiscoveryFunc();
}
IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance_v15_3_1 (void)
{
pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
if (gCreateVideoFrameAncillaryPacketsFunc == NULL)
return NULL;
return gCreateVideoFrameAncillaryPacketsFunc();
}

View file

@ -1,68 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIGLSCREENPREVIEW_v14_2_1_H
#define BMD_DECKLINKAPIGLSCREENPREVIEW_v14_2_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIVideoFrame_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkGLScreenPreviewHelper_v14_2_1 = /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ { 0x50, 0x4E, 0x22, 0x09, 0xCA, 0xC7, 0x4C, 0x1A, 0x9F, 0xB4, 0xC5, 0xBB, 0x62, 0x74, 0xD2, 0x2F };
/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance on platforms with native COM support or from CreateOpenGLScreenPreviewHelper/CreateOpenGL3ScreenPreviewHelper on other platforms. */
class BMD_PUBLIC IDeckLinkGLScreenPreviewHelper_v14_2_1 : public IUnknown
{
public:
/* Methods must be called with OpenGL context set */
virtual HRESULT InitializeGL (void) = 0;
virtual HRESULT PaintGL (void) = 0;
virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame) = 0;
virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0;
protected:
virtual ~IDeckLinkGLScreenPreviewHelper_v14_2_1 () {} // call Release method to drop reference count
};
#endif

View file

@ -1,61 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIMEMORYALLOCATOR_v14_2_1_H
#define BMD_DECKLINKAPIMEMORYALLOCATOR_v14_2_1_H
#include "DeckLinkAPI.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkMemoryAllocator_v14_2_1 = /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ { 0xB3, 0x6E, 0xB6, 0xE7, 0x9D, 0x29, 0x4A, 0xA8, 0x92, 0xEF, 0x84, 0x3B, 0x87, 0xA2, 0x89, 0xE8 };
/* Interface IDeckLinkMemoryAllocator_v14_2_1 - Created with CoCreateInstance. */
class BMD_PUBLIC IDeckLinkMemoryAllocator_v14_2_1 : public IUnknown
{
public:
virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void** allocatedBuffer) = 0;
virtual HRESULT ReleaseBuffer (/* in */ void* buffer) = 0;
virtual HRESULT Commit (void) = 0;
virtual HRESULT Decommit (void) = 0;
};
#endif

View file

@ -1,65 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIMETALSCREENPREVIEW_v14_2_1_H
#define BMD_DECKLINKAPIMETALSCREENPREVIEW_v14_2_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIVideoFrame_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkMetalScreenPreviewHelper_v14_2_1 = /* 1AB252C5-DACB-4AE8-A58B-5320DE9CE373 */ { 0x1A, 0xB2, 0x52, 0xC5, 0xDA, 0xCB, 0x4A, 0xE8, 0xA5, 0x8B, 0x53, 0x20, 0xDE, 0x9C, 0xE3, 0x73 };
/* Interface IDeckLinkMetalScreenPreviewHelper - Created with CreateMetalScreenPreviewHelper(). */
class BMD_PUBLIC IDeckLinkMetalScreenPreviewHelper_v14_2_1 : public IUnknown
{
public:
virtual HRESULT Initialize (/* in */ void* device) = 0;
virtual HRESULT Draw (/* in */ void* cmdBuffer, /* in */ void* renderPassDescriptor, /* in */ void* viewport) = 0;
virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame) = 0;
virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0;
protected:
virtual ~IDeckLinkMetalScreenPreviewHelper_v14_2_1 () {} // call Release method to drop reference count
};
#endif

View file

@ -1,291 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2026 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation covered by
** this license (the "Software") to use, reproduce, display, distribute,
** execute, and transmit the Software, and to prepare derivative works of the
** Software, and to permit third-parties to whom the Software is furnished to
** do so, all subject to the following:
**
** The copyright notices in the Software and this entire statement, including
** the above license grant, this restriction and the following disclaimer,
** must be included in all copies of the Software, in whole or in part, and
** all derivative works of the Software, unless such copies or derivative
** works are solely in the form of machine-executable object code generated by
** a source language processor.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
** -LICENSE-END-
*/
/*
* -- AUTOMATICALLY GENERATED - DO NOT EDIT ---
*/
#ifndef BMD_DECKLINKAPIMODES_H
#define BMD_DECKLINKAPIMODES_H
#ifndef BMD_CONST
#if defined(_MSC_VER)
#define BMD_CONST __declspec(selectany) static const
#else
#define BMD_CONST static const
#endif
#endif
#ifndef BMD_PUBLIC
#define BMD_PUBLIC
#endif
// Type Declarations
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkDisplayModeIterator = /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ { 0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35 };
BMD_CONST REFIID IID_IDeckLinkDisplayMode = /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ { 0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78 };
/* Enum BMDDisplayMode - BMDDisplayMode enumerates the video modes supported. */
typedef uint32_t BMDDisplayMode;
enum _BMDDisplayMode {
/* SD Modes */
bmdModeNTSC = /* 'ntsc' */ 0x6E747363,
bmdModeNTSC2398 = /* 'nt23' */ 0x6E743233, // 3:2 pulldown
bmdModePAL = /* 'pal ' */ 0x70616C20,
bmdModeNTSCp = /* 'ntsp' */ 0x6E747370,
bmdModePALp = /* 'palp' */ 0x70616C70,
/* HD 1080 Modes */
bmdModeHD1080p2398 = /* '23ps' */ 0x32337073,
bmdModeHD1080p24 = /* '24ps' */ 0x32347073,
bmdModeHD1080p25 = /* 'Hp25' */ 0x48703235,
bmdModeHD1080p2997 = /* 'Hp29' */ 0x48703239,
bmdModeHD1080p30 = /* 'Hp30' */ 0x48703330,
bmdModeHD1080p4795 = /* 'Hp47' */ 0x48703437,
bmdModeHD1080p48 = /* 'Hp48' */ 0x48703438,
bmdModeHD1080p50 = /* 'Hp50' */ 0x48703530,
bmdModeHD1080p5994 = /* 'Hp59' */ 0x48703539,
bmdModeHD1080p6000 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz.
bmdModeHD1080p9590 = /* 'Hp95' */ 0x48703935,
bmdModeHD1080p96 = /* 'Hp96' */ 0x48703936,
bmdModeHD1080p100 = /* 'Hp10' */ 0x48703130,
bmdModeHD1080p11988 = /* 'Hp11' */ 0x48703131,
bmdModeHD1080p120 = /* 'Hp12' */ 0x48703132,
bmdModeHD1080i50 = /* 'Hi50' */ 0x48693530,
bmdModeHD1080i5994 = /* 'Hi59' */ 0x48693539,
bmdModeHD1080i6000 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz.
/* HD 720 Modes */
bmdModeHD720p50 = /* 'hp50' */ 0x68703530,
bmdModeHD720p5994 = /* 'hp59' */ 0x68703539,
bmdModeHD720p60 = /* 'hp60' */ 0x68703630,
/* 2K Modes */
bmdMode2k2398 = /* '2k23' */ 0x326B3233,
bmdMode2k24 = /* '2k24' */ 0x326B3234,
bmdMode2k25 = /* '2k25' */ 0x326B3235,
/* 2K DCI Modes */
bmdMode2kDCI2398 = /* '2d23' */ 0x32643233,
bmdMode2kDCI24 = /* '2d24' */ 0x32643234,
bmdMode2kDCI25 = /* '2d25' */ 0x32643235,
bmdMode2kDCI2997 = /* '2d29' */ 0x32643239,
bmdMode2kDCI30 = /* '2d30' */ 0x32643330,
bmdMode2kDCI4795 = /* '2d47' */ 0x32643437,
bmdMode2kDCI48 = /* '2d48' */ 0x32643438,
bmdMode2kDCI50 = /* '2d50' */ 0x32643530,
bmdMode2kDCI5994 = /* '2d59' */ 0x32643539,
bmdMode2kDCI60 = /* '2d60' */ 0x32643630,
bmdMode2kDCI9590 = /* '2d95' */ 0x32643935,
bmdMode2kDCI96 = /* '2d96' */ 0x32643936,
bmdMode2kDCI100 = /* '2d10' */ 0x32643130,
bmdMode2kDCI11988 = /* '2d11' */ 0x32643131,
bmdMode2kDCI120 = /* '2d12' */ 0x32643132,
/* 4K UHD Modes */
bmdMode4K2160p2398 = /* '4k23' */ 0x346B3233,
bmdMode4K2160p24 = /* '4k24' */ 0x346B3234,
bmdMode4K2160p25 = /* '4k25' */ 0x346B3235,
bmdMode4K2160p2997 = /* '4k29' */ 0x346B3239,
bmdMode4K2160p30 = /* '4k30' */ 0x346B3330,
bmdMode4K2160p4795 = /* '4k47' */ 0x346B3437,
bmdMode4K2160p48 = /* '4k48' */ 0x346B3438,
bmdMode4K2160p50 = /* '4k50' */ 0x346B3530,
bmdMode4K2160p5994 = /* '4k59' */ 0x346B3539,
bmdMode4K2160p60 = /* '4k60' */ 0x346B3630,
bmdMode4K2160p9590 = /* '4k95' */ 0x346B3935,
bmdMode4K2160p96 = /* '4k96' */ 0x346B3936,
bmdMode4K2160p100 = /* '4k10' */ 0x346B3130,
bmdMode4K2160p11988 = /* '4k11' */ 0x346B3131,
bmdMode4K2160p120 = /* '4k12' */ 0x346B3132,
/* 4K DCI Modes */
bmdMode4kDCI2398 = /* '4d23' */ 0x34643233,
bmdMode4kDCI24 = /* '4d24' */ 0x34643234,
bmdMode4kDCI25 = /* '4d25' */ 0x34643235,
bmdMode4kDCI2997 = /* '4d29' */ 0x34643239,
bmdMode4kDCI30 = /* '4d30' */ 0x34643330,
bmdMode4kDCI4795 = /* '4d47' */ 0x34643437,
bmdMode4kDCI48 = /* '4d48' */ 0x34643438,
bmdMode4kDCI50 = /* '4d50' */ 0x34643530,
bmdMode4kDCI5994 = /* '4d59' */ 0x34643539,
bmdMode4kDCI60 = /* '4d60' */ 0x34643630,
bmdMode4kDCI9590 = /* '4d95' */ 0x34643935,
bmdMode4kDCI96 = /* '4d96' */ 0x34643936,
bmdMode4kDCI100 = /* '4d10' */ 0x34643130,
bmdMode4kDCI11988 = /* '4d11' */ 0x34643131,
bmdMode4kDCI120 = /* '4d12' */ 0x34643132,
/* 8K UHD Modes */
bmdMode8K4320p2398 = /* '8k23' */ 0x386B3233,
bmdMode8K4320p24 = /* '8k24' */ 0x386B3234,
bmdMode8K4320p25 = /* '8k25' */ 0x386B3235,
bmdMode8K4320p2997 = /* '8k29' */ 0x386B3239,
bmdMode8K4320p30 = /* '8k30' */ 0x386B3330,
bmdMode8K4320p4795 = /* '8k47' */ 0x386B3437,
bmdMode8K4320p48 = /* '8k48' */ 0x386B3438,
bmdMode8K4320p50 = /* '8k50' */ 0x386B3530,
bmdMode8K4320p5994 = /* '8k59' */ 0x386B3539,
bmdMode8K4320p60 = /* '8k60' */ 0x386B3630,
/* 8K DCI Modes */
bmdMode8kDCI2398 = /* '8d23' */ 0x38643233,
bmdMode8kDCI24 = /* '8d24' */ 0x38643234,
bmdMode8kDCI25 = /* '8d25' */ 0x38643235,
bmdMode8kDCI2997 = /* '8d29' */ 0x38643239,
bmdMode8kDCI30 = /* '8d30' */ 0x38643330,
bmdMode8kDCI4795 = /* '8d47' */ 0x38643437,
bmdMode8kDCI48 = /* '8d48' */ 0x38643438,
bmdMode8kDCI50 = /* '8d50' */ 0x38643530,
bmdMode8kDCI5994 = /* '8d59' */ 0x38643539,
bmdMode8kDCI60 = /* '8d60' */ 0x38643630,
/* PC Modes */
bmdMode640x480p60 = /* 'vga6' */ 0x76676136,
bmdMode800x600p60 = /* 'svg6' */ 0x73766736,
bmdMode1440x900p50 = /* 'wxg5' */ 0x77786735,
bmdMode1440x900p60 = /* 'wxg6' */ 0x77786736,
bmdMode1440x1080p50 = /* 'sxg5' */ 0x73786735,
bmdMode1440x1080p60 = /* 'sxg6' */ 0x73786736,
bmdMode1600x1200p50 = /* 'uxg5' */ 0x75786735,
bmdMode1600x1200p60 = /* 'uxg6' */ 0x75786736,
bmdMode1920x1200p50 = /* 'wux5' */ 0x77757835,
bmdMode1920x1200p60 = /* 'wux6' */ 0x77757836,
bmdMode1920x1440p50 = /* '1945' */ 0x31393435,
bmdMode1920x1440p60 = /* '1946' */ 0x31393436,
bmdMode2560x1440p50 = /* 'wqh5' */ 0x77716835,
bmdMode2560x1440p60 = /* 'wqh6' */ 0x77716836,
bmdMode2560x1600p50 = /* 'wqx5' */ 0x77717835,
bmdMode2560x1600p60 = /* 'wqx6' */ 0x77717836,
bmdModeUnknown = /* 'iunk' */ 0x69756E6B
};
/* Enum BMDFieldDominance - BMDFieldDominance enumerates settings applicable to video fields. */
typedef uint32_t BMDFieldDominance;
enum _BMDFieldDominance {
bmdUnknownFieldDominance = 0,
bmdLowerFieldFirst = /* 'lowr' */ 0x6C6F7772,
bmdUpperFieldFirst = /* 'uppr' */ 0x75707072,
bmdProgressiveFrame = /* 'prog' */ 0x70726F67,
bmdProgressiveSegmentedFrame = /* 'psf ' */ 0x70736620
};
/* Enum BMDPixelFormat - Video pixel formats supported for output/input */
typedef uint32_t BMDPixelFormat;
enum _BMDPixelFormat {
bmdFormatUnspecified = 0,
bmdFormat8BitYUV = /* '2vuy' */ 0x32767579,
bmdFormat10BitYUV = /* 'v210' */ 0x76323130,
bmdFormat10BitYUVA = /* 'Ay10' */ 0x41793130, // Big-endian YUVA 10 bit per component with SMPTE video levels (64-940) for YUV but full range alpha
bmdFormat8BitARGB = 32,
bmdFormat8BitBGRA = /* 'BGRA' */ 0x42475241,
bmdFormat10BitRGB = /* 'r210' */ 0x72323130, // Big-endian RGB 10-bit per component with SMPTE video levels (64-940). Packed as 2:10:10:10
bmdFormat12BitRGB = /* 'R12B' */ 0x52313242, // Big-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component
bmdFormat12BitRGBLE = /* 'R12L' */ 0x5231324C, // Little-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component
bmdFormat10BitRGBXLE = /* 'R10l' */ 0x5231306C, // Little-endian 10-bit RGB with SMPTE video levels (64-940)
bmdFormat10BitRGBX = /* 'R10b' */ 0x52313062, // Big-endian 10-bit RGB with SMPTE video levels (64-940)
/* Formats supported only by devices that can be queried for an IDeckLinkEncoderInput */
bmdFormatH265 = /* 'hev1' */ 0x68657631,
bmdFormatDNxHR = /* 'AVdh' */ 0x41566468
};
/* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */
typedef uint32_t BMDDisplayModeFlags;
enum _BMDDisplayModeFlags {
bmdDisplayModeSupports3D = 1 << 0,
bmdDisplayModeColorspaceRec601 = 1 << 1,
bmdDisplayModeColorspaceRec709 = 1 << 2,
bmdDisplayModeColorspaceRec2020 = 1 << 3
};
#if defined(__cplusplus)
// Forward Declarations
class IDeckLinkDisplayModeIterator;
class IDeckLinkDisplayMode;
/* Interface IDeckLinkDisplayModeIterator - Enumerates over supported input/output display modes. */
class BMD_PUBLIC IDeckLinkDisplayModeIterator : public IUnknown
{
public:
virtual HRESULT Next (/* out */ IDeckLinkDisplayMode** deckLinkDisplayMode) = 0;
protected:
virtual ~IDeckLinkDisplayModeIterator () {} // call Release method to drop reference count
};
/* Interface IDeckLinkDisplayMode - Represents a display mode */
class BMD_PUBLIC IDeckLinkDisplayMode : public IUnknown
{
public:
virtual HRESULT GetName (/* out */ const char** name) = 0;
virtual BMDDisplayMode GetDisplayMode (void) = 0;
virtual long GetWidth (void) = 0;
virtual long GetHeight (void) = 0;
virtual HRESULT GetFrameRate (/* out */ BMDTimeValue* frameDuration, /* out */ BMDTimeScale* timeScale) = 0;
virtual BMDFieldDominance GetFieldDominance (void) = 0;
virtual BMDDisplayModeFlags GetFlags (void) = 0;
protected:
virtual ~IDeckLinkDisplayMode () {} // call Release method to drop reference count
};
/* Functions */
extern "C" {
}
#endif /* defined(__cplusplus) */
#endif /* defined(BMD_DECKLINKAPIMODES_H) */

View file

@ -1,62 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPISCREENPREVIEWCALLBACK_v14_2_1_H
#define BMD_DECKLINKAPISCREENPREVIEWCALLBACK_v14_2_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIVideoFrame_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkScreenPreviewCallback_v14_2_1 = /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ { 0xB1, 0xD3, 0xF4, 0x9A, 0x85, 0xFE, 0x4C, 0x5D, 0x95, 0xC8, 0x0B, 0x5D, 0x5D, 0xCC, 0xD4, 0x38 };
/* Interface IDeckLinkScreenPreviewCallback_v14_2_1 - Screen preview callback */
class BMD_PUBLIC IDeckLinkScreenPreviewCallback_v14_2_1 : public IUnknown
{
public:
virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame) = 0;
protected:
virtual ~IDeckLinkScreenPreviewCallback_v14_2_1 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPISCREENPREVIEWCALLBACK_v14_2_1_H) */

View file

@ -1,140 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2026 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation covered by
** this license (the "Software") to use, reproduce, display, distribute,
** execute, and transmit the Software, and to prepare derivative works of the
** Software, and to permit third-parties to whom the Software is furnished to
** do so, all subject to the following:
**
** The copyright notices in the Software and this entire statement, including
** the above license grant, this restriction and the following disclaimer,
** must be included in all copies of the Software, in whole or in part, and
** all derivative works of the Software, unless such copies or derivative
** works are solely in the form of machine-executable object code generated by
** a source language processor.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
** -LICENSE-END-
*/
/*
* -- AUTOMATICALLY GENERATED - DO NOT EDIT ---
*/
#ifndef BMD_DECKLINKAPITYPES_H
#define BMD_DECKLINKAPITYPES_H
#ifndef BMD_CONST
#if defined(_MSC_VER)
#define BMD_CONST __declspec(selectany) static const
#else
#define BMD_CONST static const
#endif
#endif
#ifndef BMD_PUBLIC
#define BMD_PUBLIC
#endif
// Type Declarations
typedef int64_t BMDTimeValue;
typedef int64_t BMDTimeScale;
typedef uint32_t BMDTimecodeBCD;
typedef uint32_t BMDTimecodeUserBits;
typedef int64_t BMDIPFlowID;
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkTimecode = /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ { 0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40 };
/* Enum BMDTimecodeFlags - Timecode flags */
typedef uint32_t BMDTimecodeFlags;
enum _BMDTimecodeFlags {
bmdTimecodeFlagDefault = 0,
bmdTimecodeIsDropFrame = 1 << 0,
bmdTimecodeFieldMark = 1 << 1,
bmdTimecodeColorFrame = 1 << 2,
bmdTimecodeEmbedRecordingTrigger = 1 << 3, // On SDI recording trigger utilises a user-bit.
bmdTimecodeRecordingTriggered = 1 << 4
};
/* Enum BMDVideoConnection - Video connection types */
typedef uint32_t BMDVideoConnection;
enum _BMDVideoConnection {
bmdVideoConnectionUnspecified = 0,
bmdVideoConnectionSDI = 1 << 0,
bmdVideoConnectionHDMI = 1 << 1,
bmdVideoConnectionOpticalSDI = 1 << 2,
bmdVideoConnectionComponent = 1 << 3,
bmdVideoConnectionComposite = 1 << 4,
bmdVideoConnectionSVideo = 1 << 5,
bmdVideoConnectionEthernet = 1 << 6,
bmdVideoConnectionOpticalEthernet = 1 << 7,
bmdVideoConnectionInternal = 1 << 8
};
/* Enum BMDAudioConnection - Audio connection types */
typedef uint32_t BMDAudioConnection;
enum _BMDAudioConnection {
bmdAudioConnectionEmbedded = 1 << 0,
bmdAudioConnectionAESEBU = 1 << 1,
bmdAudioConnectionAnalog = 1 << 2,
bmdAudioConnectionAnalogXLR = 1 << 3,
bmdAudioConnectionAnalogRCA = 1 << 4,
bmdAudioConnectionMicrophone = 1 << 5,
bmdAudioConnectionHeadphones = 1 << 6
};
/* Enum BMDDeckControlConnection - Deck control connections */
typedef uint32_t BMDDeckControlConnection;
enum _BMDDeckControlConnection {
bmdDeckControlConnectionRS422Remote1 = 1 << 0,
bmdDeckControlConnectionRS422Remote2 = 1 << 1
};
#if defined(__cplusplus)
// Forward Declarations
class IDeckLinkTimecode;
/* Interface IDeckLinkTimecode - Used for video frame timecode representation. */
class BMD_PUBLIC IDeckLinkTimecode : public IUnknown
{
public:
virtual BMDTimecodeBCD GetBCD (void) = 0;
virtual HRESULT GetComponents (/* out */ uint8_t* hours, /* out */ uint8_t* minutes, /* out */ uint8_t* seconds, /* out */ uint8_t* frames) = 0;
virtual HRESULT GetString (/* out */ const char** timecode) = 0;
virtual BMDTimecodeFlags GetFlags (void) = 0;
virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits* userBits) = 0;
protected:
virtual ~IDeckLinkTimecode () {} // call Release method to drop reference count
};
/* Functions */
extern "C" {
}
#endif /* defined(__cplusplus) */
#endif /* defined(BMD_DECKLINKAPITYPES_H) */

View file

@ -1,50 +0,0 @@
/* -LICENSE-START-
* ** Copyright (c) 2014 Blackmagic Design
* **
* ** Permission is hereby granted, free of charge, to any person or organization
* ** obtaining a copy of the software and accompanying documentation (the
* ** "Software") to use, reproduce, display, distribute, sub-license, execute,
* ** and transmit the Software, and to prepare derivative works of the Software,
* ** and to permit third-parties to whom the Software is furnished to do so, in
* ** accordance with:
* **
* ** (1) if the Software is obtained from Blackmagic Design, the End User License
* ** Agreement for the Software Development Kit ("EULA") available at
* ** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
* **
* ** (2) if the Software is obtained from any third party, such licensing terms
* ** as notified by that third party,
* **
* ** and all subject to the following:
* **
* ** (3) the copyright notices in the Software and this entire statement,
* ** including the above license grant, this restriction and the following
* ** disclaimer, must be included in all copies of the Software, in whole or in
* ** part, and all derivative works of the Software, unless such copies or
* ** derivative works are solely in the form of machine-executable object code
* ** generated by a source language processor.
* **
* ** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
* ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
* ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
* ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* ** DEALINGS IN THE SOFTWARE.
* **
* ** A copy of the Software is available free of charge at
* ** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
* **
* ** -LICENSE-END-
* */
/* DeckLinkAPIVersion.h */
#ifndef __DeckLink_API_Version_h__
#define __DeckLink_API_Version_h__
#define BLACKMAGIC_DECKLINK_API_VERSION 0x10000000
#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "16.0"
#endif // __DeckLink_API_Version_h__

View file

@ -1,62 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOCONVERSION_v14_2_1_H
#define BMD_DECKLINKAPIVIDEOCONVERSION_v14_2_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIVideoFrame_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkVideoConversion_v14_2_1 = /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ { 0x3B, 0xBC, 0xB8, 0xA2, 0xDA, 0x2C, 0x42, 0xD9, 0xB5, 0xD8, 0x88, 0x08, 0x36, 0x44, 0xE9, 0x9A };
/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance. */
class BMD_PUBLIC IDeckLinkVideoConversion_v14_2_1 : public IUnknown
{
public:
virtual HRESULT ConvertFrame (/* in */ IDeckLinkVideoFrame_v14_2_1* srcFrame, /* in */ IDeckLinkVideoFrame_v14_2_1* dstFrame) = 0;
protected:
virtual ~IDeckLinkVideoConversion_v14_2_1 () {} // call Release method to drop reference count
};
#endif

View file

@ -1,88 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2017 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H
#define BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPI_v10_11.h"
#include "DeckLinkAPIMemoryAllocator_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkEncoderInput_v10_11 = /* 270587DA-6B7D-42E7-A1F0-6D853F581185 */ {0x27,0x05,0x87,0xDA,0x6B,0x7D,0x42,0xE7,0xA1,0xF0,0x6D,0x85,0x3F,0x58,0x11,0x85};
/* Interface IDeckLinkEncoderInput_v10_11 - Created by QueryInterface from IDeckLink. */
class IDeckLinkEncoderInput_v10_11 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0;
/* Video Input */
virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0;
virtual HRESULT DisableVideoInput (void) = 0;
virtual HRESULT GetAvailablePacketsCount (/* out */ uint32_t *availablePacketsCount) = 0;
virtual HRESULT SetMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1 *theAllocator) = 0;
/* Audio Input */
virtual HRESULT EnableAudioInput (/* in */ BMDAudioFormat audioFormat, /* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0;
virtual HRESULT DisableAudioInput (void) = 0;
virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0;
/* Input Control */
virtual HRESULT StartStreams (void) = 0;
virtual HRESULT StopStreams (void) = 0;
virtual HRESULT PauseStreams (void) = 0;
virtual HRESULT FlushStreams (void) = 0;
virtual HRESULT SetCallback (/* in */ IDeckLinkEncoderInputCallback *theCallback) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0;
protected:
virtual ~IDeckLinkEncoderInput_v10_11 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOENCODERINPUT_v10_11_H) */

View file

@ -1,63 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOFRAME3DEXTENSIONS_v14_2_1_H
#define BMD_DECKLINKAPIVIDEOFRAME3DEXTENSIONS_v14_2_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIVideoFrame_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkVideoFrame3DExtensions_v14_2_1 = /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ { 0xDA, 0x0F, 0x7E, 0x4A, 0xED, 0xC7, 0x48, 0xA8, 0x9C, 0xDD, 0x2D, 0xB5, 0x1C, 0x72, 0x9C, 0xD7 };
/* Interface IDeckLinkVideoFrame3DExtensions - Optional interface implemented on IDeckLinkVideoFrame to support 3D frames */
class BMD_PUBLIC IDeckLinkVideoFrame3DExtensions_v14_2_1 : public IUnknown
{
public:
virtual BMDVideo3DPackingFormat Get3DPackingFormat (void) = 0;
virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame_v14_2_1** rightEyeFrame) = 0;
protected:
virtual ~IDeckLinkVideoFrame3DExtensions_v14_2_1 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOFRAME3DEXTENSIONS_v14_2_1_H) */

View file

@ -1,68 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOFRAME_v14_2_1_H
#define BMD_DECKLINKAPIVIDEOFRAME_v14_2_1_H
#include "DeckLinkAPI.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkVideoFrame_v14_2_1 = /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ { 0x3F, 0x71, 0x6F, 0xE0, 0xF0, 0x23, 0x41, 0x11, 0xBE, 0x5D, 0xEF, 0x44, 0x14, 0xC0, 0x5B, 0x17 };
/* Interface IDeckLinkVideoFrame - Interface to encapsulate a video frame; can be caller-implemented. */
class BMD_PUBLIC IDeckLinkVideoFrame_v14_2_1 : public IUnknown
{
public:
virtual long GetWidth (void) = 0;
virtual long GetHeight (void) = 0;
virtual long GetRowBytes (void) = 0;
virtual BMDPixelFormat GetPixelFormat (void) = 0;
virtual BMDFrameFlags GetFlags (void) = 0;
virtual HRESULT GetBytes (/* out */ void** buffer) = 0;
virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode** timecode) = 0;
virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary** ancillary) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred
protected:
virtual ~IDeckLinkVideoFrame_v14_2_1 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOFRAME_v14_2_1_H) */

View file

@ -1,91 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2017 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOINPUT_v10_11_H
#define BMD_DECKLINKAPIVIDEOINPUT_v10_11_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPI_v10_11.h"
#include "DeckLinkAPIMemoryAllocator_v14_2_1.h"
#include "DeckLinkAPIVideoInput_v11_5_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkInput_v10_11 = /* AF22762B-DFAC-4846-AA79-FA8883560995 */ {0xAF,0x22,0x76,0x2B,0xDF,0xAC,0x48,0x46,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95};
/* Interface IDeckLinkInput_v10_11 - DeckLink input interface. */
class IDeckLinkInput_v10_11 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v14_2_1 *previewCallback) = 0;
/* Video Input */
virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0;
virtual HRESULT DisableVideoInput (void) = 0;
virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0;
virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1 *theAllocator) = 0;
/* Audio Input */
virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0;
virtual HRESULT DisableAudioInput (void) = 0;
virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0;
/* Input Control */
virtual HRESULT StartStreams (void) = 0;
virtual HRESULT StopStreams (void) = 0;
virtual HRESULT PauseStreams (void) = 0;
virtual HRESULT FlushStreams (void) = 0;
virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback_v11_5_1 *theCallback) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0;
protected:
virtual ~IDeckLinkInput_v10_11 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v10_11_H) */

View file

@ -1,90 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2019 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOINPUT_v11_4_H
#define BMD_DECKLINKAPIVIDEOINPUT_v11_4_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIMemoryAllocator_v14_2_1.h"
#include "DeckLinkAPIVideoInput_v11_5_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkInput_v11_4 = /* 2A88CF76-F494-4216-A7EF-DC74EEB83882 */ { 0x2A,0x88,0xCF,0x76,0xF4,0x94,0x42,0x16,0xA7,0xEF,0xDC,0x74,0xEE,0xB8,0x38,0x82 };
/* Interface IDeckLinkInput_v11_4 - Created by QueryInterface from IDeckLink. */
class BMD_PUBLIC IDeckLinkInput_v11_4 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of 0 is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDSupportedVideoModeFlags flags, /* out */ bool* supported) = 0;
virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v14_2_1* previewCallback) = 0;
/* Video Input */
virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0;
virtual HRESULT DisableVideoInput (void) = 0;
virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0;
virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1* theAllocator) = 0;
/* Audio Input */
virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0;
virtual HRESULT DisableAudioInput (void) = 0;
virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0;
/* Input Control */
virtual HRESULT StartStreams (void) = 0;
virtual HRESULT StopStreams (void) = 0;
virtual HRESULT PauseStreams (void) = 0;
virtual HRESULT FlushStreams (void) = 0;
virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback_v11_5_1* theCallback) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0;
protected:
virtual ~IDeckLinkInput_v11_4 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v11_4_H) */

View file

@ -1,103 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2020 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H
#define BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIVideoInput_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkInputCallback_v11_5_1 = /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ { 0xDD, 0x04, 0xE5, 0xEC, 0x74, 0x15, 0x42, 0xAB, 0xAE, 0x4A, 0xE8, 0x0C, 0x4D, 0xFC, 0x04, 0x4A };
BMD_CONST REFIID IID_IDeckLinkInput_v11_5_1 = /* 9434C6E4-B15D-4B1C-979E-661E3DDCB4B9 */ { 0x94, 0x34, 0xC6, 0xE4, 0xB1, 0x5D, 0x4B, 0x1C, 0x97, 0x9E, 0x66, 0x1E, 0x3D, 0xDC, 0xB4, 0xB9 };
/* Interface IDeckLinkInputCallback_v11_5_1 - Frame arrival callback. */
class BMD_PUBLIC IDeckLinkInputCallback_v11_5_1 : public IUnknown
{
public:
virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode* newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0;
virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame_v14_2_1* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0;
protected:
virtual ~IDeckLinkInputCallback_v11_5_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkInput_v11_5_1 - Created by QueryInterface from IDeckLink. */
class BMD_PUBLIC IDeckLinkInput_v11_5_1 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoInputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0;
virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v14_2_1* previewCallback) = 0;
/* Video Input */
virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0;
virtual HRESULT DisableVideoInput (void) = 0;
virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0;
virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1* theAllocator) = 0;
/* Audio Input */
virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0;
virtual HRESULT DisableAudioInput (void) = 0;
virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0;
/* Input Control */
virtual HRESULT StartStreams (void) = 0;
virtual HRESULT StopStreams (void) = 0;
virtual HRESULT PauseStreams (void) = 0;
virtual HRESULT FlushStreams (void) = 0;
virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback_v11_5_1* theCallback) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0;
protected:
virtual ~IDeckLinkInput_v11_5_1 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v11_5_1_H) */

View file

@ -1,118 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOINPUT_v14_2_1_H
#define BMD_DECKLINKAPIVIDEOINPUT_v14_2_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIMemoryAllocator_v14_2_1.h"
#include "DeckLinkAPIVideoFrame_v14_2_1.h"
#include "DeckLinkAPIScreenPreviewCallback_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkVideoInputFrame_v14_2_1 = /* 05CFE374-537C-4094-9A57-680525118F44 */ { 0x05, 0xCF, 0xE3, 0x74, 0x53, 0x7C, 0x40, 0x94, 0x9A, 0x57, 0x68, 0x05, 0x25, 0x11, 0x8F, 0x44 };
BMD_CONST REFIID IID_IDeckLinkInputCallback_v14_2_1 = /* C6FCE4C9-C4E4-4047-82FB-5D238232A902 */ { 0xC6, 0xFC, 0xE4, 0xC9, 0xC4, 0xE4, 0x40, 0x47, 0x82, 0xFB, 0x5D, 0x23, 0x82, 0x32, 0xA9, 0x02 };
BMD_CONST REFIID IID_IDeckLinkInput_v14_2_1 = /* C21CDB6E-F414-46E4-A636-80A566E0ED37 */ { 0xC2, 0x1C, 0xDB, 0x6E, 0xF4, 0x14, 0x46, 0xE4, 0xA6, 0x36, 0x80, 0xA5, 0x66, 0xE0, 0xED, 0x37 };
/* Interface IDeckLinkVideoInputFrame - Provided by the IDeckLinkVideoInput frame arrival callback. */
class BMD_PUBLIC IDeckLinkVideoInputFrame_v14_2_1 : public IDeckLinkVideoFrame_v14_2_1
{
public:
virtual HRESULT GetStreamTime (/* out */ BMDTimeValue* frameTime, /* out */ BMDTimeValue* frameDuration, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue* frameTime, /* out */ BMDTimeValue* frameDuration) = 0;
protected:
virtual ~IDeckLinkVideoInputFrame_v14_2_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkInputCallback_v14_2_1 - Frame arrival callback. */
class BMD_PUBLIC IDeckLinkInputCallback_v14_2_1 : public IUnknown
{
public:
virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode* newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0;
virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame_v14_2_1* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0;
protected:
virtual ~IDeckLinkInputCallback_v14_2_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */
class BMD_PUBLIC IDeckLinkInput_v14_2_1 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoInputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0;
virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v14_2_1* previewCallback) = 0;
/* Video Input */
virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0;
virtual HRESULT DisableVideoInput (void) = 0;
virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0;
virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1* theAllocator) = 0;
/* Audio Input */
virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0;
virtual HRESULT DisableAudioInput (void) = 0;
virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0;
/* Input Control */
virtual HRESULT StartStreams (void) = 0;
virtual HRESULT StopStreams (void) = 0;
virtual HRESULT PauseStreams (void) = 0;
virtual HRESULT FlushStreams (void) = 0;
virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback_v14_2_1* theCallback) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0;
protected:
virtual ~IDeckLinkInput_v14_2_1 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOINPUT_v14_2_1_H) */

View file

@ -1,86 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2025 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#pragma once
#include "DeckLinkAPI_v15_3_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkInput_v15_3_1 = /* 4095DB82-E294-4B8C-AAA8-3B9E80C49336 */ { 0x40,0x95,0xDB,0x82,0xE2,0x94,0x4B,0x8C,0xAA,0xA8,0x3B,0x9E,0x80,0xC4,0x93,0x36 };
/* Interface IDeckLinkInput_v15_3_1 - Created by QueryInterface from IDeckLink. */
class BMD_PUBLIC IDeckLinkInput_v15_3_1 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoInputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0;
virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0;
/* Video Input */
virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0;
virtual HRESULT EnableVideoInputWithAllocatorProvider (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* in */ IDeckLinkVideoBufferAllocatorProvider_v15_3_1* allocatorProvider) = 0;
virtual HRESULT DisableVideoInput (void) = 0;
virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t* availableFrameCount) = 0;
/* Audio Input */
virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0;
virtual HRESULT DisableAudioInput (void) = 0;
virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0;
/* Input Control */
virtual HRESULT StartStreams (void) = 0;
virtual HRESULT StopStreams (void) = 0;
virtual HRESULT PauseStreams (void) = 0;
virtual HRESULT FlushStreams (void) = 0;
virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback* theCallback) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0;
protected:
virtual ~IDeckLinkInput_v15_3_1 () {} // call Release method to drop reference count
};

View file

@ -1,109 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2017 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H
#define BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPI_v10_11.h"
#include "DeckLinkAPIVideoInput_v14_2_1.h"
#include "DeckLinkAPIVideoOutput_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkOutput_v10_11 = /* CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564 */ {0xCC,0x5C,0x8A,0x6E,0x3F,0x2F,0x4B,0x3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64};
/* Interface IDeckLinkOutput_v10_11 - DeckLink output interface. */
class IDeckLinkOutput_v10_11 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport_v10_11 *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v14_2_1 *previewCallback) = 0;
/* Video Output */
virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0;
virtual HRESULT DisableVideoOutput (void) = 0;
virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1 *theAllocator) = 0;
virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame_v14_2_1 **outFrame) = 0;
virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0;
virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame_v14_2_1 *theFrame) = 0;
virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame_v14_2_1 *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback_v14_2_1 *theCallback) = 0;
virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0;
/* Audio Output */
virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0;
virtual HRESULT DisableAudioOutput (void) = 0;
virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0;
virtual HRESULT BeginAudioPreroll (void) = 0;
virtual HRESULT EndAudioPreroll (void) = 0;
virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0;
virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0;
virtual HRESULT FlushBufferedAudioSamples (void) = 0;
virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0;
/* Output Control */
virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0;
virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0;
virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0;
virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0;
virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame_v14_2_1 *theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *frameCompletionTimestamp) = 0;
protected:
virtual ~IDeckLinkOutput_v10_11 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOOUTPUT_v10_11_H) */

View file

@ -1,101 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2019 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H
#define BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIVideoOutput_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkOutput_v11_4 = /* 065A0F6C-C508-4D0D-B919-F5EB0EBFC96B */ { 0x06,0x5A,0x0F,0x6C,0xC5,0x08,0x4D,0x0D,0xB9,0x19,0xF5,0xEB,0x0E,0xBF,0xC9,0x6B };
/* Interface IDeckLinkOutput_v11_4 - Created by QueryInterface from IDeckLink. */
class BMD_PUBLIC IDeckLinkOutput_v11_4 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of 0 is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0;
virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v14_2_1* previewCallback) = 0;
/* Video Output */
virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0;
virtual HRESULT DisableVideoOutput (void) = 0;
virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1* theAllocator) = 0;
virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame_v14_2_1** outFrame) = 0;
virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary** outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred
virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame) = 0;
virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback_v14_2_1* theCallback) = 0;
virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t* bufferedFrameCount) = 0;
/* Audio Output */
virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0;
virtual HRESULT DisableAudioOutput (void) = 0;
virtual HRESULT WriteAudioSamplesSync (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t* sampleFramesWritten) = 0;
virtual HRESULT BeginAudioPreroll (void) = 0;
virtual HRESULT EndAudioPreroll (void) = 0;
virtual HRESULT ScheduleAudioSamples (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t* sampleFramesWritten) = 0;
virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t* bufferedSampleFrameCount) = 0;
virtual HRESULT FlushBufferedAudioSamples (void) = 0;
virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback* theCallback) = 0;
/* Output Control */
virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0;
virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue* actualStopTime, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool* active) = 0;
virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* streamTime, /* out */ double* playbackSpeed) = 0;
virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus* referenceStatus) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0;
virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* frameCompletionTimestamp) = 0;
protected:
virtual ~IDeckLinkOutput_v11_4 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPIVIDEOOUTPUT_v11_4_H) */

View file

@ -1,133 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2022 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPIVIDEOOUTPUT_v14_2_1_H
#define BMD_DECKLINKAPIVIDEOOUTPUT_v14_2_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIMemoryAllocator_v14_2_1.h"
#include "DeckLinkAPIVideoFrame_v14_2_1.h"
#include "DeckLinkAPIScreenPreviewCallback_v14_2_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkMutableVideoFrame_v14_2_1 = /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ { 0x69, 0xE2, 0x63, 0x9F, 0x40, 0xDA, 0x4E, 0x19, 0xB6, 0xF2, 0x20, 0xAC, 0xE8, 0x15, 0xC3, 0x90 };
BMD_CONST REFIID IID_IDeckLinkVideoOutputCallback_v14_2_1 = /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ { 0x20, 0xAA, 0x52, 0x25, 0x19, 0x58, 0x47, 0xCB, 0x82, 0x0B, 0x80, 0xA8, 0xD5, 0x21, 0xA6, 0xEE };
BMD_CONST REFIID IID_IDeckLinkOutput_v14_2_1 = /* BE2D9020-461E-442F-84B7-E949CB953B9D */ { 0xBE, 0x2D, 0x90, 0x20, 0x46, 0x1E, 0x44, 0x2F, 0x84, 0xB7, 0xE9, 0x49, 0xCB, 0x95, 0x3B, 0x9D };
/* Interface IDeckLinkMutableVideoFrame - Created by IDeckLinkOutput::CreateVideoFrame. */
class BMD_PUBLIC IDeckLinkMutableVideoFrame_v14_2_1 : public IDeckLinkVideoFrame_v14_2_1
{
public:
virtual HRESULT SetFlags (/* in */ BMDFrameFlags newFlags) = 0;
virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode* timecode) = 0;
virtual HRESULT SetTimecodeFromComponents (/* in */ BMDTimecodeFormat format, /* in */ uint8_t hours, /* in */ uint8_t minutes, /* in */ uint8_t seconds, /* in */ uint8_t frames, /* in */ BMDTimecodeFlags flags) = 0;
virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary* ancillary) = 0;
virtual HRESULT SetTimecodeUserBits (/* in */ BMDTimecodeFormat format, /* in */ BMDTimecodeUserBits userBits) = 0;
protected:
virtual ~IDeckLinkMutableVideoFrame_v14_2_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkVideoOutputCallback - Frame completion callback. */
class BMD_PUBLIC IDeckLinkVideoOutputCallback_v14_2_1 : public IUnknown
{
public:
virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame_v14_2_1* completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0;
virtual HRESULT ScheduledPlaybackHasStopped (void) = 0;
protected:
virtual ~IDeckLinkVideoOutputCallback_v14_2_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */
class BMD_PUBLIC IDeckLinkOutput_v14_2_1 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoOutputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0;
virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback_v14_2_1* previewCallback) = 0;
/* Video Output */
virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0;
virtual HRESULT DisableVideoOutput (void) = 0;
virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1* theAllocator) = 0;
virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame_v14_2_1** outFrame) = 0;
virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary** outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred
virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame) = 0;
virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback_v14_2_1* theCallback) = 0;
virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t* bufferedFrameCount) = 0;
/* Audio Output */
virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0;
virtual HRESULT DisableAudioOutput (void) = 0;
virtual HRESULT WriteAudioSamplesSync (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t* sampleFramesWritten) = 0;
virtual HRESULT BeginAudioPreroll (void) = 0;
virtual HRESULT EndAudioPreroll (void) = 0;
virtual HRESULT ScheduleAudioSamples (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t* sampleFramesWritten) = 0;
virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t* bufferedSampleFrameCount) = 0;
virtual HRESULT FlushBufferedAudioSamples (void) = 0;
virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback* theCallback) = 0;
/* Output Control */
virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0;
virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue* actualStopTime, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool* active) = 0;
virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* streamTime, /* out */ double* playbackSpeed) = 0;
virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus* referenceStatus) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0;
virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame_v14_2_1* theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* frameCompletionTimestamp) = 0;
protected:
virtual ~IDeckLinkOutput_v14_2_1 () {} // call Release method to drop reference count
};
#endif

View file

@ -1,103 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2025 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#pragma once
#include "DeckLinkAPI_v15_3_1.h"
// Type Declarations
BMD_CONST REFIID IID_IDeckLinkOutput_v15_3_1 = /* 1A8077F1-9FE2-4533-8147-2294305E253F */ { 0x1A,0x80,0x77,0xF1,0x9F,0xE2,0x45,0x33,0x81,0x47,0x22,0x94,0x30,0x5E,0x25,0x3F };
#if defined(__cplusplus)
/* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */
class BMD_PUBLIC IDeckLinkOutput_v15_3_1 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedPixelFormat, /* in */ BMDVideoOutputConversionMode conversionMode, /* in */ BMDSupportedVideoModeFlags flags, /* out */ BMDDisplayMode* actualMode, /* out */ bool* supported) = 0;
virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0;
virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback* previewCallback) = 0;
/* Video Output */
virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0;
virtual HRESULT DisableVideoOutput (void) = 0;
virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame** outFrame) = 0;
virtual HRESULT CreateVideoFrameWithBuffer (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* in */ IDeckLinkVideoBuffer_v15_3_1* buffer, /* out */ IDeckLinkMutableVideoFrame** outFrame) = 0;
virtual HRESULT RowBytesForPixelFormat (/* in */ BMDPixelFormat pixelFormat, /* in */ int32_t width, /* out */ int32_t* rowBytes) = 0;
virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary** outBuffer) = 0; // Use of IDeckLinkVideoFrameAncillaryPackets is preferred
virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame* theFrame) = 0;
virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback* theCallback) = 0;
virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t* bufferedFrameCount) = 0;
/* Audio Output */
virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0;
virtual HRESULT DisableAudioOutput (void) = 0;
virtual HRESULT WriteAudioSamplesSync (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t* sampleFramesWritten) = 0;
virtual HRESULT BeginAudioPreroll (void) = 0;
virtual HRESULT EndAudioPreroll (void) = 0;
virtual HRESULT ScheduleAudioSamples (/* in */ void* buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t* sampleFramesWritten) = 0;
virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t* bufferedSampleFrameCount) = 0;
virtual HRESULT FlushBufferedAudioSamples (void) = 0;
virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback* theCallback) = 0;
/* Output Control */
virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0;
virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue* actualStopTime, /* in */ BMDTimeScale timeScale) = 0;
virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool* active) = 0;
virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* streamTime, /* out */ double* playbackSpeed) = 0;
virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus* referenceStatus) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0;
virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame* theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* frameCompletionTimestamp) = 0;
protected:
virtual ~IDeckLinkOutput_v15_3_1 () {} // call Release method to drop reference count
};
#endif // defined(__cplusplus)

View file

@ -1,134 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2018 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v10_11_H
#define BMD_DECKLINKAPI_v10_11_H
#include "DeckLinkAPI.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkAttributes_v10_11 = /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ {0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4};
BMD_CONST REFIID IID_IDeckLinkNotification_v10_11 = /* 0A1FB207-E215-441B-9B19-6FA1575946C5 */ {0x0A,0x1F,0xB2,0x07,0xE2,0x15,0x44,0x1B,0x9B,0x19,0x6F,0xA1,0x57,0x59,0x46,0xC5};
/* Enum BMDDisplayModeSupport_v10_11 - Output mode supported flags */
typedef uint32_t BMDDisplayModeSupport_v10_11;
enum _BMDDisplayModeSupport_v10_11 {
bmdDisplayModeNotSupported_v10_11 = 0,
bmdDisplayModeSupported_v10_11,
bmdDisplayModeSupportedWithConversion_v10_11
};
/* Enum BMDDuplexMode_v10_11 - Duplex for configurable ports */
typedef uint32_t BMDDuplexMode_v10_11;
enum _BMDDuplexMode_v10_11 {
bmdDuplexModeFull_v10_11 = /* 'fdup' */ 0x66647570,
bmdDuplexModeHalf_v10_11 = /* 'hdup' */ 0x68647570
};
/* Enum BMDDeckLinkAttributeID_v10_11 - DeckLink Attribute ID */
enum _BMDDeckLinkAttributeID_v10_11 {
/* Flags */
BMDDeckLinkSupportsDuplexModeConfiguration_v10_11 = 'dupx',
BMDDeckLinkSupportsHDKeying_v10_11 = 'keyh',
/* Integers */
BMDDeckLinkPairedDevicePersistentID_v10_11 = 'ppid',
BMDDeckLinkSupportsFullDuplex_v10_11 = 'fdup',
};
enum _BMDDeckLinkStatusID_v10_11 {
bmdDeckLinkStatusDuplexMode_v10_11 = 'dupx',
};
typedef uint32_t BMDDuplexStatus_v10_11;
enum _BMDDuplexStatus_v10_11 {
bmdDuplexFullDuplex_v10_11 = 'fdup',
bmdDuplexHalfDuplex_v10_11 = 'hdup',
bmdDuplexSimplex_v10_11 = 'splx',
bmdDuplexInactive_v10_11 = 'inac',
};
#if defined(__cplusplus)
/* Interface IDeckLinkAttributes_v10_11 - DeckLink Attribute interface */
class BMD_PUBLIC IDeckLinkAttributes_v10_11 : public IUnknown
{
public:
virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char **value) = 0;
protected:
virtual ~IDeckLinkAttributes_v10_11 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkNotification_v10_11 - DeckLink Notification interface */
class BMD_PUBLIC IDeckLinkNotification_v10_11 : public IUnknown
{
public:
virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0;
virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0;
};
/* Functions */
extern "C" {
BMD_PUBLIC IDeckLinkIterator* CreateDeckLinkIteratorInstance_v10_11 (void);
BMD_PUBLIC IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance_v10_11 (void);
BMD_PUBLIC IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance_v10_11 (void);
BMD_PUBLIC IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper_v10_11 (void);
BMD_PUBLIC IDeckLinkVideoConversion* CreateVideoConversionInstance_v10_11 (void);
BMD_PUBLIC IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance_v10_11 (void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame
}
#endif // defined(__cplusplus)
#endif /* defined(BMD_DECKLINKAPI_v10_11_H) */

View file

@ -1,68 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2014 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v10_2_H
#define BMD_DECKLINKAPI_v10_2_H
#include "DeckLinkAPI.h"
// Type Declarations
/* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */
typedef uint32_t BMDDeckLinkConfigurationID_v10_2;
enum _BMDDeckLinkConfigurationID_v10_2 {
/* Video output flags */
bmdDeckLinkConfig3GBpsVideoOutput_v10_2 = '3gbs',
};
/* Enum BMDAudioConnection_v10_2 - Audio connection types */
typedef uint32_t BMDAudioConnection_v10_2;
enum _BMDAudioConnection_v10_2 {
bmdAudioConnectionEmbedded_v10_2 = /* 'embd' */ 0x656D6264,
bmdAudioConnectionAESEBU_v10_2 = /* 'aes ' */ 0x61657320,
bmdAudioConnectionAnalog_v10_2 = /* 'anlg' */ 0x616E6C67,
bmdAudioConnectionAnalogXLR_v10_2 = /* 'axlr' */ 0x61786C72,
bmdAudioConnectionAnalogRCA_v10_2 = /* 'arca' */ 0x61726361
};
#endif /* defined(BMD_DECKLINKAPI_v10_2_H) */

View file

@ -1,58 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2015 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v10_4_H
#define BMD_DECKLINKAPI_v10_4_H
#include "DeckLinkAPI.h"
// Type Declarations
/* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */
typedef uint32_t BMDDeckLinkConfigurationID_v10_4;
enum _BMDDeckLinkConfigurationID_v10_4 {
/* Video output flags */
bmdDeckLinkConfigSingleLinkVideoOutput_v10_4 = /* 'sglo' */ 0x73676C6F,
};
#endif /* defined(BMD_DECKLINKAPI_v10_4_H) */

View file

@ -1,59 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2015 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v10_5_H
#define BMD_DECKLINKAPI_v10_5_H
#include "DeckLinkAPI.h"
// Type Declarations
/* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */
typedef uint32_t BMDDeckLinkAttributeID_v10_5;
enum _BMDDeckLinkAttributeID_v10_5 {
/* Integers */
BMDDeckLinkDeviceBusyState_v10_5 = /* 'dbst' */ 0x64627374,
};
#endif /* defined(BMD_DECKLINKAPI_v10_5_H) */

View file

@ -1,63 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2016 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v10_6_H
#define BMD_DECKLINKAPI_v10_6_H
#include "DeckLinkAPI.h"
// Type Declarations
/* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */
typedef uint32_t BMDDeckLinkAttributeID_c10_6;
enum _BMDDeckLinkAttributeID_v10_6 {
/* Flags */
BMDDeckLinkSupportsDesktopDisplay_v10_6 = /* 'extd' */ 0x65787464,
};
typedef uint32_t BMDIdleVideoOutputOperation_v10_6;
enum _BMDIdleVideoOutputOperation_v10_6 {
bmdIdleVideoOutputDesktop_v10_6 = /* 'desk' */ 0x6465736B
};
#endif /* defined(BMD_DECKLINKAPI_v10_6_H) */

View file

@ -1,58 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2017 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v10_9_H
#define BMD_DECKLINKAPI_v10_9_H
#include "DeckLinkAPI.h"
// Type Declarations
/* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */
typedef uint32_t BMDDeckLinkConfigurationID_v10_9;
enum _BMDDeckLinkConfigurationID_v10_9 {
/* Flags */
bmdDeckLinkConfig1080pNotPsF_v10_9 = 'fpro',
};
#endif /* defined(BMD_DECKLINKAPI_v10_9_H) */

View file

@ -1,113 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2020 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v11_5_H
#define BMD_DECKLINKAPI_v11_5_H
#include "DeckLinkAPI.h"
BMD_CONST REFIID IID_IDeckLinkVideoFrameMetadataExtensions_v11_5 = /* D5973DC9-6432-46D0-8F0B-2496F8A1238F */ {0xD5,0x97,0x3D,0xC9,0x64,0x32,0x46,0xD0,0x8F,0x0B,0x24,0x96,0xF8,0xA1,0x23,0x8F};
/* Enum BMDDeckLinkFrameMetadataID - DeckLink Frame Metadata ID */
typedef uint32_t BMDDeckLinkFrameMetadataID_v11_5;
enum _BMDDeckLinkFrameMetadataID_v11_5 {
bmdDeckLinkFrameMetadataCintelFilmType_v11_5 = /* 'cfty' */ 0x63667479, // Current film type
bmdDeckLinkFrameMetadataCintelFilmGauge_v11_5 = /* 'cfga' */ 0x63666761, // Current film gauge
bmdDeckLinkFrameMetadataCintelKeykodeLow_v11_5 = /* 'ckkl' */ 0x636B6B6C, // Raw keykode value - low 64 bits
bmdDeckLinkFrameMetadataCintelKeykodeHigh_v11_5 = /* 'ckkh' */ 0x636B6B68, // Raw keykode value - high 64 bits
bmdDeckLinkFrameMetadataCintelTile1Size_v11_5 = /* 'ct1s' */ 0x63743173, // Size in bytes of compressed raw tile 1
bmdDeckLinkFrameMetadataCintelTile2Size_v11_5 = /* 'ct2s' */ 0x63743273, // Size in bytes of compressed raw tile 2
bmdDeckLinkFrameMetadataCintelTile3Size_v11_5 = /* 'ct3s' */ 0x63743373, // Size in bytes of compressed raw tile 3
bmdDeckLinkFrameMetadataCintelTile4Size_v11_5 = /* 'ct4s' */ 0x63743473, // Size in bytes of compressed raw tile 4
bmdDeckLinkFrameMetadataCintelImageWidth_v11_5 = /* 'IWPx' */ 0x49575078, // Width in pixels of image
bmdDeckLinkFrameMetadataCintelImageHeight_v11_5 = /* 'IHPx' */ 0x49485078, // Height in pixels of image
bmdDeckLinkFrameMetadataCintelLinearMaskingRedInRed_v11_5 = /* 'mrir' */ 0x6D726972, // Red in red linear masking parameter
bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInRed_v11_5 = /* 'mgir' */ 0x6D676972, // Green in red linear masking parameter
bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInRed_v11_5 = /* 'mbir' */ 0x6D626972, // Blue in red linear masking parameter
bmdDeckLinkFrameMetadataCintelLinearMaskingRedInGreen_v11_5 = /* 'mrig' */ 0x6D726967, // Red in green linear masking parameter
bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInGreen_v11_5 = /* 'mgig' */ 0x6D676967, // Green in green linear masking parameter
bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInGreen_v11_5 = /* 'mbig' */ 0x6D626967, // Blue in green linear masking parameter
bmdDeckLinkFrameMetadataCintelLinearMaskingRedInBlue_v11_5 = /* 'mrib' */ 0x6D726962, // Red in blue linear masking parameter
bmdDeckLinkFrameMetadataCintelLinearMaskingGreenInBlue_v11_5 = /* 'mgib' */ 0x6D676962, // Green in blue linear masking parameter
bmdDeckLinkFrameMetadataCintelLinearMaskingBlueInBlue_v11_5 = /* 'mbib' */ 0x6D626962, // Blue in blue linear masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingRedInRed_v11_5 = /* 'mlrr' */ 0x6D6C7272, // Red in red log masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingGreenInRed_v11_5 = /* 'mlgr' */ 0x6D6C6772, // Green in red log masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingBlueInRed_v11_5 = /* 'mlbr' */ 0x6D6C6272, // Blue in red log masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingRedInGreen_v11_5 = /* 'mlrg' */ 0x6D6C7267, // Red in green log masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingGreenInGreen_v11_5 = /* 'mlgg' */ 0x6D6C6767, // Green in green log masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingBlueInGreen_v11_5 = /* 'mlbg' */ 0x6D6C6267, // Blue in green log masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingRedInBlue_v11_5 = /* 'mlrb' */ 0x6D6C7262, // Red in blue log masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingGreenInBlue_v11_5 = /* 'mlgb' */ 0x6D6C6762, // Green in blue log masking parameter
bmdDeckLinkFrameMetadataCintelLogMaskingBlueInBlue_v11_5 = /* 'mlbb' */ 0x6D6C6262, // Blue in blue log masking parameter
bmdDeckLinkFrameMetadataCintelFilmFrameRate_v11_5 = /* 'cffr' */ 0x63666672, // Film frame rate
bmdDeckLinkFrameMetadataCintelOffsetToApplyHorizontal_v11_5 = /* 'otah' */ 0x6F746168, // Horizontal offset (pixels) to be applied to image
bmdDeckLinkFrameMetadataCintelOffsetToApplyVertical_v11_5 = /* 'otav' */ 0x6F746176, // Vertical offset (pixels) to be applied to image
bmdDeckLinkFrameMetadataCintelGainRed_v11_5 = /* 'LfRd' */ 0x4C665264, // Red gain parameter to apply after log
bmdDeckLinkFrameMetadataCintelGainGreen_v11_5 = /* 'LfGr' */ 0x4C664772, // Green gain parameter to apply after log
bmdDeckLinkFrameMetadataCintelGainBlue_v11_5 = /* 'LfBl' */ 0x4C66426C, // Blue gain parameter to apply after log
bmdDeckLinkFrameMetadataCintelLiftRed_v11_5 = /* 'GnRd' */ 0x476E5264, // Red lift parameter to apply after log and gain
bmdDeckLinkFrameMetadataCintelLiftGreen_v11_5 = /* 'GnGr' */ 0x476E4772, // Green lift parameter to apply after log and gain
bmdDeckLinkFrameMetadataCintelLiftBlue_v11_5 = /* 'GnBl' */ 0x476E426C, // Blue lift parameter to apply after log and gain
bmdDeckLinkFrameMetadataCintelHDRGainRed_v11_5 = /* 'HGRd' */ 0x48475264, // Red gain parameter to apply to linear data for HDR Combination
bmdDeckLinkFrameMetadataCintelHDRGainGreen_v11_5 = /* 'HGGr' */ 0x48474772, // Green gain parameter to apply to linear data for HDR Combination
bmdDeckLinkFrameMetadataCintelHDRGainBlue_v11_5 = /* 'HGBl' */ 0x4847426C, // Blue gain parameter to apply to linear data for HDR Combination
bmdDeckLinkFrameMetadataCintel16mmCropRequired_v11_5 = /* 'c16c' */ 0x63313663, // The image should be cropped to 16mm size
bmdDeckLinkFrameMetadataCintelInversionRequired_v11_5 = /* 'cinv' */ 0x63696E76, // The image should be colour inverted
bmdDeckLinkFrameMetadataCintelFlipRequired_v11_5 = /* 'cflr' */ 0x63666C72, // The image should be flipped horizontally
bmdDeckLinkFrameMetadataCintelFocusAssistEnabled_v11_5 = /* 'cfae' */ 0x63666165, // Focus Assist is currently enabled
bmdDeckLinkFrameMetadataCintelKeykodeIsInterpolated_v11_5 = /* 'kkii' */ 0x6B6B6969 // The keykode for this frame is interpolated from nearby keykodes
};
/* Interface IDeckLinkVideoFrameMetadataExtensions - Optional interface implemented on IDeckLinkVideoFrame to support frame metadata such as HDMI HDR information */
class BMD_PUBLIC IDeckLinkVideoFrameMetadataExtensions_v11_5 : public IUnknown
{
public:
virtual HRESULT GetInt (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ int64_t *value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ double *value) = 0;
virtual HRESULT GetFlag (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ bool* value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkFrameMetadataID_v11_5 metadataID, /* out */ const char **value) = 0;
protected:
virtual ~IDeckLinkVideoFrameMetadataExtensions_v11_5 () {} // call Release method to drop reference count
};
#endif /* defined(BMD_DECKLINKAPI_v11_5_H) */

View file

@ -1,57 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2020 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v11_5_1_H
#define BMD_DECKLINKAPI_v11_5_1_H
#include "DeckLinkAPI.h"
/* Enum BMDDeckLinkStatusID - DeckLink Status ID */
typedef uint32_t BMDDeckLinkStatusID_v11_5_1;
enum _BMDDeckLinkStatusID_v11_5_1 {
/* Video output flags */
bmdDeckLinkStatusDetectedVideoInputFlags_v11_5_1 = /* 'dvif' */ 0x64766966,
};
#endif /* defined(BMD_DECKLINKAPI_v11_5_1_H) */

View file

@ -1,110 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2018 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v14_2_1_H
#define BMD_DECKLINKAPI_v14_2_1_H
#include "DeckLinkAPI.h"
#include "DeckLinkAPIVideoConversion_v14_2_1.h"
#include "DeckLinkAPIGLScreenPreview_v14_2_1.h"
#include "DeckLinkAPIMetalScreenPreview_v14_2_1.h"
#include "DeckLinkAPIScreenPreviewCallback_v14_2_1.h"
#include "DeckLinkAPIVideoOutput_v14_2_1.h"
#include "DeckLinkAPIVideoInput_v14_2_1.h"
#include "DeckLinkAPIVideoFrame3DExtensions_v14_2_1.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkEncoderInput_v14_2_1 = /* F222551D-13DF-4FD8-B587-9D4F19EC12C9 */ { 0xF2,0x22,0x55,0x1D,0x13,0xDF,0x4F,0xD8,0xB5,0x87,0x9D,0x4F,0x19,0xEC,0x12,0xC9 };
#if defined(__cplusplus)
/* Interface IDeckLinkEncoderInput - Created by QueryInterface from IDeckLink. */
class BMD_PUBLIC IDeckLinkEncoderInput_v14_2_1 : public IUnknown
{
public:
virtual HRESULT DoesSupportVideoMode (/* in */ BMDVideoConnection connection /* If a value of bmdVideoConnectionUnspecified is specified, the caller does not care about the connection */, /* in */ BMDDisplayMode requestedMode, /* in */ BMDPixelFormat requestedCodec, /* in */ uint32_t requestedCodecProfile, /* in */ BMDSupportedVideoModeFlags flags, /* out */ bool* supported) = 0;
virtual HRESULT GetDisplayMode (/* in */ BMDDisplayMode displayMode, /* out */ IDeckLinkDisplayMode** resultDisplayMode) = 0;
virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator** iterator) = 0;
/* Video Input */
virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0;
virtual HRESULT DisableVideoInput (void) = 0;
virtual HRESULT GetAvailablePacketsCount (/* out */ uint32_t* availablePacketsCount) = 0;
virtual HRESULT SetMemoryAllocator (/* in */ IDeckLinkMemoryAllocator_v14_2_1* theAllocator) = 0;
/* Audio Input */
virtual HRESULT EnableAudioInput (/* in */ BMDAudioFormat audioFormat, /* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0;
virtual HRESULT DisableAudioInput (void) = 0;
virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t* availableSampleFrameCount) = 0;
/* Input Control */
virtual HRESULT StartStreams (void) = 0;
virtual HRESULT StopStreams (void) = 0;
virtual HRESULT PauseStreams (void) = 0;
virtual HRESULT FlushStreams (void) = 0;
virtual HRESULT SetCallback (/* in */ IDeckLinkEncoderInputCallback* theCallback) = 0;
/* Hardware Timing */
virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue* hardwareTime, /* out */ BMDTimeValue* timeInFrame, /* out */ BMDTimeValue* ticksPerFrame) = 0;
protected:
virtual ~IDeckLinkEncoderInput_v14_2_1 () {} // call Release method to drop reference count
};
/* Functions */
extern "C" {
BMD_PUBLIC IDeckLinkIterator* CreateDeckLinkIteratorInstance_v14_2_1(void);
BMD_PUBLIC IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance_v14_2_1(void);
BMD_PUBLIC IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance_v14_2_1(void);
BMD_PUBLIC IDeckLinkGLScreenPreviewHelper_v14_2_1* CreateOpenGLScreenPreviewHelper_v14_2_1(void);
BMD_PUBLIC IDeckLinkGLScreenPreviewHelper_v14_2_1* CreateOpenGL3ScreenPreviewHelper_v14_2_1(void); // Requires OpenGL 3.2 support and provides improved performance and color handling
BMD_PUBLIC IDeckLinkVideoConversion_v14_2_1* CreateVideoConversionInstance_v14_2_1(void);
BMD_PUBLIC IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance_v14_2_1(void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame
}
#endif // defined(__cplusplus)
#endif /* defined(BMD_DECKLINKAPI_v14_2_1_H) */

View file

@ -1,96 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2025 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef BMD_DECKLINKAPI_v15_2_H
#define BMD_DECKLINKAPI_v15_2_H
#include "DeckLinkAPI.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkAncillaryPacket_v15_2 = /* CC5BBF7E-029C-4D3B-9158-6000EF5E3670 */ { 0xCC,0x5B,0xBF,0x7E,0x02,0x9C,0x4D,0x3B,0x91,0x58,0x60,0x00,0xEF,0x5E,0x36,0x70 };
BMD_CONST REFIID IID_IDeckLinkAncillaryPacketIterator_v15_2 = /* 3FC8994B-88FB-4C17-968F-9AAB69D964A7 */ { 0x3F,0xC8,0x99,0x4B,0x88,0xFB,0x4C,0x17,0x96,0x8F,0x9A,0xAB,0x69,0xD9,0x64,0xA7 };
BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillaryPackets_v15_2 = /* 6C186C0F-459E-41D8-AEE2-4812D81AEE68 */ { 0x6C,0x18,0x6C,0x0F,0x45,0x9E,0x41,0xD8,0xAE,0xE2,0x48,0x12,0xD8,0x1A,0xEE,0x68 };
/* Interface IDeckLinkAncillaryPacket - On output, user needs to implement this interface */
#if defined(__cplusplus)
class BMD_PUBLIC IDeckLinkAncillaryPacket_v15_2 : public IUnknown
{
public:
virtual HRESULT GetBytes (/* in */ BMDAncillaryPacketFormat format /* For output, only one format need be offered */, /* out */ const void** data /* Optional */, /* out */ uint32_t* size /* Optional */) = 0;
virtual uint8_t GetDID (void) = 0;
virtual uint8_t GetSDID (void) = 0;
virtual uint32_t GetLineNumber (void) = 0; // On output, zero is auto
virtual uint8_t GetDataStreamIndex (void) = 0; // Usually zero. Can only be 1 if non-SD and the first data stream is completely full
protected:
virtual ~IDeckLinkAncillaryPacket_v15_2 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkAncillaryPacketIterator - Enumerates ancillary packets */
class BMD_PUBLIC IDeckLinkAncillaryPacketIterator_v15_2 : public IUnknown
{
public:
virtual HRESULT Next (/* out */ IDeckLinkAncillaryPacket_v15_2** packet) = 0;
protected:
virtual ~IDeckLinkAncillaryPacketIterator_v15_2 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkVideoFrameAncillaryPackets - Obtained through QueryInterface on an IDeckLinkVideoFrame object. */
class BMD_PUBLIC IDeckLinkVideoFrameAncillaryPackets_v15_2 : public IUnknown
{
public:
virtual HRESULT GetPacketIterator (/* out */ IDeckLinkAncillaryPacketIterator_v15_2** iterator) = 0;
virtual HRESULT GetFirstPacketByID (/* in */ uint8_t DID, /* in */ uint8_t SDID, /* out */ IDeckLinkAncillaryPacket_v15_2** packet) = 0;
virtual HRESULT AttachPacket (/* in */ IDeckLinkAncillaryPacket_v15_2* packet) = 0; // Implement IDeckLinkAncillaryPacket to output your own
virtual HRESULT DetachPacket (/* in */ IDeckLinkAncillaryPacket_v15_2* packet) = 0;
virtual HRESULT DetachAllPackets (void) = 0;
protected:
virtual ~IDeckLinkVideoFrameAncillaryPackets_v15_2 () {} // call Release method to drop reference count
};
#endif /* defined(__cplusplus) */
#endif /* defined(BMD_DECKLINKAPI_H) */

View file

@ -1,189 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2025 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit (EULA) available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#pragma once
#include "DeckLinkAPI.h"
// Interface ID Declarations
BMD_CONST REFIID IID_IDeckLinkStatus_v15_3_1 = /* 5F558200-4028-49BC-BEAC-DB3FA4A96E46 */ { 0x5F,0x55,0x82,0x00,0x40,0x28,0x49,0xBC,0xBE,0xAC,0xDB,0x3F,0xA4,0xA9,0x6E,0x46 };
BMD_CONST REFIID IID_IDeckLinkVideoBuffer_v15_3_1 = /* CCB4B64A-5C86-4E02-B778-885D352709FE */ { 0xCC,0xB4,0xB6,0x4A,0x5C,0x86,0x4E,0x02,0xB7,0x78,0x88,0x5D,0x35,0x27,0x09,0xFE };
BMD_CONST REFIID IID_IDeckLinkVideoBufferAllocator_v15_3_1 = /* 3481A4DF-2B11-4E55-AC61-836B87985E9A */ { 0x34,0x81,0xA4,0xDF,0x2B,0x11,0x4E,0x55,0xAC,0x61,0x83,0x6B,0x87,0x98,0x5E,0x9A };
BMD_CONST REFIID IID_IDeckLinkVideoBufferAllocatorProvider_v15_3_1 = /* 08B80403-BFF2-49D0-B448-8C908B9E9FC9 */ { 0x08,0xB8,0x04,0x03,0xBF,0xF2,0x49,0xD0,0xB4,0x48,0x8C,0x90,0x8B,0x9E,0x9F,0xC9 };
BMD_CONST REFIID IID_IDeckLinkVideoConversion_v15_3_1 = /* A48755D9-8BD5-4727-A1E9-069FDEDBA6E9 */ { 0xA4,0x87,0x55,0xD9,0x8B,0xD5,0x47,0x27,0xA1,0xE9,0x06,0x9F,0xDE,0xDB,0xA6,0xE9 };
BMD_CONST REFIID IID_IDeckLinkProfileAttributes_v15_3_1 = /* 17D4BF8E-4911-473A-80A0-731CF6FF345B */ { 0x17,0xD4,0xBF,0x8E,0x49,0x11,0x47,0x3A,0x80,0xA0,0x73,0x1C,0xF6,0xFF,0x34,0x5B };
BMD_CONST REFIID IID_IDeckLinkNotification_v15_3_1 = /* B85DF4C8-BDF5-47C1-8064-28162EBDD4EB */ { 0xB8,0x5D,0xF4,0xC8,0xBD,0xF5,0x47,0xC1,0x80,0x64,0x28,0x16,0x2E,0xBD,0xD4,0xEB };
#if defined(__cplusplus)
/* Enum BMDDeckLinkStatusID_v15_3_1 - DeckLink Status ID */
typedef uint32_t BMDDeckLinkStatusID_v15_3_1;
enum _BMDDeckLinkStatusID_v15_3_1
{
/* Integers */
bmdDeckLinkStatusDeviceTemperature_v15_3_1 = /* 'dtmp' */ 0x64746D70,
bmdDeckLinkStatusEthernetLink_v15_3_1 = /* 'sels' */ 0x73656C73,
bmdDeckLinkStatusEthernetLinkMbps_v15_3_1 = /* 'sesp' */ 0x73657370,
/* Strings */
bmdDeckLinkStatusEthernetLocalIPAddress_v15_3_1 = /* 'seip' */ 0x73656970,
bmdDeckLinkStatusEthernetSubnetMask_v15_3_1 = /* 'sesm' */ 0x7365736D,
bmdDeckLinkStatusEthernetGatewayIPAddress_v15_3_1 = /* 'segw' */ 0x73656777,
bmdDeckLinkStatusEthernetPrimaryDNS_v15_3_1 = /* 'sepd' */ 0x73657064,
bmdDeckLinkStatusEthernetSecondaryDNS_v15_3_1 = /* 'sesd' */ 0x73657364,
bmdDeckLinkStatusEthernetVideoOutputAddress_v15_3_1 = /* 'soav' */ 0x736F6176,
bmdDeckLinkStatusEthernetAudioOutputAddress_v15_3_1 = /* 'soaa' */ 0x736F6161,
bmdDeckLinkStatusEthernetAncillaryOutputAddress_v15_3_1 = /* 'soaA' */ 0x736F6141,
};
/* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */
typedef uint32_t BMDDeckLinkAttributeID_v15_3_1;
enum _BMDDeckLinkAttributeID_v15_3_1
{
/* Strings */
BMDDeckLinkEthernetMACAddress_v15_3_1 = /* 'eMAC' */ 0x654D4143,
};
/* Interface IDeckLinkStatus_v15_3_1 - DeckLink Status interface */
class BMD_PUBLIC IDeckLinkStatus_v15_3_1 : public IUnknown
{
public:
virtual HRESULT GetFlag (/* in */ BMDDeckLinkStatusID statusID, /* out */ bool* value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkStatusID statusID, /* out */ int64_t* value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkStatusID statusID, /* out */ double* value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkStatusID statusID, /* out */ const char** value) = 0;
virtual HRESULT GetBytes (/* in */ BMDDeckLinkStatusID statusID, /* out */ void* buffer, /* in, out */ uint32_t* bufferSize) = 0;
protected:
virtual ~IDeckLinkStatus_v15_3_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkVideoBuffer_v15_3_1 - Interface to encapsulate a video frame buffer; can be caller-implemented. */
class BMD_PUBLIC IDeckLinkVideoBuffer_v15_3_1 : public IUnknown
{
public:
virtual HRESULT GetBytes (/* out */ void** buffer) = 0;
virtual HRESULT StartAccess (/* in */ BMDBufferAccessFlags flags) = 0;
virtual HRESULT EndAccess (/* in */ BMDBufferAccessFlags flags) = 0;
protected:
virtual ~IDeckLinkVideoBuffer_v15_3_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkVideoBufferAllocator_v15_3_1 - Buffer allocator for video. */
class BMD_PUBLIC IDeckLinkVideoBufferAllocator_v15_3_1 : public IUnknown
{
public:
virtual HRESULT AllocateVideoBuffer (/* out */ IDeckLinkVideoBuffer_v15_3_1** allocatedBuffer) = 0;
protected:
virtual ~IDeckLinkVideoBufferAllocator_v15_3_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkVideoBufferAllocatorProvider_v15_3_1 - Allows EnableVideoInputWithAllocatorProvider to obtain allocators */
class BMD_PUBLIC IDeckLinkVideoBufferAllocatorProvider_v15_3_1 : public IUnknown
{
public:
virtual HRESULT GetVideoBufferAllocator (/* in */ uint32_t bufferSize, /* in */ uint32_t width, /* in */ uint32_t height, /* in */ uint32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoBufferAllocator_v15_3_1** allocator) = 0;
protected:
virtual ~IDeckLinkVideoBufferAllocatorProvider_v15_3_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkVideoConversion_v15_3_1 */
class BMD_PUBLIC IDeckLinkVideoConversion_v15_3_1 : public IUnknown
{
public:
virtual HRESULT ConvertFrame (/* in */ IDeckLinkVideoFrame* srcFrame, /* in */ IDeckLinkVideoFrame* dstFrame) = 0;
virtual HRESULT ConvertNewFrame (/* in */ IDeckLinkVideoFrame* srcFrame, /* in */ BMDPixelFormat dstPixelFormat, /* in */ BMDColorspace dstColorspace, /* in */ IDeckLinkVideoBuffer_v15_3_1* dstBuffer, /* out */ IDeckLinkVideoFrame** dstFrame) = 0;
protected:
virtual ~IDeckLinkVideoConversion_v15_3_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkProfileAttributes_v15_3_1 - Created by QueryInterface from an IDeckLinkProfile, or from IDeckLink. When queried from IDeckLink, interrogates the active profile */
class BMD_PUBLIC IDeckLinkProfileAttributes_v15_3_1 : public IUnknown
{
public:
virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool* value) = 0;
virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t* value) = 0;
virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double* value) = 0;
virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char** value) = 0;
protected:
virtual ~IDeckLinkProfileAttributes_v15_3_1 () {} // call Release method to drop reference count
};
/* Interface IDeckLinkNotification_v15_3_1 - DeckLink Notification interface */
class BMD_PUBLIC IDeckLinkNotification_v15_3_1 : public IUnknown
{
public:
virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0;
virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0;
protected:
virtual ~IDeckLinkNotification_v15_3_1 () {} // call Release method to drop reference count
};
/* Functions */
extern "C"
{
BMD_PUBLIC IDeckLinkIterator* CreateDeckLinkIteratorInstance_v15_3_1(void);
BMD_PUBLIC IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance_v15_3_1(void);
BMD_PUBLIC IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance_v15_3_1(void);
BMD_PUBLIC IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper_v15_3_1(void);
BMD_PUBLIC IDeckLinkGLScreenPreviewHelper* CreateOpenGL3ScreenPreviewHelper_v15_3_1(void); // Requires OpenGL 3.2 support and provides improved performance and color handling
BMD_PUBLIC IDeckLinkVideoConversion_v15_3_1* CreateVideoConversionInstance_v15_3_1(void);
BMD_PUBLIC IDeckLinkVideoFrameAncillaryPackets* CreateVideoFrameAncillaryPacketsInstance_v15_3_1(void); // For use when creating a custom IDeckLinkVideoFrame without wrapping IDeckLinkOutput::CreateVideoFrame
}
#endif // defined(__cplusplus)

View file

@ -1,116 +0,0 @@
/* -LICENSE-START-
** Copyright (c) 2009 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation (the
** "Software") to use, reproduce, display, distribute, sub-license, execute,
** and transmit the Software, and to prepare derivative works of the Software,
** and to permit third-parties to whom the Software is furnished to do so, in
** accordance with:
**
** (1) if the Software is obtained from Blackmagic Design, the End User License
** Agreement for the Software Development Kit ("EULA") available at
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
**
** (2) if the Software is obtained from any third party, such licensing terms
** as notified by that third party,
**
** and all subject to the following:
**
** (3) the copyright notices in the Software and this entire statement,
** including the above license grant, this restriction and the following
** disclaimer, must be included in all copies of the Software, in whole or in
** part, and all derivative works of the Software, unless such copies or
** derivative works are solely in the form of machine-executable object code
** generated by a source language processor.
**
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
** A copy of the Software is available free of charge at
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
**
** -LICENSE-END-
*/
#ifndef __LINUX_COM_H_
#define __LINUX_COM_H_
struct REFIID
{
unsigned char byte0;
unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
unsigned char byte4;
unsigned char byte5;
unsigned char byte6;
unsigned char byte7;
unsigned char byte8;
unsigned char byte9;
unsigned char byte10;
unsigned char byte11;
unsigned char byte12;
unsigned char byte13;
unsigned char byte14;
unsigned char byte15;
};
typedef REFIID CFUUIDBytes;
#define CFUUIDGetUUIDBytes(x) x
typedef int HRESULT;
typedef unsigned long ULONG;
typedef void *LPVOID;
#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
#define FAILED(Status) ((HRESULT)(Status)<0)
#define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR)
#define HRESULT_CODE(hr) ((hr) & 0xFFFF)
#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff)
#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1)
#define SEVERITY_SUCCESS 0
#define SEVERITY_ERROR 1
#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
#define S_OK ((HRESULT)0x00000000L)
#define S_FALSE ((HRESULT)0x00000001L)
#define E_UNEXPECTED ((HRESULT)0x8000FFFFL)
#define E_NOTIMPL ((HRESULT)0x80000001L)
#define E_OUTOFMEMORY ((HRESULT)0x80000002L)
#define E_INVALIDARG ((HRESULT)0x80000003L)
#define E_NOINTERFACE ((HRESULT)0x80000004L)
#define E_POINTER ((HRESULT)0x80000005L)
#define E_HANDLE ((HRESULT)0x80000006L)
#define E_ABORT ((HRESULT)0x80000007L)
#define E_FAIL ((HRESULT)0x80000008L)
#define E_ACCESSDENIED ((HRESULT)0x80000009L)
#define STDMETHODCALLTYPE
#define IID_IUnknown (REFIID){0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}
#define IUnknownUUID IID_IUnknown
#ifndef BMD_PUBLIC
#define BMD_PUBLIC
#endif
#ifdef __cplusplus
class BMD_PUBLIC IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
};
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,6 @@ dotenv.config();
const app = express(); const app = express();
const PORT = process.env.PORT || 3001; const PORT = process.env.PORT || 3001;
const MAM_API_URL = process.env.MAM_API_URL || 'http://mam-api:3000'; const MAM_API_URL = process.env.MAM_API_URL || 'http://mam-api:3000';
const MAM_API_TOKEN = process.env.MAM_API_TOKEN || '';
app.use(cors()); app.use(cors());
app.use(express.json()); app.use(express.json());
@ -129,42 +128,17 @@ async function gracefulShutdown(signal) {
try { try {
await fetch(`${MAM_API_URL}/api/v1/assets/${liveAssetId}/mark-empty`, { await fetch(`${MAM_API_URL}/api/v1/assets/${liveAssetId}/mark-empty`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json', ...(MAM_API_TOKEN ? { 'Authorization': `Bearer ${MAM_API_TOKEN}` } : {}) }, headers: { 'Content-Type': 'application/json' },
}); });
} catch (e) { } catch (e) {
console.error('[shutdown] failed to flag empty asset:', e.message); console.error('[shutdown] failed to flag empty asset:', e.message);
} }
} }
} else if (completed.growingPath) {
// Growing-files recorder: the master lives on the SMB share as a .ts,
// NOT in S3 yet. The promotion worker (which watches the same share)
// uploads it to S3 and enqueues the proxy from the real, finalized key.
// We must NOT call /finalize here: that sets original_s3_key to a key
// that doesn't exist yet and enqueues a proxy that instantly fails with
// "unable to open the file on disk." Leave the asset 'live' for the
// promotion worker to flip to 'ready'.
console.log(`[shutdown] growing capture finalized on share (${completed.growingPath}); leaving promotion worker to upload + proxy`);
} else if (liveAssetId) {
// Finalise the pre-created live asset by id (avoids POST / 409 collision).
try {
const res = await fetch(`${MAM_API_URL}/api/v1/assets/${liveAssetId}/finalize`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...(MAM_API_TOKEN ? { 'Authorization': `Bearer ${MAM_API_TOKEN}` } : {}) },
body: JSON.stringify({ hiresKey: completed.hiresKey, proxyKey: completed.proxyKey, duration: completed.duration }),
});
if (!res.ok) {
console.warn(`[shutdown] mam-api finalize returned ${res.status}: ${await res.text()}`);
} else {
console.log('[shutdown] live asset finalised with mam-api');
}
} catch (mamErr) {
console.error('[shutdown] failed to finalise asset:', mamErr.message);
}
} else { } else {
try { try {
const res = await fetch(`${MAM_API_URL}/api/v1/assets`, { const res = await fetch(`${MAM_API_URL}/api/v1/assets`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json', ...(MAM_API_TOKEN ? { 'Authorization': `Bearer ${MAM_API_TOKEN}` } : {}) }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
projectId: completed.projectId, projectId: completed.projectId,
binId: completed.binId, binId: completed.binId,

View file

@ -1,6 +1,5 @@
import express from 'express'; import express from 'express';
import { execSync, spawn } from 'child_process'; import { execSync, spawn } from 'child_process';
import { existsSync, readdirSync } from 'node:fs';
import captureManager from '../capture-manager.js'; import captureManager from '../capture-manager.js';
import dgram from 'dgram'; import dgram from 'dgram';
@ -96,8 +95,8 @@ router.get('/devices', (req, res) => {
output = error.stderr ? error.stderr.toString() : error.toString(); output = error.stderr ? error.stderr.toString() : error.toString();
} }
// Parse ffmpeg output for DeckLink device names. // Parse ffmpeg output for DeckLink device names
// DeckLink source lines: " 81:76669a80:00000000 [DeckLink Duo (1)] (none)" // Format: [decklink @ ...] "DeckLink Quad 2" (input #0)
const lines = output.split('\n'); const lines = output.split('\n');
let deviceIndex = 0; let deviceIndex = 0;
@ -119,57 +118,6 @@ router.get('/devices', (req, res) => {
} }
}); });
/**
* GET /devices/deltacast
* List available Deltacast ports.
* Reads /dev/deltacast<N> nodes; falls back to env DELTACAST_PORT_COUNT
* so nodes without hardware still report their configured port count
* (test-card mode).
*/
router.get('/devices/deltacast', (req, res) => {
try {
const devices = [];
// First: enumerate actual /dev/deltacast* device nodes.
try {
const devEntries = readdirSync('/dev').filter(n => /^deltacast\d+$/.test(n));
devEntries.sort();
for (const entry of devEntries) {
const m = entry.match(/^deltacast(\d+)$/);
if (m) {
devices.push({
index: parseInt(m[1], 10),
name: `Deltacast Port ${m[1]}`,
device: `/dev/${entry}`,
present: true,
});
}
}
} catch (_) { /* /dev always exists; ignore */ }
// Second: if DELTACAST_PORT_COUNT env is set and larger than what we found,
// fill in the remaining slots as test-card entries (no physical device).
const envCount = parseInt(process.env.DELTACAST_PORT_COUNT || '0', 10);
const found = new Set(devices.map(d => d.index));
for (let i = 0; i < envCount; i++) {
if (!found.has(i)) {
devices.push({
index: i,
name: `Deltacast Port ${i} (test card)`,
device: `/dev/deltacast${i}`,
present: false,
});
}
}
devices.sort((a, b) => a.index - b.index);
res.json({ devices });
} catch (error) {
console.error('Error listing Deltacast devices:', error);
res.status(500).json({ error: 'Failed to list Deltacast devices' });
}
});
/** /**
* GET /status * GET /status
* Get current capture status * Get current capture status
@ -202,28 +150,6 @@ router.post('/probe', async (req, res) => {
} }
} }
if (source_type === 'deltacast') {
// Enumerate /dev/deltacast* nodes; report present/absent per index.
try {
const envCount = parseInt(process.env.DELTACAST_PORT_COUNT || '0', 10);
const devEntries = readdirSync('/dev').filter(n => /^deltacast\d+$/.test(n)).sort();
const found = devEntries.map(n => {
const m = n.match(/^deltacast(\d+)$/);
return { index: parseInt(m[1], 10), device: `/dev/${n}`, present: true };
});
const foundIdx = new Set(found.map(d => d.index));
for (let i = 0; i < envCount; i++) {
if (!foundIdx.has(i)) {
found.push({ index: i, device: `/dev/deltacast${i}`, present: false });
}
}
found.sort((a, b) => a.index - b.index);
return res.json({ ok: true, source_type, devices: found });
} catch (err) {
return res.json({ ok: false, source_type, error: err.message });
}
}
if (listen) { if (listen) {
return res.json({ ok: false, source_type, error: 'Listener-mode sources cannot be probed standalone. Start the recorder and watch the signal indicator.' }); return res.json({ ok: false, source_type, error: 'Listener-mode sources cannot be probed standalone. Start the recorder and watch the signal indicator.' });
} }
@ -325,13 +251,9 @@ router.post('/start', async (req, res) => {
error: `${source_type.toUpperCase()} caller mode requires: source_url`, error: `${source_type.toUpperCase()} caller mode requires: source_url`,
}); });
} }
} else if (source_type === 'deltacast') {
if (device === undefined || device === null) {
return res.status(400).json({ error: 'deltacast source requires: device (board/port index)' });
}
} else { } else {
return res.status(400).json({ return res.status(400).json({
error: `Unknown source_type: ${source_type}. Must be sdi, srt, rtmp, or deltacast`, error: `Unknown source_type: ${source_type}. Must be sdi, srt, or rtmp`,
}); });
} }

65
services/editor/.gitignore vendored Normal file
View file

@ -0,0 +1,65 @@
# Dependencies
node_modules/
.pnpm-store/
# Build outputs
dist/
build/
.next/
out/
*.tsbuildinfo
# Environment variables
.env
.env.local
.env.*.local
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Logs
logs/
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
# Testing
coverage/
.nyc_output/
# Temporary files
*.tmp
.cache/
.temp/
.docs/
docs/
# Project-specific
/public/projects/
*.openreel
apps/cloud/
apps/ios
apps/android
# Local files
FEATURES_TWITTER.md
.claude-tasks.md
CLAUDE.md
*-PLAN.md
*-PLAN-*.md
.playwright-mcp/
.wrangler/
mobile-mockup/

2
services/editor/.serena/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/cache
/project.local.yml

View file

@ -0,0 +1,135 @@
# the name by which the project can be referenced within Serena
project_name: "openreel-video"
# list of languages for which language servers are started; choose from:
# al bash clojure cpp csharp
# csharp_omnisharp dart elixir elm erlang
# fortran fsharp go groovy haskell
# java julia kotlin lua markdown
# matlab nix pascal perl php
# php_phpactor powershell python python_jedi r
# rego ruby ruby_solargraph rust scala
# swift terraform toml typescript typescript_vts
# vue yaml zig
# (This list may be outdated. For the current list, see values of Language enum here:
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
# Note:
# - For C, use cpp
# - For JavaScript, use typescript
# - For Free Pascal/Lazarus, use pascal
# Special requirements:
# Some languages require additional setup/installations.
# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
# When using multiple languages, the first language server that supports a given file will be used for that file.
# The first language is the default language and the respective language server will be used as a fallback.
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
languages:
- typescript
# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: "utf-8"
# line ending convention to use when writing source files.
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
line_ending:
# The language backend to use for this project.
# If not set, the global setting from serena_config.yml is used.
# Valid values: LSP, JetBrains
# Note: the backend is fixed at startup. If a project with a different backend
# is activated post-init, an error will be returned.
language_backend:
# whether to use project's .gitignore files to ignore files
ignore_all_files_in_gitignore: true
# list of additional paths to ignore in this project.
# Same syntax as gitignore, so you can use * and **.
# Note: global ignored_paths from serena_config.yml are also applied additively.
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default)
included_optional_tools: []
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
fixed_tools: []
# list of mode names to that are always to be included in the set of active modes
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this setting overrides the global configuration.
# Set this to [] to disable base modes for this project.
# Set this to a list of mode names to always include the respective modes for this project.
base_modes:
# list of mode names that are to be activated by default.
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
# This setting can, in turn, be overridden by CLI parameters (--mode).
default_modes:
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
# time budget (seconds) per tool call for the retrieval of additional symbol information
# such as docstrings or parameter information.
# This overrides the corresponding setting in the global configuration; see the documentation there.
# If null or missing, use the setting from the global configuration.
symbol_info_budget:
# list of regex patterns which, when matched, mark a memory entry as readonly.
# Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: []

View file

@ -0,0 +1,387 @@
# Contributing to OpenReel
Thank you for your interest in contributing to OpenReel! This document provides guidelines and instructions for contributing.
## Table of Contents
- [Code of Conduct](#code-of-conduct)
- [Getting Started](#getting-started)
- [Development Setup](#development-setup)
- [Project Structure](#project-structure)
- [Coding Standards](#coding-standards)
- [Making Changes](#making-changes)
- [Testing](#testing)
- [Submitting Changes](#submitting-changes)
## Code of Conduct
Be respectful, constructive, and professional. We're building something great together!
## Getting Started
### Prerequisites
- Node.js 18 or higher
- pnpm (recommended) or npm
- Git
- Modern browser with WebCodecs support (Chrome 94+, Edge 94+)
### Development Setup
```bash
# 1. Fork and clone the repository
git clone https://github.com/Augani/openreel-video.git
cd openreel-video
# 2. Install dependencies
pnpm install
# 3. Start development server
pnpm dev
# 4. Open browser to http://localhost:5173
```
## Project Structure
```
openreel/
├── apps/
│ └── web/ # Main web application
│ ├── public/ # Static assets
│ └── src/
│ ├── components/ # React components
│ ├── stores/ # State management (Zustand)
│ ├── bridges/ # Core engine bridges
│ └── services/ # Business logic
├── packages/
│ └── core/ # Shared core logic
│ ├── src/
│ │ ├── actions/ # Action system
│ │ ├── video/ # Video processing
│ │ ├── audio/ # Audio processing
│ │ ├── graphics/ # Graphics & SVG
│ │ ├── text/ # Text & titles
│ │ └── export/ # Export engine
│ └── types/ # TypeScript types
```
## Coding Standards
### TypeScript
- **Strict mode**: Always use TypeScript strict mode
- **Types**: Prefer interfaces over types for object shapes
- **No `any`**: Avoid `any` - use `unknown` or proper types
- **Naming**:
- Components: `PascalCase` (e.g., `Timeline`, `Preview`)
- Functions: `camelCase` (e.g., `handleClick`, `processVideo`)
- Constants: `UPPER_SNAKE_CASE` (e.g., `MAX_DURATION`)
- Files: `kebab-case.tsx` or `PascalCase.tsx` for components
### Code Style
```typescript
// ✅ Good
interface VideoClip {
id: string;
duration: number;
startTime: number;
}
function processClip(clip: VideoClip): ProcessedClip {
if (!clip.id) {
throw new Error('Clip ID is required');
}
return {
...clip,
processed: true,
};
}
// ❌ Avoid
function processClip(clip: any) {
console.log('Processing...'); // Remove debug logs
const result = clip; // Unclear what's happening
return result;
}
```
### React Components
```typescript
// ✅ Good
interface TimelineProps {
tracks: Track[];
onClipSelect: (clipId: string) => void;
}
export const Timeline: React.FC<TimelineProps> = ({ tracks, onClipSelect }) => {
const handleClick = useCallback((id: string) => {
onClipSelect(id);
}, [onClipSelect]);
return (
<div className="timeline">
{tracks.map(track => (
<Track key={track.id} track={track} onClick={handleClick} />
))}
</div>
);
};
```
### Comments
- **Do**: Comment complex algorithms and business logic
- **Don't**: Comment obvious code
- **Do**: Add JSDoc for public APIs
- **Don't**: Leave TODO comments without issues
```typescript
// ✅ Good - Explains WHY
// Use binary search for O(log n) performance on large timelines
const clipIndex = binarySearch(clips, targetTime);
// ❌ Bad - States the obvious
// Loop through clips
for (const clip of clips) { }
// ✅ Good - Public API documentation
/**
* Applies a filter to a video clip
* @param clipId - The clip identifier
* @param filter - Filter configuration
* @returns Updated clip with filter applied
*/
export function applyFilter(clipId: string, filter: Filter): Clip {
// ...
}
```
## Making Changes
### 1. Create a Branch
```bash
# Feature branch
git checkout -b feat/add-transition-effects
# Bug fix branch
git checkout -b fix/timeline-scroll-bug
# Documentation
git checkout -b docs/update-contributing-guide
```
### 2. Make Your Changes
- Write clean, self-documenting code
- Follow the existing code style
- Keep commits focused and atomic
- Write meaningful commit messages
### 3. Commit Messages
Follow conventional commits:
```
feat: add crossfade transition effect
fix: resolve timeline scrubbing lag
docs: update API documentation
refactor: simplify video processing pipeline
test: add tests for audio mixer
perf: optimize waveform rendering
```
### 4. Keep Your Branch Updated
```bash
git fetch origin
git rebase origin/main
```
## Testing
### Running Tests
```bash
# Run all tests (watch mode)
pnpm test
# Run tests once (CI mode)
pnpm test:run
# Type checking
pnpm typecheck
# Linting
pnpm lint
```
### Writing Tests
```typescript
import { describe, it, expect } from 'vitest';
import { processClip } from './clip-processor';
describe('processClip', () => {
it('should process a valid clip', () => {
const clip = { id: '123', duration: 10, startTime: 0 };
const result = processClip(clip);
expect(result.processed).toBe(true);
expect(result.id).toBe('123');
});
it('should throw error for invalid clip', () => {
const clip = { id: '', duration: 10, startTime: 0 };
expect(() => processClip(clip)).toThrow('Clip ID is required');
});
});
```
## Submitting Changes
### 1. Push Your Branch
```bash
git push origin feat/your-feature-name
```
### 2. Create a Pull Request
1. Go to GitHub and create a pull request
2. Fill out the PR template:
- **Description**: What does this PR do?
- **Motivation**: Why is this change needed?
- **Testing**: How was this tested?
- **Screenshots**: For UI changes
- **Breaking Changes**: Any breaking changes?
### 3. PR Template
```markdown
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] All tests passing
## Screenshots (if applicable)
[Add screenshots for UI changes]
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No console.log or debug code left
- [ ] Tests pass
```
### 4. Code Review Process
- Respond to feedback promptly
- Make requested changes
- Push updates to the same branch
- Re-request review when ready
## Areas to Contribute
### 🐛 Bug Fixes
- Check [Issues](https://github.com/Augani/openreel-video/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
- Reproduce the bug
- Write a failing test
- Fix the bug
- Verify the test passes
### ✨ New Features
- Discuss in [Discussions](https://github.com/Augani/openreel-video/discussions) first
- Get approval before large changes
- Break into smaller PRs if possible
- Update documentation
### 📖 Documentation
- Fix typos and errors
- Add examples
- Improve clarity
- Add tutorials
### 🎨 Effects & Presets
- Create new video effects
- Add transition effects
- Build color grading presets
- Contribute templates
### 🧪 Testing
- Add missing tests
- Improve test coverage
- Add integration tests
- Performance testing
### 🌍 Translation
- Add new language support
- Improve existing translations
- Fix translation errors
## Development Tips
### Hot Reload
Changes to React components hot reload automatically. For core engine changes, you may need to refresh.
### Debugging
```typescript
// Use browser DevTools
// Set breakpoints in TypeScript source
// Check Network tab for media loading
// Use Performance profiler for optimization
```
### Performance
- Profile before optimizing
- Use Web Workers for heavy processing
- Leverage WebCodecs API for video
- Cache expensive computations
- Use useMemo/useCallback appropriately
### Common Issues
**Issue**: Video won't play
- Check browser support for WebCodecs
- Verify codec support
- Check browser console for errors
**Issue**: Build fails
- Clear node_modules and reinstall
- Check Node.js version (18+)
- Verify pnpm version
**Issue**: Tests fail
- Try running `pnpm test:run` for a single run
- Check for console errors
- Verify test environment setup
- Run `pnpm typecheck` to check for type errors
## Questions?
- **Discord**: [Join our Discord](https://discord.gg/openreeel)
- **Discussions**: [GitHub Discussions](https://github.com/Augani/openreel-video/discussions)
- **Email**: contribute@openreeel.video
## Recognition
Contributors are recognized in:
- README.md contributors section
- GitHub contributors page
- Release notes for significant contributions
Thank you for contributing to OpenReel! 🎬

View file

@ -0,0 +1,19 @@
# syntax=docker/dockerfile:1.6
FROM node:20-alpine AS builder
RUN apk add --no-cache python3 make g++ git bash
RUN corepack enable && corepack prepare pnpm@9.7.0 --activate
WORKDIR /build
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json tsconfig.base.json mediabunny.d.ts ./
COPY apps ./apps
COPY packages ./packages
RUN pnpm install --frozen-lockfile=false
RUN pnpm build:wasm || echo "no wasm build step, continuing"
RUN pnpm --filter @openreel/web build
RUN ls -la apps/web/dist
FROM nginx:alpine AS runtime
RUN rm -rf /usr/share/nginx/html/* /etc/nginx/conf.d/default.conf
COPY --from=builder /build/apps/web/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View file

@ -0,0 +1,20 @@
# Z-AMPP <-> openreel-video integration
Vendored from https://github.com/Augani/openreel-video (MIT). The upstream .git directory was removed so this lives as plain source we can patch freely.
## Files added (Z-AMPP-only, not upstream)
- Dockerfile, nginx.conf, VENDOR.txt, INTEGRATION.md
- apps/web/src/mam-bridge.ts: boot hook + pickFromMAM() modal
- packages/core/src/export/mam-export-target.ts: helpers for upload-to-MAM
## Upstream files patched
- apps/web/package.json: build script changed `tsc --noEmit && vite build` -> `vite build`. Original preserved as build:strict. (upstream tsc fails on pre-existing WebGPU + import.meta errors.)
- apps/web/src/bridges/media-bridge.ts: appended importFromURL(url, name, contentType?) as the last method of the MediaBridge class.
- apps/web/src/main.tsx: appended `import "./mam-bridge";` so the bridge boot hook runs.
## Query params honored
- ?asset=<uuid> auto-imports that asset on load.
- ?project=<uuid> stored in localStorage.mamProjectId for save-to-MAM.
## Ports
Container exposes 80; compose maps ${PORT_EDITOR:-47435}:80.

21
services/editor/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024-2026 Augustus Otu and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

308
services/editor/README.md Normal file
View file

@ -0,0 +1,308 @@
# OpenReel Video
> **The open source CapCut alternative. Professional video editing in your browser. No uploads. No installs. 100% open source.**
OpenReel Video is a fully-featured browser-based video editor that runs entirely client-side. Built with React, TypeScript, WebCodecs, and WebGPU for professional-grade video editing without the need for expensive software or cloud processing.
**[Try it Live](https://openreel.video)** | **[Documentation](CONTRIBUTING.md)** | **[Discussions](https://github.com/Augani/openreel-video/discussions)** | **[Twitter](https://x.com/python_xi)**
![OpenReel Editor](https://img.shields.io/badge/Lines%20of%20Code-130k+-blue) ![License](https://img.shields.io/badge/License-MIT-green) ![Status](https://img.shields.io/badge/Status-Beta-orange) ![Open Source](https://img.shields.io/badge/Open%20Source-100%25-brightgreen)
---
## Why OpenReel?
- **100% Client-Side** - Your videos never leave your device. No uploads, no cloud processing, complete privacy.
- **No Installation** - Works in Chrome/Edge. Just open and start editing.
- **Professional Features** - Multi-track timeline, keyframe animations, color grading, audio effects, and more.
- **GPU Accelerated** - WebGPU and WebCodecs for smooth 4K editing and fast exports.
- **Free Forever** - MIT licensed, no subscriptions, no watermarks.
---
## Features
### Video Editing
- **Multi-track timeline** - Unlimited video, audio, image, text, and graphics tracks
- **Real-time preview** - Smooth playback with GPU acceleration
- **Precision editing** - Frame-accurate scrubbing, cut, trim, split, ripple delete
- **Transitions** - Crossfade, dip to black/white, wipe, slide effects
- **Video effects** - Brightness, contrast, saturation, blur, sharpen, glow, vignette, chroma key
- **Blend modes** - Multiply, screen, overlay, add, subtract, and more
- **Speed control** - 0.25x to 4x with audio pitch preservation
- **Crop & transform** - Position, scale, rotation with 3D perspective
### Graphics & Text
- **Professional text editor** - Rich styling, shadows, outlines, gradients
- **20+ text animations** - Typewriter, fade, slide, bounce, pop, elastic, glitch
- **Karaoke-style subtitles** - Word-by-word highlighting synced to audio
- **Shape tools** - Rectangle, circle, arrow, polygon, star with fill/stroke
- **SVG support** - Import SVGs with color tinting and animations
- **Stickers & emoji** - Built-in library
- **Background generator** - Solid colors, gradients, mesh gradients, patterns
- **Keyframe animations** - Animate any property over time with 20+ easing curves
### Audio
- **Multi-track mixing** - Unlimited audio tracks with real-time mixing
- **Waveform visualization** - Visual audio editing
- **Audio effects** - EQ, compressor, reverb, delay, chorus, flanger, distortion
- **Volume & panning** - Per-clip controls with fade in/out
- **Beat detection** - Auto-generate markers synced to music
- **Audio ducking** - Auto-reduce music when dialog plays
- **Noise reduction** - 3-pass noise removal (tonal, broadband, rumble)
### Color Grading
- **Color wheels** - Lift, gamma, gain controls
- **HSL adjustments** - Hue, saturation, lightness fine-tuning
- **Curves editor** - RGB and individual channel curves
- **LUT support** - Import and apply 3D LUTs
- **Built-in presets** - One-click color grading
### Export
- **MP4 (H.264/H.265)** - Universal compatibility
- **WebM (VP8/VP9/AV1)** - Web-optimized format
- **ProRes** - Professional intermediate format (Proxy, LT, Standard, HQ, 4444)
- **Quality presets** - 4K @ 60fps, 1080p, 720p, 480p
- **Custom settings** - Bitrate, frame rate, codec options, color depth
- **Hardware encoding** - WebCodecs for fast exports
- **AI upscaling** - Enhance resolution with WebGPU shaders
- **Audio export** - MP3, WAV, AAC, FLAC, OGG
- **Image sequences** - JPG, PNG, WebP frame export
- **Progress tracking** - Real-time progress with cancel support
### Professional Tools
- **Unlimited undo/redo** - Full history with recovery
- **Auto-save** - Never lose work (IndexedDB storage)
- **Keyboard shortcuts** - Professional workflow
- **Snap to grid** - Magnetic alignment
- **Track management** - Show/hide, lock/unlock, reorder
- **Subtitle support** - SRT import with customizable styling
- **Screen recording** - Record screen, camera, or both
- **Project sharing** - Export/import project files
### Performance
- **WebGPU rendering** - GPU-accelerated compositing
- **WebCodecs API** - Hardware video decoding/encoding
- **Frame caching** - LRU cache for smooth playback
- **Web Workers** - Background processing
- **4K support** - Edit and export in 4K resolution
---
## Quick Start
### Try Online
Visit **[openreel.video](https://openreel.video)** to start editing immediately.
### Run Locally
```bash
# Clone the repository
git clone https://github.com/Augani/openreel-video.git
cd openreel-video
# Install dependencies (requires Node.js 18+)
pnpm install
# Start development server
pnpm dev
# Open http://localhost:5173
```
### Build for Production
```bash
pnpm build
pnpm preview
```
---
## Browser Requirements
| Browser | Version | Status |
|---------|---------|--------|
| Chrome | 94+ | Full support |
| Edge | 94+ | Full support |
| Firefox | 130+ | Full support |
| Safari | 16.4+ | Full support |
All major browsers now support WebCodecs for hardware-accelerated video encoding/decoding.
**Recommended:**
- 8GB+ RAM
- Dedicated GPU for 4K editing
- Modern multi-core CPU
---
## Architecture
### Monorepo Structure
```
openreel/
├── apps/web/ # React frontend (~66k lines)
│ └── src/
│ ├── components/ # UI components
│ │ └── editor/ # Editor panels (Timeline, Preview, Inspector)
│ ├── stores/ # Zustand state management
│ ├── services/ # Auto-save, shortcuts, screen recording
│ └── bridges/ # Engine coordination
└── packages/core/ # Core engines (~59k lines)
└── src/
├── video/ # Video processing, WebGPU rendering
├── audio/ # Web Audio API, effects, beat detection
├── graphics/ # Canvas/THREE.js, shapes, SVG
├── text/ # Text rendering, animations
├── export/ # MP4/WebM encoding
└── storage/ # IndexedDB, serialization
```
### Key Technologies
- **React 18** + **TypeScript** - Type-safe UI
- **Zustand** - Lightweight state management
- **MediaBunny** - Video/audio processing
- **WebCodecs** - Hardware encoding/decoding
- **WebGPU** - GPU-accelerated rendering
- **Web Audio API** - Professional audio processing
- **THREE.js** - 3D transforms and effects
- **IndexedDB** - Local project storage
### Design Principles
- **Action-based editing** - Every edit is an undoable action
- **Immutable state** - Predictable updates with Zustand
- **Engine separation** - Video, audio, graphics engines are independent
- **Progressive enhancement** - Graceful fallbacks (WebGPU → Canvas2D)
---
## AI-Managed Development
OpenReel is an experiment in AI-assisted open source development. Claude AI helps manage:
- **Issue triage** - Reviews and responds to issues
- **Code implementation** - Writes features and fixes bugs
- **Code review** - Maintains quality standards
- **Documentation** - Keeps docs up to date
Human oversight from Augustus ensures strategic direction and final approval on major changes. All code is public, tested, and follows best practices.
**What this means for contributors:**
- Issues get reviewed quickly (usually within 24 hours)
- Bug fixes ship fast
- Clear, detailed responses to questions
- High code quality standards
---
## Contributing
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
**Ways to contribute:**
- Report bugs with reproduction steps
- Suggest features in Discussions
- Submit PRs for bugs or features
- Improve documentation
- Write tests
- Share effect presets
**Development workflow:**
```bash
# Fork and clone
git clone https://github.com/Augani/openreel-video.git
# Create feature branch
git checkout -b feat/your-feature
# Make changes, then test
pnpm typecheck
pnpm test
pnpm lint
# Commit with conventional commits
git commit -m "feat: add your feature"
# Push and open PR
git push origin feat/your-feature
```
---
## Roadmap
### Completed
- Multi-track timeline with drag-and-drop
- Real-time video preview with GPU acceleration
- Full editing suite (cut, trim, split, transitions)
- Text editor with 20+ animations
- Graphics (shapes, SVG, stickers, backgrounds)
- Audio mixing with effects and beat detection
- Color grading with LUT support
- Keyframe animation system
- Export to MP4/WebM (4K supported)
- Screen recording
- AI upscaling
- Undo/redo with auto-save
### In Progress
- Nested sequences (timeline in timeline)
- Motion tracking
- More export formats (ProRes, GIF)
- Plugin system
### Planned
- Adjustment layers
- Advanced masking
- Audio spectral editing
- Collaborative editing
- Mobile optimization
---
## License
MIT License - Use freely for personal and commercial projects.
See [LICENSE](LICENSE) for details.
---
## Acknowledgments
**Built with:**
- [MediaBunny](https://mediabunny.dev) - Media processing
- [React](https://react.dev) - UI framework
- [Zustand](https://zustand-demo.pmnd.rs/) - State management
- [THREE.js](https://threejs.org) - 3D rendering
- [TailwindCSS](https://tailwindcss.com) - Styling
**Inspired by:**
- DaVinci Resolve - Professional tools done right
- CapCut - Accessible editing for everyone
- Figma - Browser-based professional software
---
## Support
- **GitHub Issues** - Bug reports and feature requests
- **GitHub Discussions** - Questions and community chat
- **Twitter/X** - [@python_xi](https://x.com/python_xi)
---
## $OPENREEL Token
CA: `B7wDnfrdtvdG7SCkRjSMJ6LkVwGWvdWrQ75iV8G9pump`
---
**Built with care by [@python_xi](https://x.com/python_xi) and AI working together.**
*Making professional video editing accessible to everyone. Forever free. Forever open source.*

View file

@ -0,0 +1 @@
Vendored from Augani/openreel-video @ 2026-05-18T01:29:08Z

View file

@ -0,0 +1,70 @@
import js from "@eslint/js";
import tseslint from "@typescript-eslint/eslint-plugin";
import tsparser from "@typescript-eslint/parser";
import reactHooks from "eslint-plugin-react-hooks";
import globals from "globals";
export default [
js.configs.recommended,
{
files: ["**/*.{ts,tsx}"],
languageOptions: {
parser: tsparser,
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
...globals.es2021,
...globals.node,
NodeJS: "readonly",
CanvasTextAlign: "readonly",
CanvasTextBaseline: "readonly",
CanvasLineCap: "readonly",
CanvasLineJoin: "readonly",
CanvasFillRule: "readonly",
GlobalCompositeOperation: "readonly",
ImageBitmap: "readonly",
OffscreenCanvas: "readonly",
OffscreenCanvasRenderingContext2D: "readonly",
React: "readonly",
JSX: "readonly",
},
},
plugins: {
"@typescript-eslint": tseslint,
"react-hooks": reactHooks,
},
rules: {
...tseslint.configs.recommended.rules,
"@typescript-eslint/no-unused-vars": [
"warn",
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
],
"@typescript-eslint/no-explicit-any": "warn",
"no-console": ["warn", { allow: ["warn", "error"] }],
"prefer-const": "warn",
"no-unused-vars": "off",
"no-empty": "warn",
"no-case-declarations": "warn",
"react-hooks/rules-of-hooks": "warn",
"react-hooks/exhaustive-deps": "warn",
},
linterOptions: {
reportUnusedDisableDirectives: false,
},
},
{
ignores: [
"dist/**",
"node_modules/**",
"*.config.js",
"*.config.ts",
"vite.config.ts",
],
},
];

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#22c55e" />
<meta name="description" content="Professional browser-based graphic design editor - Create stunning visuals offline" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=DM+Sans:wght@400;500;700&family=Poppins:wght@300;400;500;600;700;800;900&family=Montserrat:wght@300;400;500;600;700;800;900&family=Playfair+Display:wght@400;500;600;700;800;900&family=Roboto:wght@300;400;500;700;900&family=Open+Sans:wght@300;400;600;700;800&family=Lato:wght@300;400;700;900&family=Oswald:wght@300;400;500;600;700&family=Bebas+Neue&family=Pacifico&family=Lobster&family=Dancing+Script:wght@400;700&family=Great+Vibes&display=swap" rel="stylesheet" />
<title>OpenReel Image - Professional Graphic Design Editor</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').catch(() => {});
});
}
</script>
</body>
</html>

View file

@ -0,0 +1,64 @@
{
"name": "@openreel/image",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build",
"preview": "vite preview",
"deploy": "wrangler pages deploy dist --project-name=openreel-image",
"deploy:preview": "wrangler pages deploy dist --project-name=openreel-image --branch=preview",
"test": "vitest",
"test:run": "vitest run",
"lint": "eslint src",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist node_modules/.vite"
},
"dependencies": {
"@imgly/background-removal": "^1.7.0",
"@openreel/image-core": "workspace:*",
"@openreel/ui": "workspace:*",
"@radix-ui/react-context-menu": "^2.2.16",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slider": "^1.3.6",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^12.23.24",
"lucide-react": "^0.555.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"tailwind-merge": "^3.4.0",
"uuid": "^13.0.0",
"zod": "^4.4.3",
"zustand": "^4.5.2"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^11.0.0",
"@typescript-eslint/eslint-plugin": "^8.53.0",
"@typescript-eslint/parser": "^8.53.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.19",
"eslint": "^9.39.2",
"eslint-plugin-react-hooks": "^7.0.1",
"globals": "^17.0.0",
"jsdom": "^24.1.0",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.4",
"tailwindcss-animate": "^1.0.7",
"typescript": "^5.4.5",
"vite": "^5.3.1",
"vitest": "^1.6.0",
"wrangler": "^3.114.17"
}
}

View file

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

View file

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect width="100" height="100" rx="20" fill="#22c55e"/>
<rect x="20" y="20" width="60" height="60" rx="8" fill="white" fill-opacity="0.9"/>
<circle cx="35" cy="38" r="8" fill="#22c55e"/>
<path d="M20 65 L45 45 L60 55 L80 35 L80 72 A8 8 0 0 1 72 80 L28 80 A8 8 0 0 1 20 72 Z" fill="#22c55e" fill-opacity="0.8"/>
</svg>

After

Width:  |  Height:  |  Size: 389 B

Some files were not shown because too many files have changed in this diff Show more