Receive Sample
The ReceiveSample demonstrates how to use IMediaSource directly to connect to a remote stream, receive compressed media samples, and optionally decode them into raw pixel data (BGRA) and PCM audio (S16). This is useful when you need to process media frames in your application — for example, computer vision, audio analysis, or custom rendering.
Overview
The ReceiveSample class performs the following:
- Creates a media source from a URI using SourceFactory (or HlsClientSource for HTTP)
- Opens the source asynchronously and starts receiving media on the
Openedstate - Detects streams via
NewStreamand creates decoders for video and audio - Queues incoming samples and decodes them on a background task
- Delivers decoded raw data to
processData()for application-specific processing
Creating the Source
#if VAST_FEATURE_HLS
if (uri.StartsWith("http"))
{
this.source = new VAST.HLS.HlsClientSource();
}
else
#endif
{
this.source = VAST.Media.SourceFactory.Create(uri);
}
this.source.Uri = uri;
this.source.NewStream += source_NewStream;
this.source.NewSample += source_NewSample;
this.source.Error += source_Error;
this.source.StateChanged += source_StateChanged;
this.source.Open();
SourceFactory creates the appropriate source for the URI protocol (rtsp://, rtmp://, srt://, etc.). HTTP URIs require the HLS client source explicitly. Four event handlers are registered:
| Event | Description |
|---|---|
NewStream |
A new media stream has been detected |
NewSample |
A compressed media sample has been received |
StateChanged |
Source state transitions (Opened, Started, Closed) |
Error |
An error occurred |
Source State Management
private void source_StateChanged(object sender, Media.MediaState e)
{
switch (e)
{
case VAST.Media.MediaState.Opened:
this.source.Start();
break;
case VAST.Media.MediaState.Started:
// samples will come soon
break;
case VAST.Media.MediaState.Closed:
// source has been disconnected
break;
}
}
The source opens asynchronously. When the Opened state is reached, Start() is called to begin receiving media samples.
Stream Detection and Decoder Creation
When a new stream is detected, a decoder is created based on the content type:
Video Decoder
case VAST.Common.ContentType.Video:
if (e.MediaType.CodecId == VAST.Common.Codec.Uncompressed
&& e.MediaType.PixelFormat == VAST.Common.PixelFormat.BGRA)
{
// already in BGRA format, no decoding needed
streamContext.PerformDecoding = false;
}
else
{
VAST.Common.MediaType desiredVideoMediaType = new VAST.Common.MediaType
{
ContentType = VAST.Common.ContentType.Video,
CodecId = VAST.Common.Codec.Uncompressed,
PixelFormat = VAST.Common.PixelFormat.BGRA,
Width = e.MediaType.Width,
Height = e.MediaType.Height,
};
streamContext.Decoder = VAST.Media.DecoderFactory.Create(
e.MediaType, desiredVideoMediaType, decoderParameters);
streamContext.PerformDecoding = true;
}
break;
Video is decoded to uncompressed BGRA pixel data at the source resolution. If the source already provides uncompressed BGRA, decoding is skipped.
Audio Decoder
case VAST.Common.ContentType.Audio:
if (e.MediaType.CodecId == VAST.Common.Codec.PCM
&& e.MediaType.SampleFormat == VAST.Common.SampleFormat.S16)
{
// already in PCM S16 format, no decoding needed
streamContext.PerformDecoding = false;
}
else
{
VAST.Common.MediaType desiredAudioMediaType = new VAST.Common.MediaType
{
ContentType = VAST.Common.ContentType.Audio,
CodecId = VAST.Common.Codec.PCM,
SampleFormat = VAST.Common.SampleFormat.S16,
SampleRate = e.MediaType.SampleRate,
Channels = e.MediaType.Channels,
};
streamContext.Decoder = VAST.Media.DecoderFactory.Create(
e.MediaType, desiredAudioMediaType, decoderParameters);
streamContext.PerformDecoding = true;
}
break;
Audio is decoded to PCM signed 16-bit samples at the source sample rate and channel count.
Decoder Parameters
VAST.Media.DecoderParameters decoderParameters = new VAST.Media.DecoderParameters
{
PreferredMediaFramework = useFFmpeg
? VAST.Common.MediaFramework.FFmpeg
: VAST.Common.MediaFramework.Builtin,
AllowHardwareAcceleration = allowHardwareAcceleration,
};
| Field | Default | Description |
|---|---|---|
useFFmpeg |
false |
Use FFmpeg for decoding instead of the built-in framework |
allowHardwareAcceleration |
true |
Allow GPU-accelerated decoding |
Sample Queue and Decoding
Incoming compressed samples are queued in source_NewSample and decoded on a background task:
Queuing Samples
private void source_NewSample(object sender, VAST.Media.NewSampleEventArgs e)
{
this.inputSampleQueue.Enqueue(e.Sample);
e.Sample.AddRef();
}
The sample's reference count is incremented via AddRef() to keep it alive until the decoding task processes it.
Decoding Loop
private async void decodingRoutine()
{
while (this.running)
{
VAST.Common.VersatileBuffer inputSample = null;
lock (this)
{
if (this.inputSampleQueue.Count > 0)
{
inputSample = this.inputSampleQueue.Dequeue();
}
}
if (inputSample != null)
{
StreamContext streamContext = this.streams[inputSample.StreamIndex];
if (streamContext.PerformDecoding)
{
streamContext.Decoder.Write(inputSample);
while (true)
{
VAST.Common.VersatileBuffer decodedSample = streamContext.Decoder.Read();
if (decodedSample == null) break;
this.processData(decodedSample);
decodedSample.Release();
}
}
else
{
this.processData(inputSample);
}
inputSample.Release();
}
else
{
await Task.Delay(10);
}
}
}
The decoding loop follows the same write/read pattern as in Push Source 3: write a compressed sample, then read decoded frames in a loop. When decoding is not needed (source already provides the desired format), samples are passed directly to processData.
Processing Decoded Data
private void processData(VAST.Common.VersatileBuffer sample)
{
// TODO: process decoded, uncompressed data
}
This is where application-specific processing goes:
- Video —
samplecontains a raw BGRA pixel array that can be used to create a bitmap, fed into a computer vision pipeline, or rendered to screen - Audio —
samplecontains a raw PCM signed 16-bit buffer for audio analysis, playback, or further processing
See Also
- Sample Applications — overview of all demo projects
- .NET Server Demo — parent page with setup instructions, license key configuration, and access URL reference