VAST.Image Library
The VAST.Image library provides image processing, MJPEG streaming, and video mixing capabilities for VASTreaming applications. It supports MJPEG HTTP sources/sinks, static image overlays, real-time video compositing with multiple layers, and GPU-accelerated image processing.
Overview
| Feature | Description |
|---|---|
| MJPEG Server | Serve MJPEG streams over HTTP to clients |
| MJPEG Client | Receive MJPEG streams from cameras and servers |
| Image Source | Static images and text overlays as media sources |
| Mixing Source | Combine multiple video/audio sources with compositing |
| Video Effects | Opacity, crop, rotation, blur, chroma key, fade animations |
| Audio Mixing | Mix multiple audio tracks with volume control |
Requirements
- .NET: .NET 6.0 or later
- Dependencies: VAST.Common, VAST.File (for file sources in MixingSource)
MJPEG Server
Note
MjpegServer is not available as a standalone server. It operates as part of the VAST.Network.StreamingServer infrastructure and is instantiated by the StreamingServer automatically when enabled.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ VAST.Network.StreamingServer │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ VAST.Network.PublishingPoint │ │
│ │ /mjpeg/stream1 │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ Live Media Source │ │ │
│ │ │ (Camera, File, Network Stream) │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ ↓ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ MjpegSink (internal class) │ │ │
│ │ │ (Receives MJPEG frames, sends to clients) │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ MjpegServer (internal class) │ │
│ │ (client context management) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ HttpServer │ │
│ │ (HTTP request/response management, │ │
│ │ based on System.Net.HttpListener or ASP.NET Core) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
Multiple HTTP Clients (browsers, players)
Enabling MJPEG Server
var server = new VAST.Network.StreamingServer();
// Enable MJPEG over HTTP
server.EnableMjpeg = true;
server.MjpegServerParameters = new VAST.Image.JPEG.MjpegServerParameters
{
MjpegPath = "/mjpeg/"
};
server.Start();
Client Access
Clients connect via HTTP GET requests:
http://server:port/mjpeg/stream-name
The server responds with a continuous MJPEG stream using multipart/x-mixed-replace content type.
MJPEG HTTP Source
The MjpegHttpSource class receives MJPEG video streams over HTTP from cameras and streaming servers.
Supported Formats
| Format | Content Type | Description |
|---|---|---|
| Multipart | multipart/x-mixed-replace | Standard MJPEG with boundary separators |
| Continuous | image/jpeg | Borderless stream of JPEG images |
Usage
var source = new VAST.Image.JPEG.MjpegHttpSource();
source.Uri = "http://camera.local/mjpeg/stream";
source.NewStream += (sender, e) =>
{
Console.WriteLine($"Stream: {e.MediaType}");
Console.WriteLine($"Resolution: {e.MediaType.Width}x{e.MediaType.Height}");
};
source.NewSample += (sender, e) =>
{
// Process MJPEG frame
ProcessFrame(e.Sample);
};
source.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
source.Start();
}
};
source.Open();
Authentication
For cameras requiring authentication:
source.Uri = "http://username:password@camera.local/mjpeg/stream";
Note
If the username or password contains special characters, they must be URL-encoded.
Connection Timeout
The source automatically reconnects if no data is received within 60 seconds.
Image Source
The ImageSource class provides static images and text overlays as media sources for use with the mixing source or as standalone video sources.
ImageSource utilizes SkiaSharp in .NET Core or System.Drawing in .NET Framework projects.
Loading Images
var source = new VAST.Image.ImageSource();
// Load from file stream
using (var stream = File.OpenRead("overlay.png"))
{
source.SetImage(stream);
}
source.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
source.Start();
}
};
source.Open();
Async Loading
await source.SetImageAsync(imageStream);
Text Overlays
Render text as an image with full styling support:
var overlay = new VAST.Image.OverlayText
{
Text = "Live Stream",
Location = new VAST.Common.Rect(0, 0, 400, 100),
FontFamily = "Arial",
FontSize = 24,
FontBold = true,
FontColor = "#FFFFFF",
BackgroundColor = "#80000000",
OutlineWidth = 2,
OutlineColor = "#000000",
HorizontalAlignment = VAST.Image.HorizontalAlignment.Center,
VerticalAlignment = VAST.Image.VerticalAlignment.Center
};
source.SetText(overlay);
Supported Image Formats
| Format | Support |
|---|---|
| JPEG | Full |
| PNG | Full (with transparency) |
| BMP | Full |
| GIF | First frame only |
| WebP | .NET Core only |
Mixing Source
The MixingSource class combines multiple video and audio sources into a single output stream with real-time compositing, layer management, and audio mixing.
Operating Modes
MixingSource operates in one of two modes based on the AllowVideoProcessing setting:
| Mode | AllowVideoProcessing | Description |
|---|---|---|
| Compositing | true |
GPU-accelerated compositing with layers, effects, and multiple visible sources |
| Switching | false |
Single source displayed at a time, sources can be switched between |
Compositing Mode (AllowVideoProcessing = true)
When video processing is enabled, the mixing source uses GPU-accelerated compositing to combine multiple sources:
- Multiple sources can be visible simultaneously using layers
- Video effects (opacity, crop, rotation, blur, chroma key) are available
- Fade animations between layer states
- Higher resource usage
Switching Mode (AllowVideoProcessing = false)
When video processing is disabled, the mixing source operates in a simpler switching mode:
- Only one source is displayed at a time
- VideoMixingType must be set to
Single - Sources are switched between using SourceIndex
- Fallback source support via FallbackSourceIndex
- All sources are converted to the output resolution(s)
- Lower resource usage, suitable for simple source switching scenarios
Basic Usage
var mixingSource = new VAST.Image.Mixing.MixingSource();
// Configure the mixing scene
var descriptor = new VAST.Image.Mixing.Descriptor
{
AllowVideoProcessing = true, // enable video compositing
Sources = new List<VAST.Image.Mixing.Source>
{
new VAST.Image.Mixing.Source
{
Uri = "rtsp://camera1.local/stream",
},
new VAST.Image.Mixing.Source
{
Uri = "rtsp://camera2.local/stream",
}
},
Processing = new VAST.Image.Mixing.Processing
{
VideoProcessing = new VAST.Image.Mixing.VideoProcessing
{
Mixing = new VAST.Image.Mixing.VideoMixing
{
Type = Image.Mixing.VideoMixingType.All,
Layers = new List<VAST.Image.Mixing.Layer>
{
new VAST.Image.Mixing.Layer
{
Sources = new List<int> { 0 },
Location = new VAST.Common.Rect(0, 0, 1920, 1080)
},
new VAST.Image.Mixing.Layer
{
Sources = new List<int> { 1 },
Location = new VAST.Common.Rect(1500, 50, 1870, 330),
Opacity = 0.9f
}
},
},
Tracks = new List<VAST.Image.Mixing.VideoTrack>
{
new VAST.Image.Mixing.VideoTrack
{
Index = 0,
Width = 1280,
Height = 720,
Framerate = new VAST.Common.Rational(30),
KeyframeInterval = 30,
Bitrate = 3000000,
Codec = VAST.Common.Codec.H264,
Profile = 66
}
}
},
AudioProcessing = new VAST.Image.Mixing.AudioProcessing
{
Mixing = new VAST.Image.Mixing.AudioMixing
{
Type = VAST.Image.Mixing.AudioMixingType.Single,
SourceIndex = 0,
},
Tracks = new List<VAST.Image.Mixing.AudioTrack>
{
new VAST.Image.Mixing.AudioTrack
{
Index = 1,
SampleRate = 44100,
Channels = 2,
Bitrate = 128000,
Codec = VAST.Common.Codec.AAC,
}
}
}
}
};
mixingSource.Update(descriptor);
mixingSource.NewStream += (sender, e) =>
{
Console.WriteLine($"Output stream: {e.MediaType}");
};
mixingSource.NewSample += (sender, e) =>
{
// Process mixed output
ProcessSample(e.Sample);
};
mixingSource.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
mixingSource.Start();
}
};
mixingSource.Open();
Mixing Configuration Levels
Video and audio mixing settings can be configured at two levels:
| Level | Classes | Description |
|---|---|---|
| Common | VideoProcessing, AudioProcessing | Shared mixing settings applied to all output tracks |
| Track-specific | VideoTrack, AudioTrack | Per-track mixing settings that override common settings |
When mixing is defined at the processing level (common), all output tracks share the same mixing configuration. When mixing is defined at the track level, each track can have its own independent mixing settings.
var processing = new VAST.Image.Mixing.Processing
{
VideoProcessing = new VAST.Image.Mixing.VideoProcessing
{
// Common mixing for all video tracks
Mixing = new VAST.Image.Mixing.VideoMixing { ... },
Tracks = new List<VAST.Image.Mixing.VideoTrack>
{
new VAST.Image.Mixing.VideoTrack
{
Index = 0,
// Track-specific mixing (overrides common)
Mixing = new VAST.Image.Mixing.VideoMixing { ... }
}
}
}
};
Sources
Source position in the Sources list defines source index.
Using Existing Media Sources
Instead of specifying a Uri, you can pass an existing IMediaSource object via the MediaSource property. This is useful when you want to use a capture device, VirtualNetworkSource, or any other pre-configured source:
var descriptor = new VAST.Image.Mixing.Descriptor
{
Sources = new List<VAST.Image.Mixing.Source>
{
new VAST.Image.Mixing.Source
{
MediaSource = captureSource
}
}
};
Source Formats
The Format property specifies how to interpret the source content:
| Format | Description |
|---|---|
text |
Text overlay rendered from Content property containing text string using Decoration settings |
image |
In-memory image data (via Content property with image bytes) |
imagefile |
Static image loaded from file path or uri (PNG, JPG, BMP, GIF, TIFF) |
mediafile |
Media file loaded from file path or uri (MP4, MOV, TS, MP3, WAV, playlists) |
Format is auto-detected from file extension when not explicitly specified.
Video Layers
Layers are composited in z-order (first layer is background, last layer is foreground).
Layer Properties
| Property | Description |
|---|---|
| Sources | List of source indices (their indices) to display |
| Layout | Manual (arranged by user) or Auto (arranged automatically) |
| Location | Position and size on output canvas |
| Crop | Crop source video (left, top, right, bottom margins) |
| Rotation | Rotation angle in degrees (negative = horizontal mirror) |
| Opacity | 0.0 (transparent) to 1.0 (opaque) |
| Stretch | How content fills the layer area |
| FillColor | The fill color for empty areas |
Stretch Modes
| Mode | Description |
|---|---|
| Original | Keep original image size, clip if outside boundaries |
| Preserve | Scale to fit preserving aspect ratio, whole image visible (letterbox/pillarbox) |
| Fill | Stretch to fill boundaries without preserving aspect ratio |
| Zoom | Scale to fill preserving aspect ratio, clip edges if needed |
Video Effects
Apply real-time effects to layers:
var layer = new VAST.Image.Mixing.Layer
{
Sources = new List<int> { 0 },
Location = new VAST.Common.Rect(0, 0, 1920, 1080),
// Brightness/Contrast (-10 to 10)
BrightnessAdjustment = 1.0f,
ContrastAdjustment = -2.0f,
// Blur effect
BlurSize = 5,
// Chroma key (green screen)
ChromaKeyColor = "#00FF00",
ChromaKeyThreshold = 0.1f,
ChromaKeySmoothing = 0.05f
};
Fade Animations
Smooth transitions when layers appear or disappear. Specify either FadeInMsec or FadeOutMsec, not both simultaneously:
// Fade in a new layer
var layer = new VAST.Image.Mixing.Layer
{
Sources = new List<int> { 1 },
Location = new VAST.Common.Rect(100, 100, 500, 400),
FadeInMsec = 500 // 500ms fade in
};
mixingSource.Update(descriptor);
After the animation completes, update the descriptor again with the fade property removed to finalize the transition:
// After fade completes, remove FadeInMsec
layer.FadeInMsec = null;
mixingSource.Update(descriptor);
Audio Mixing
Mix audio from multiple sources with individual volume control:
var descriptor = new VAST.Image.Mixing.Descriptor
{
Processing = new VAST.Image.Mixing.Processing
{
AudioProcessing = new VAST.Image.Mixing.AudioProcessing
{
Mixing = new VAST.Image.Mixing.AudioMixing
{
Type = VAST.Image.Mixing.AudioMixingType.All,
Filters = new List<VAST.Image.Mixing.Filter>
{
new VAST.Image.Mixing.Filter
{
Sources = new List<int> { 0 },
Volume = 1.0f // Full volume
},
new VAST.Image.Mixing.Filter
{
Sources = new List<int> { 1 },
Volume = 0.3f // 30% volume (background)
}
}
},
}
}
};
Output Tracks
MixingSource supports multiple output video and audio tracks, enabling scenarios like adaptive bitrate streaming or multiple audio languages.
Important
VideoTrack.Index and AudioTrack.Index properties must form a consecutive sequence starting from 0 (e.g., 0, 1, 2, ...).
Video Track Properties
| Property | Description |
|---|---|
| Index | Track index (must be consecutive starting from 0) |
| Width | Output width in pixels (0 = use source width) |
| Height | Output height in pixels (0 = use source height) |
| Framerate | Output framerate (null = use source framerate) |
| Bitrate | Bitrate in bits per second |
| Codec | Video codec (H264, H265, etc.) |
| KeyframeInterval | GOP size in frames |
| Profile | Encoder profile |
| Mixing | Track-specific mixing settings |
Audio Track Properties
| Property | Description |
|---|---|
| Index | Track index (must be consecutive starting from 0) |
| SampleRate | Sample rate in Hz (0 = use source rate) |
| Channels | Number of channels (0 = use source channels) |
| Bitrate | Bitrate in bits per second |
| Codec | Audio codec (AAC, MP3, etc.) |
| Mixing | Track-specific mixing settings |
Multiple Output Tracks Example
var processing = new VAST.Image.Mixing.Processing
{
VideoProcessing = new VAST.Image.Mixing.VideoProcessing
{
Tracks = new List<VAST.Image.Mixing.VideoTrack>
{
new VAST.Image.Mixing.VideoTrack
{
Index = 0,
Width = 1920, Height = 1080,
Bitrate = 5000000, Codec = Codec.H264
},
new VAST.Image.Mixing.VideoTrack
{
Index = 1,
Width = 1280, Height = 720,
Bitrate = 2500000, Codec = Codec.H264
},
new VAST.Image.Mixing.VideoTrack
{
Index = 2,
Width = 640, Height = 360,
Bitrate = 800000, Codec = Codec.H264
}
}
},
AudioProcessing = new VAST.Image.Mixing.AudioProcessing
{
Tracks = new List<VAST.Image.Mixing.AudioTrack>
{
new VAST.Image.Mixing.AudioTrack
{
Index = 3,
SampleRate = 48000, Channels = 2,
Bitrate = 128000, Codec = Codec.AAC
}
}
}
};
Audio Level Monitoring
Monitor real-time audio levels from input sources:
mixingSource.AudioNotification += (sender, e) =>
{
Console.WriteLine($"Source {e.SourceUri}: Peak={e.PeakAudioLevel:P0}, Avg={e.AverageAudioLevel:P0}");
};
Dynamic Scene Updates
Update the mixing scene at runtime:
// Keep current descriptor
var currentDescriptor = new ...
// Modify and apply
currentDescriptor.Processing.VideoProcessing.Mixing.Layers[1].Opacity = 0.5f;
mixingSource.Update(currentDescriptor);
Fallback Sources
Configure fallback sources for automatic failover when video compositing is disabled. Use FallbackSourceIndex to specify which source to display when the primary source becomes unavailable:
var descriptor = new VAST.Image.Mixing.Descriptor
{
AllowVideoProcessing = false, // Required for fallback to work
Sources = new List<VAST.Image.Mixing.Source>
{
new VAST.Image.Mixing.Source { Uri = "rtsp://primary-camera/stream" },
new VAST.Image.Mixing.Source { Uri = "fallback.mp4" } // Local file recommended
},
Processing = new VAST.Image.Mixing.Processing
{
VideoProcessing = new VAST.Image.Mixing.VideoProcessing
{
Mixing = new VAST.Image.Mixing.VideoMixing
{
Type = VAST.Image.Mixing.VideoMixingType.Single,
SourceIndex = 0, // Primary source
FallbackSourceIndex = 1 // Fallback when primary unavailable
}
}
}
};
Note
Fallback source switching is only available when AllowVideoProcessing is false and VideoMixingType is Single. It is recommended to use a locally stored image or video file as the fallback source to ensure availability.
Performance Options
| Option | Description |
|---|---|
| AllowVideoProcessing | Enable/disable GPU compositing |
| ForceVideoResampling | Downscale inputs to output resolution early |
| EnableSmoothOutputBuffer | Buffer output for consistent frame delivery |
| EnableZeroLatency | Minimize processing delay by sacrificing precise synchronization and smoothness |
var descriptor = new VAST.Image.Mixing.Descriptor
{
AllowVideoProcessing = true,
ForceVideoResampling = true, // Recommended for many sources
EnableSmoothOutputBuffer = true
};
Preview Output
The mixed video output can be rendered to a video renderer for preview purposes using the Renderer property:
// Assign a video renderer for preview
mixingSource.Renderer = videoRenderer;
The renderer displays the mixed output in addition to outputting samples via the NewSample event.
By default, the renderer is cleared (filled with black) when the mixing source stops. To keep the last rendered frame visible after stopping, set CleanupOnStop to false:
mixingSource.CleanupOnStop = false;
Image Processor Parameters
Configure the image processing backend:
var parameters = new VAST.Image.ImageProcessorParameters
{
ImageFramework = VAST.Image.ImageFramework.OpenGL
};
var mixingSource = new VAST.Image.Mixing.MixingSource(parameters);
Available Frameworks
| Framework | Description |
|---|---|
| Auto | Automatically detected image framework |
| Builtin | Default image processing framework of current OS |
| OpenGL | GPU-accelerated compositing |
| ImageSharp | Software compositing |
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| MJPEG not playing | Wrong content type | Verify camera sends multipart/x-mixed-replace |
| Black output | No sources connected | Check source URIs and network |
| High CPU usage | Software rendering | Enable GPU image processor |
| Audio out of sync | Mismatched sample rates | Ensure consistent audio format |
| Layer not visible | Wrong z-order | Check layer order (last = top) |
Debugging
Enable debug logging to diagnose issues:
VAST.Common.Log.Level = VAST.Common.Log.LogLevel.Debug;
See Also
- Supported Platforms - Platform compatibility matrix
- VAST.Common Library - Core media types and interfaces
- VAST.Codec Library - Video encoders for output
- VAST.File Library - File source with metadata caching
- VAST.Network Library - StreamingServer and publishing points