Real-Time Video Processing in .NET MAUI
π₯ Real-Time Video Processing in .NET MAUI
Applying Live Camera Filters with SKCanvas and SkiaSharp
Mobile applications are increasingly incorporating real-time computer vision, augmented reality, image enhancement, and live camera effects.
Whether you're building:
- πΈ A social media app
- π¨ A photo editing tool
- π€ An AI-powered vision application
- π‘οΈ A barcode or document scanner
- π§ A machine learning camera pipeline β¦you'll eventually need to process camera frames in real time.
Fortunately, combining .NET MAUI with SkiaSharp allows us to build powerful cross-platform video processing experiences using GPU-accelerated rendering and custom filters. In this guide, we'll build a real-time camera processing pipeline capable of:
- π₯ Capturing live camera frames
- π¨ Applying image filters
- β‘ Rendering at interactive frame rates
- π§ Preparing frames for AI/ML inference
- π± Running across Android, iOS, Windows, and MacCatalyst
π§ Understanding the Pipeline
Unlike static image processing:
Image
β
Filter
β
Render
Real-time processing becomes:
Camera
β
Frame Capture
β
Image Processing
β
SKCanvas Rendering
β
Display
This pipeline repeats 30β60 times per second.
β‘ Why Use SkiaSharp?
While MAUI graphics are excellent for standard UI rendering, video processing requires:
- High-frequency drawing
- Pixel manipulation
- Shader support
- Image effects
- GPU acceleration
This makes SkiaSharp an excellent choice.
π GraphicsView vs SKCanvas
| Feature | GraphicsView | SKCanvas |
|---|---|---|
| Basic Drawing | β | β |
| Real-Time Video | β οΈ | β |
| Pixel Processing | β | β |
| Image Filters | β οΈ | β |
| Shaders | Limited | β |
| GPU Rendering | Good | Excellent |
For video processing, SKCanvas is the clear winner.
ποΈ Architecture Overview
A scalable design looks like:
Camera Service
β
Frame Processor
β
Filter Pipeline
β
SKCanvasView
β
Screen
This separation allows filters to evolve independently.
π¦ Required Packages
Install:
dotnet add package SkiaSharp.Views.Maui.Controls
Optionally:
dotnet add package CommunityToolkit.Maui.Camera
or your preferred camera library.
πΈ Capturing Camera Frames
Most camera libraries expose frames as:
byte[]
or
Stream
We convert them into:
SKBitmap
for processing.
π§© Creating the Camera Service
public interface ICameraFrameProvider
{
event EventHandler<SKBitmap> FrameReceived;
}
This abstraction keeps rendering independent from capture.
π¨ SKCanvasView Setup
XAML
<skia:SKCanvasView
x:Name="CameraCanvas"
PaintSurface="OnPaintSurface"/>
Backing Field
private SKBitmap? _currentFrame;
π Receiving Frames
_camera.FrameReceived += (_, frame) =>
{
_currentFrame = frame;
MainThread.BeginInvokeOnMainThread(() =>
{
CameraCanvas.InvalidateSurface();
});
};
Every new frame triggers a redraw.
π₯ Rendering Frames
private void OnPaintSurface(
object sender,
SKPaintSurfaceEventArgs e)
{
var canvas = e.Surface.Canvas;
canvas.Clear();
if (_currentFrame is null)
return;
canvas.DrawBitmap(
_currentFrame,
e.Info.Rect);
}
At this point we have a live camera feed.
π¨ Applying Real-Time Filters
Now comes the fun part.
π Grayscale Filter
private SKColorFilter CreateGrayScaleFilter()
{
return SKColorFilter.CreateColorMatrix(new float[]
{
0.3f,0.3f,0.3f,0,0,
0.59f,0.59f,0.59f,0,0,
0.11f,0.11f,0.11f,0,0,
0,0,0,1,0
});
}
Apply During Rendering
using var paint = new SKPaint
{
ColorFilter = CreateGrayScaleFilter()
};
canvas.DrawBitmap(
_currentFrame,
e.Info.Rect,
paint);
Result: πΈ Live grayscale video.
π Sepia Filter
private SKColorFilter CreateSepiaFilter()
{
return SKColorFilter.CreateColorMatrix(new float[]
{
0.393f,0.769f,0.189f,0,0,
0.349f,0.686f,0.168f,0,0,
0.272f,0.534f,0.131f,0,0,
0,0,0,1,0
});
}
Classic vintage effect.
βοΈ Cool Tone Filter
private SKColorFilter CreateCoolFilter()
{
return SKColorFilter.CreateLighting(
SKColors.LightBlue,
SKColors.Black);
}
Useful for camera enhancement apps.
π₯ Dynamic Filter Switching
Create:
public enum FilterType
{
None,
GrayScale,
Sepia,
Cool
}
Current selection:
private FilterType _currentFilter;
Then:
private SKPaint CreatePaint()
{
return _currentFilter switch
{
FilterType.GrayScale => new SKPaint
{
ColorFilter = CreateGrayScaleFilter()
},
FilterType.Sepia => new SKPaint
{
ColorFilter = CreateSepiaFilter()
},
_ => new SKPaint()
};
}
Now filters can be changed at runtime.
* * *
β‘ Performance Optimization
==========================
Real-time rendering can become expensive quickly.
* * *
1οΈβ£ Reuse Bitmaps
-----------------
Bad:
```csharp
new SKBitmap(...)
every frame. Good:
bitmap.InstallPixels(...)
Reuse buffers whenever possible.
2οΈβ£ Limit Resolution
Processing:
1920x1080
for every frame may be unnecessary. Many apps use:
640x480
or
1280x720
for real-time pipelines.
3οΈβ£ Frame Skipping
Process:
Frame 1 β
Frame 2 β
Frame 3 β
Frame 4 β
This dramatically reduces CPU usage.
4οΈβ£ Background Processing
Never process frames on the UI thread.
await Task.Run(() =>
{
ProcessFrame(bitmap);
});
π§ Integrating AI Processing
One of the most powerful use cases is combining:
- Camera
- SkiaSharp
- TensorFlow Lite Pipeline:
Camera
β
SKBitmap
β
TensorFlow Lite
β
Detection
β
Overlay
Examples:
- Face detection π
- Object recognition π¦
- OCR π
- Barcode scanning π·οΈ
- Pose estimation π
π― Drawing Detection Overlays
Suppose an AI model returns:
public record Detection(
string Label,
SKRect Bounds);
Drawing becomes:
foreach(var detection in detections)
{
canvas.DrawRect(
detection.Bounds,
overlayPaint);
canvas.DrawText(
detection.Label,
detection.Bounds.Left,
detection.Bounds.Top,
textPaint);
}
This creates augmented-reality style overlays.
π Real-World Frame Rates
| Device | Resolution | FPS |
|---|---|---|
| Mid Android | 720p | 25β35 |
| Flagship Android | 1080p | 45β60 |
| iPhone | 1080p | 50β60 |
| Windows Desktop | 1080p | 60+ |
Actual performance depends on:
- Filter complexity
- AI workload
- Device GPU
β οΈ Common Mistakes
β Processing on UI Thread
Causes visible stuttering.
β Creating New Paint Objects Every Frame
Allocate once. Reuse often.
β Full HD Processing for Simple Effects
Most filters do not require maximum resolution.
β Forgetting Bitmap Disposal
bitmap.Dispose();
Memory leaks become obvious during long camera sessions.
π§© Advanced Ideas
Once the pipeline exists, adding new features becomes easy:
π¨ Beauty Filters
- Skin smoothing
- Brightness enhancement
π· QR Scanner
Real-time barcode recognition.
π§ AI Classification
TensorFlow Lite integration.
π AR Effects
Draw masks, stickers, or overlays.
π₯ Live Streaming Effects
Apply filters before streaming.
π Reference Links
- https://learn.microsoft.com/dotnet/maui/
- https://github.com/mono/SkiaSharp
- https://learn.microsoft.com/dotnet/communitytoolkit/maui/
π¬ Final Thoughts
Real-time video processing opens the door to an entirely new class of mobile experiences. By combining .NET MAUI with SkiaSharp, you can build applications that don't just display camera feedsβthey actively understand, transform, and enhance them.
Whether you're creating an AI-powered scanner, a social media camera, or an augmented reality experience, the combination of MAUI and SKCanvas provides a powerful and flexible foundation for modern computer vision applications. π₯π
