VAST.File Library
The VAST.File library provides file-based media sources and sinks for VASTreaming applications. It supports playlist playback, MPEG audio (MP1/MP2/MP3) and WAV file handling, metadata caching for VOD optimization, and media processing utilities.
Overview
| Feature | Description |
|---|---|
| Playlist Source | Play M3U/M3U8/PLS playlists with seamless concatenation |
| MPEG Audio | Read and write MP1, MP2, MP3 files |
| WAV Audio | Read and write WAV files with multiple PCM formats |
| File Caching | Cache file metadata for instant reopening |
| File Rotation | Automatic file chunking for long recordings |
| Media Utilities | Audio analysis, mixing, video composition |
Requirements
- .NET: .NET 6.0 or later
- Dependencies: VAST.Common
- Optional Dependencies: VAST.File.ISO for MP4 support and utilities, VAST.TS for TS file support
File Sources
FileSource (Playlist)
The FileSource plays playlists with automatic file concatenation and seamless playback.
Supported Formats
| Format | Extension | Description |
|---|---|---|
| M3U | .m3u | Standard playlist |
| M3U8 | .m3u8 | UTF-8 playlist (HLS compatible) |
| PLS | .pls | Winamp playlist format |
Usage
var source = new VAST.File.FileSource();
source.Uri = "playlist.m3u";
source.Loop = true;
source.NewStream += (sender, e) =>
{
Console.WriteLine($"Stream: {e.MediaType}");
};
source.NewSample += (sender, e) =>
{
ProcessSample(e.Sample);
};
source.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
source.Start();
}
};
source.Open();
Playlist Format
A playlist is a simple text file with a list of file paths, one per line:
C:\path\rec1.mp4
C:\path\rec2.mp4
C:\path\rec3.mp4
Playlist files must have .pls, .m3u, or .m3u8 extension.
Important
All files in a playlist must have exactly the same encoding settings, including low-level parameters. Files should be recorded from the same source or encoded using the same encoder with identical settings. You cannot combine files recorded from different sources in one playlist without first transcoding them to exactly the same output format using identical encoding settings.
Inline Playlists
Playlists can also be specified inline using the content: URI scheme:
source.Uri = @"content:
#EXT-X-VAST-INTERVAL:0:01:05.000-
T:\file1.mp4
T:\file2.mp4
#EXT-X-VAST-INTERVAL:0:00:00-0:00:33.133
T:\file3.mp4";
Playback Intervals
Use the #EXT-X-VAST-INTERVAL directive to play only a portion of a file:
#EXT-X-VAST-INTERVAL:<from>-<to>
Both <from> and <to> are optional:
- If
<from>is omitted, playback starts from the beginning - If
<to>is omitted, playback continues to the end
Timestamps must be in a format parseable by the TimeSpan class.
Examples
Both start and end specified:
#EXT-X-VAST-INTERVAL:0:01:05.000-0:01:15.000
C:\path\rec1.mp4
Only start specified (play to end):
#EXT-X-VAST-INTERVAL:0:01:05.000-
C:\path\rec1.mp4
Only end specified (play from beginning):
#EXT-X-VAST-INTERVAL:-0:01:15.000
C:\path\rec1.mp4
Keyframe Alignment
Actual playback positions are aligned to the nearest keyframes, since splicing can only occur at keyframes:
- For
<from>: the keyframe equal to or preceding the specified position is used - For
<to>: the keyframe equal to or following the specified position is used
This alignment behavior can be configured via StartPositionAlignment and EndPositionAlignment properties.
Note
Due to keyframe alignment, the actual duration of each playlist segment (and the total playlist duration) may differ slightly from the values specified in the interval directives.
NTP Timestamp Intervals
For MP4 files written by VASTreaming that contain NTP timestamps, use #EXT-X-VAST-NTP-INTERVAL:
#EXT-X-VAST-NTP-INTERVAL:<from>-<to>
Both <from> and <to> are optional and represent absolute NTP timestamps in hexadecimal format.
Example:
#EXT-X-VAST-NTP-INTERVAL:0xe5a5b9370e71f70e-0xe5a5b9c31b186799
C:\path\rec1.mp4
The same keyframe alignment rules apply as with #EXT-X-VAST-INTERVAL.
Error Handling
Control behavior when playlist items fail:
| Mode | Description |
|---|---|
| FailOnAny | Stop on first error |
| FailOnAll | Transition to error state only if all files in the playlist fail |
source.ErrorHandling = FileSource.FileErrorHandling.FailOnAll;
MpaSource (MPEG Audio)
The MpaSource reads MPEG audio files with metadata extraction and HTTP streaming support.
Supported Formats
| Format | Description |
|---|---|
| MP1 | MPEG Audio Layer I |
| MP2 | MPEG Audio Layer II |
| MP3 | MPEG Audio Layer III |
Features
| Feature | Support |
|---|---|
| Local Files | Yes |
| HTTP/HTTPS Streaming | Yes |
| ID3v1/ID3v2 Tags | Yes |
| APE Tags | Yes |
| Seeking | Frame-accurate |
| Looping | Yes |
Usage
var source = new VAST.File.MpaSource();
source.Uri = "audio.mp3";
source.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
Console.WriteLine($"Duration: {source.Duration}");
source.Start();
}
};
source.Open();
WavSource
The WavSource reads WAV audio files with multiple PCM format support.
Supported Formats
| Format | Description |
|---|---|
| PCM 8-bit | Unsigned 8-bit samples |
| PCM 16-bit | Signed 16-bit samples |
| PCM 32-bit | Signed 32-bit integer or float samples |
| PCM 64-bit | Signed 64-bit float samples |
Usage
var source = new VAST.File.WavSource();
source.Uri = "audio.wav";
source.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
source.Start();
}
};
source.Open();
Playback Control
All file sources support interactive playback:
// Seeking
source.Position = TimeSpan.FromSeconds(30);
// Playback rate
source.PlaybackRate = 2.0; // 2x speed
// Pause/Resume
source.Pause();
source.Start(); // Resume
Playback Features
| Feature | Support |
|---|---|
| Seeking | Timestamp-based positioning |
| Pause/Resume | Full support |
| Playback Rate | Variable speed playback |
| Looping | Continuous playback |
| Multi-track | Video, audio, subtitles/metadata |
Playback Rates
| Rate | Description |
|---|---|
| double.MinValue | As fast as possible in backward direction (no pacing) |
| -32 to -1 | Rewind (backward playback) |
| 0 to 1 (exclusive) | Slow motion |
| 1 | Normal speed |
| 1 to 32 | Fast forward |
| double.MaxValue | As fast as possible (no pacing) |
File Sinks
MpaSink (MPEG Audio)
The MpaSink writes MPEG audio to files with rotation support.
var sink = new VAST.File.MpaSink();
sink.Uri = "output.mp3";
sink.AddStream(0, audioMediaType);
sink.Open();
sink.Start();
// Write samples
sink.PushMedia(0, audioSample);
sink.Stop();
WavSink
The WavSink writes WAV files with automatic header management.
Supported Codecs
| Codec | Description |
|---|---|
| PCM (S16, S32, FLT, U8) | Uncompressed PCM |
| GSM / GSM-MS | GSM audio |
| G.711 A-law | Telephony codec |
| G.711 ยต-law | Telephony codec |
| G.722 | Wideband telephony |
| G.723.1 | Low bitrate telephony |
| G.729 | Telephony codec |
var sink = new VAST.File.WavSink();
sink.Uri = "output.wav";
sink.AddStream(0, audioMediaType);
sink.Open();
sink.Start();
sink.PushMedia(0, audioSample);
sink.Stop();
File Rotation
Both sinks support automatic file rotation for long recordings:
var sink = new VAST.File.MpaSink();
sink.RotationPeriod = 3600; // Rotate every hour (seconds)
int fileNumber = 0;
sink.NextUri = () => $"recording_{fileNumber++:D4}.mp3";
sink.UriRotated += (sender, e) =>
{
Console.WriteLine($"Completed: {e.Uri}");
Console.WriteLine($"Duration: {e.FinishTimestamp - e.StartTimestamp}");
};
sink.Open();
sink.Start();
Writing to Stream
Write audio data to a custom stream instead of a file:
var memoryStream = new MemoryStream();
var sink = new VAST.File.WavSink();
sink.Stream = memoryStream;
sink.AddStream(0, audioMediaType);
sink.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
sink.Start();
}
};
sink.Open();
...
sink.PushMedia(0, audioSample);
sink.Stop();
// Access the WAV data
byte[] wavData = memoryStream.ToArray();
Delayed Start
Use delayed start when the first media sample may arrive after a significant delay:
sink.Start(delayedStart: true);
// File will be created/recreated when first sample arrives
// Empty file is automatically deleted if no samples received
File Caching
The FileCache class caches file metadata and indices for instant reopening, optimizing VOD scenarios where multiple clients access the same files.
Benefits
- Instant Open: Cached files open without re-parsing metadata and indices
- Reduced I/O: Avoid redundant disk reads
- Memory Efficient: Sharing of references of big indice arrays instead of copying data, automatic expiration of unused entries
- Thread-Safe: Safe for concurrent access
Usage
var cache = new VAST.File.FileCache();
// Add source to cache
cache.Add("video.mp4", source);
// Retrieve cached source
var cachedSource = cache.GetSource("video.mp4");
// Update access time to prevent expiration
cache.UpdateUseState("video.mp4");
// Cleanup expired entries
cache.Update();
Expiration
Cached entries expire after 600 seconds of inactivity. Call UpdateUseState() to refresh the expiration timer for actively used files.
Media Utilities
The following utilities require the VAST.File.ISO library.
AudioAnalyzer
Analyze audio files for signal metrics:
var analyzer = new VAST.File.Utility.AudioAnalyzer();
if (await analyzer.Execute("audio.wav"))
{
Console.WriteLine($"RMS Level: {metrics.RmsSignal}");
Console.WriteLine($"Peak Level: {metrics.PeakSignal}");
Console.WriteLine($"Silence Duration: {metrics.TotalSilenceDuration}");
}
AudioMixer
Mix audio track of one video file with multiple others with individual volume control:
var mixer = new VAST.File.Utility.AudioMixer();
var inputFiles = new List<VAST.File.Utility.InputFileItem>();
inputFiles.Add(new VAST.File.Utility.InputFileItem
{
FilePath = "video_and_audio_input.mp4",
Volume = 1.0
});
inputFiles.Add(new VAST.File.Utility.InputFileItem
{
FilePath = "audio_input.mp4",
Volume = 0.3
});
await mixer.Execute(inputFiles, "output.mp4");
VideoMixer
Composite video from multiple sources with positioning:
var mixer = new VAST.File.Utility.VideoMixer();
mixer.InputFile.FilePath = "background.mp4";
mixer.Images.Add(new InputFileItem
{
FilePath = "overlay.png",
Waypoints = new List<Waypoint>
{
new Waypoint
{
Location = new VAST.Common.Rect(10, 10, 100, 100),
StartTimestamp = 10 * 10_000_000, // 10 seconds in 100 ns units
Duration = Timestamp.FromSeconds(30),
Opacity = 0.8
}
}
});
mixer.OutputFilePath = "output.mp4";
await mixer.Execute();
ImageExtractor
Extract a single frame from a video file at a specified position and save it as an image:
var extractor = new VAST.File.Utility.ImageExtractor();
var image = await extractor.Execute("video.mp4", TimeSpan.FromSeconds(30));
if (image != null)
{
// .NET Core: image is SkiaSharp.SKImage
// .NET Framework: image is System.Drawing.Image
// Save to file
using (var stream = File.OpenWrite("thumbnail.jpg"))
{
image.Encode(SkiaSharp.SKEncodedImageFormat.Jpeg, 80).SaveTo(stream);
}
}
else
{
Console.WriteLine($"Extraction failed: {extractor.ErrorDescription}");
}
The extractor automatically seeks to the nearest keyframe before the specified position and decodes frames until reaching the target timestamp.
Concurrency Control
Limit concurrent Media Foundation decoder instances to manage system resources:
// Default is 5 concurrent instances
ImageExtractor.MaxMediaFoundationInstanceCount = 10;
Concatenator
Join multiple media files
var concatenator = new VAST.File.Utility.Concatenator();
var inputFiles = new List<VAST.File.Utility.InputFileItem>();
// take the first file from 0:00:10.000 to the end
inputFiles.Add(new VAST.File.Utility.InputFileItem
{
FilePath = "part1.mp4",
StartTimestamp = 10 * 10_000_000, // 10 seconds in 100 ns units
});
// take the whole second file
inputFiles.Add(new VAST.File.Utility.InputFileItem
{
FilePath = "part2.mp4",
});
// take the third file from the beginning to the 0:00:45.000
inputFiles.Add(new VAST.File.Utility.InputFileItem
{
FilePath = "part3.mp4",
EndTimestamp = 45 * 10_000_000, // 45 seconds in 100 ns units
});
await concatenator.Execute(inputFiles, "output.mp4");
Cut single file
var concatenator = new VAST.File.Utility.Concatenator();
var inputFiles = new List<VAST.File.Utility.InputFileItem>();
inputFiles.Add(new VAST.File.Utility.InputFileItem
{
FilePath = "input.mp4",
StartTimestamp = 10 * 10_000_000, // 10 seconds in 100 ns units
EndTimestamp = 45 * 10_000_000, // 45 seconds in 100 ns units
});
await concatenator.Execute(inputFiles, "output.mp4");
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Playlist item fails | File not found | Use SkipOnError or ContinueOnError mode |
| MP3 seeking inaccurate | VBR without seek table | File plays correctly, seek may be approximate |
| WAV header invalid | Incomplete write | Ensure Stop() is called before closing |
| Cache not working | Wrong file path | Use consistent paths (absolute recommended) |
| Rotation not triggering | RotationPeriod not set | Set RotationPeriod > 0 |
Supported URI Schemes
| Scheme | Source Types |
|---|---|
| Local file path or file:// | All sources |
| http:// | MpaSource |
| https:// | MpaSource |
| content: | FileSource (playlist) |
See Also
- Supported Platforms - Platform compatibility matrix
- VAST.Common Library - Core media types and interfaces
- VAST.File.ISO Library - MP4 file support with caching integration
- VAST.TS Library - MPEG-2 Transport Stream