Pre-Event Recording Block - VisioForge Media Blocks SDK .NET¶
The PreEventRecordingBlock continuously buffers encoded video and audio frames in a memory-based circular (ring) buffer. When an event triggers (motion detection, alarm, API call), it flushes the buffered pre-event footage to a file and continues recording live frames for a configurable post-event duration. This creates complete event clips that include footage from before the trigger occurred.
This block is commonly used in surveillance and security applications where you need to capture what happened before and after an event, without continuously writing to disk.
Block info¶
Name: PreEventRecordingBlock.
| Pin direction | Media type | Description |
|---|---|---|
| Input video | encoded video (H.264, H.265) | Encoded video stream from an encoder or passthrough source |
| Input audio | encoded audio (AAC, MP3, etc.) | Encoded audio stream (optional, can be disabled) |
This is a sink block — it has no output pads. Recorded files are written directly to disk when a recording is triggered.
Settings¶
The PreEventRecordingBlock is configured using PreEventRecordingSettings.
| Property | Type | Default | Description |
|---|---|---|---|
PreEventDuration | TimeSpan | 30 seconds | Duration of video/audio to keep buffered in memory. When a trigger occurs, this amount of footage is flushed to the output file. |
PostEventDuration | TimeSpan | 10 seconds | Duration to continue recording after trigger. After this time elapses, recording stops automatically and the block returns to buffering mode. |
MaxBufferBytes | long | 0 (unlimited) | Maximum buffer memory in bytes. When exceeded, oldest frames are evicted regardless of time-based duration. Set to 0 for time-based eviction only. |
Constructor¶
public PreEventRecordingBlock(PreEventRecordingSettings settings, string muxFactoryName = "mp4mux")
Parameters:
settings— Pre-event recording configuration. Uses defaults if null.muxFactoryName— GStreamer muxer element factory name. Default:"mp4mux". Other options:"matroskamux"(MKV),"mpegtsmux"(MPEG-TS).
Block properties¶
| Property | Type | Description |
|---|---|---|
AudioEnabled | bool | Enable/disable audio capture. Set before pipeline start. Default: true. |
State | PreEventRecordingState | Current block state (read-only, thread-safe). |
CurrentFilename | string | Current recording filename. Null when not recording. |
BufferTotalBytes | long | Total bytes currently stored in the ring buffer. |
BufferedDuration | TimeSpan | Current duration of buffered media. |
DebugLogPath | string | Path to debug log file. When non-null, writes detailed frame timestamp debugging. |
State machine¶
The block follows a well-defined state machine:
stateDiagram-v2
[*] --> Idle
Idle --> Buffering : pipeline start / StartBuffering()
Buffering --> Recording : TriggerRecording()
Recording --> PostEventRecording : Pre-event buffer flushed
PostEventRecording --> Buffering : Post-event timer expires / StopRecording() / StartBuffering() / format change
Recording --> Buffering : StopRecording() / StartBuffering() / format change / trigger failed
Idle --> Stopped : StopBuffering()
Buffering --> Stopped : StopBuffering() / pipeline stop
Recording --> Stopped : StopBuffering() / pipeline stop
PostEventRecording --> Stopped : StopBuffering() / pipeline stop
Stopped --> Buffering : StartBuffering() / restart after a pipeline stop | State | Description |
|---|---|
Idle | Not initialized or not started. |
Buffering | Actively buffering frames in the ring buffer, not recording to file. |
Recording | Flushing pre-event buffer to file and capturing live frames. |
PostEventRecording | Post-event phase — recording live frames until the timer expires. |
Stopped | Not buffering. After a pipeline stop, a restart resumes buffering; after StopBuffering(), only StartBuffering() does. |
A change of the encoded format during a run — resolution, profile, level, codec data, or the audio rate, channel count or codec — closes a recording that is in progress, the same way StopRecording() does, and drops that stream's buffered frames. The other stream stays buffered. The next file is built from the new format. A restated frame rate or pixel aspect ratio does not close the recording.
Events¶
public event EventHandler<PreEventRecordingEventArgs> OnRecordingStarted;
public event EventHandler<PreEventRecordingEventArgs> OnRecordingStopped;
public event EventHandler<PreEventRecordingEventArgs> OnStateChanged;
The events are raised one at a time, in the order the changes happened: a handler never runs alongside another one, and OnRecordingStopped follows the OnRecordingStarted of the same file and comes once the file is finalized. While a handler is running, anything that causes a new event — StopRecording(), StopBuffering(), StartBuffering(), TriggerRecording(), a pipeline stop or a format change, on another thread or inside the handler — returns before that event is raised; the thread running the handler raises it when the handler returns. A handler can therefore run on a worker thread even when the call was made on the UI thread, and after the pipeline stopped or the block was disposed; marshal to the UI thread before touching controls. StopRecording(), StopBuffering(), StartBuffering() and TriggerRecording() rethrow what the handlers they raised threw; on the post-event timer, a pipeline start or stop, or a format change the exception is logged as an error.
PreEventRecordingEventArgs properties:
| Property | Type | Description |
|---|---|---|
State | PreEventRecordingState | Current state at the time of the event. |
Filename | string | Output filename for the recording. |
PreEventDuration | TimeSpan | Actual pre-event duration included in the file (may be less than configured if insufficient buffered data or keyframe alignment adjusted the start). |
Methods¶
| Method | Description |
|---|---|
TriggerRecording(string filename) | Flush the ring buffer to the specified file and start recording live frames. If already recording, extends the current recording (resets post-event timer). Refused, with an error, until the first encoded video frame has arrived and, when audio is enabled, until the first encoded audio frame has arrived. A later call records normally. |
ExtendRecording() | Reset the post-event timer. Call this when the trigger condition is still active (e.g., motion continues). |
StopRecording() | Manually stop the current recording and return to buffering mode. |
StartBuffering() | Start or resume buffering after being stopped. Frames are buffered only while the pipeline runs. Called before the pipeline starts, it raises OnStateChanged with Buffering at once, and the start does not raise it again. Does nothing when the block is already buffering. |
StopBuffering() | Stop everything including buffering and clear the buffer. The block stays stopped, across pipeline restarts, until StartBuffering(). A repeated call raises no event. |
The sample pipeline¶
With a local camera source, motion detection, video preview, and pre-event recording:
graph LR;
VideoSource-->MotionDetector;
MotionDetector-->VideoTee;
VideoTee-->VideoRenderer;
VideoTee-->H264Encoder;
H264Encoder-->PreEventRecordingBlock;
AudioSource-->AudioTee;
AudioTee-->AudioRenderer;
AudioTee-->AACEncoder;
AACEncoder-->PreEventRecordingBlock; When TriggerRecording() is called, the block internally creates a dynamic output pipeline:
graph LR;
RingBuffer-->AppSrcVideo;
RingBuffer-->AppSrcAudio;
AppSrcVideo-->Muxer;
AppSrcAudio-->Muxer;
Muxer-->FileSink; Sample code¶
The following snippet shows how to create and connect the block. For a complete working application with motion detection, video preview, RTSP camera support, and full WPF UI, see the Pre-Event Recording Guide.
// Configure pre-event settings
var preEventSettings = new PreEventRecordingSettings
{
PreEventDuration = TimeSpan.FromSeconds(10),
PostEventDuration = TimeSpan.FromSeconds(5)
};
// Create the block (MP4 output)
var preEventBlock = new PreEventRecordingBlock(preEventSettings, "mp4mux");
preEventBlock.AudioEnabled = true;
// Subscribe to events
preEventBlock.OnRecordingStarted += (s, args) =>
Debug.WriteLine($"Recording started: {args.Filename}");
preEventBlock.OnRecordingStopped += (s, args) =>
Debug.WriteLine($"Recording stopped: {args.Filename}");
// Connect encoded video and audio to the block
pipeline.Connect(h264Encoder.Output, preEventBlock.VideoInput);
pipeline.Connect(aacEncoder.Output, preEventBlock.AudioInput);
// Start pipeline — buffering begins immediately
await pipeline.StartAsync();
// Later: trigger recording on event
preEventBlock.TriggerRecording("/recordings/event_001.mp4");
// Extend if trigger condition persists
preEventBlock.ExtendRecording();
// Or stop manually
preEventBlock.StopRecording();
Container format options¶
| Format | Muxer Factory Name | Pros | Cons |
|---|---|---|---|
| MP4 | mp4mux | Most compatible, widely supported | Requires finalization (moov atom); file may be corrupt if process crashes during recording |
| MPEG-TS | mpegtsmux | Crash-safe — no finalization step needed; file is always playable | Slightly larger file size; less universal support in some players |
| MKV | matroskamux | Flexible container; supports many codecs | Less compatible with some mobile players |
Crash Safety
For surveillance applications where process crashes are a concern, use MPEG-TS (mpegtsmux). MP4 files that are not properly finalized (e.g., due to a crash or power loss during recording) may be unplayable.
Platforms¶
Windows, macOS, Linux, Android, iOS (platform availability depends on GStreamer muxer and encoder support).