DVR Mode
DVR mode provides time-shifted playback of a live stream. It combines a rolling in-memory buffer with optional external recordings, allowing you to:
- Pause playback while the player continues buffering incoming data.
- Inspect video frames and synchronized telemetry with
StepForward()andStepBackward(). - Seek within the available recording range.
- Resume from the paused position, provided that the data is still available.
- Return to live playback with
GoToLive().
Note: The DVR buffer is temporary and is overwritten as new data arrives. For persistent DVR recordings, use an external HLS recorder, such as the StanagStream Recorder SDK or StanagOnDemand Server, and register its recording with the player. The live and recorded sources must contain matching timestamps in the selected reference time mode.
DVR Operation Scenarios
1. In-Memory Buffer Playback
The player buffers incoming stream data in memory during DVR operation. Pausing freezes the displayed video but does not stop buffering. Frame stepping, seeking, and delayed playback use the local buffer while the requested data remains available.

2. Hybrid Buffer and HLS Playback
As new data arrives, older data is removed from the local buffer. If the paused position or the data needed for playback leaves the buffer, the player attempts to switch to a registered external recording.
This requires an accessible recording that covers the requested position and can be matched to the live source. Availability also depends on the recorder's retention policy.

3. External Recording Playback
When you seek to an earlier position outside the local buffer, the player attempts to access the corresponding externally recorded content. Without an external recording, DVR playback is limited to the data retained in memory.

Licensing for DVR Playback and Recording
Activate the player after creating CKlvPlayer(true) and before calling Init(). Creating a DVR player enables the DVR configuration; it does not activate a license. See License Activation for obtaining a license and the target machine's node information.
For a JWT player license, use:
m_KlvPlayer = new CKlvPlayer(true);
if (!m_KlvPlayer.Activate(m_PlayerLicensePath, out string decodedLicense, out string licenseError))
{
throw new System.InvalidOperationException("Player activation failed: " + licenseError);
}
// Configure the player, then call Init() and Start().
The JWT license must be issued for KlvPlayerSdk. A TSRecorder license is not a substitute for the player license. For a legacy player license and activation key, use the corresponding overload instead:
if (!m_KlvPlayer.Activate("KlvPlayer", m_PlayerLicensePath, m_PlayerLicenseKey))
{
throw new System.InvalidOperationException("Player activation failed.");
}
External Recorder License
The local DVR buffer is implemented by the native player engine, this path does not create or activate a Recorder instance. TSRecorder SDK licensing applies when your application uses that SDK to produce the external recording used for longer DVR retention.
Activate the external recorder separately before initializing and starting it. The CRecorder implementation in this repository exposes the legacy license-file-and-key API:
var recorder = new TsRecorderLib.CRecorder(0, "DVR Recorder");
if (!recorder.Activate("TSRecorder", m_RecorderLicensePath, m_RecorderLicenseKey))
{
throw new System.InvalidOperationException("Recorder activation failed.");
}
// Configure and initialize HLS recording, then start the recorder.
// Once its playlist is available and the player is initialized:
m_KlvPlayer.AddRecordedUrl(m_RecordingUrl);
The recorder wrapper also accepts a legacy KlvPlayer license when its Recording feature is permitted. If you have been issued such a license, use:
recorder.Activate("KlvPlayer", m_PlayerLicensePath, m_PlayerLicenseKey);
Check the return value just as in the TSRecorder example. A player-only license that disables recording will not activate the recorder. The recorder API shown here does not expose the player's JWT activation overload; use credentials issued for this recorder API.
StPlayer activates the player during Init(). Its CRecorder constructor also has an application-specific activation path for StPlayer, so the absence of an explicit recorder activation call in the application is not an activation example for SDK consumers. Use the public recorder activation API in your own application.
If an independent recorder or StanagOnDemand Server supplies the HLS recording, apply its license in that recorder or server. AddRecordedUrl() only registers recorded content with the player and does not activate the recording software.
Configuring DVR Mode
Enable DVR mode when creating the player:
m_KlvPlayer = new CKlvPlayer(true);
The default constructors create a player with DVR mode disabled. Use new CKlvPlayer(false) when live time-shifting is unnecessary to avoid the overhead of continuous buffering. File playback has its own playback controls and does not require DVR mode.
Set the following properties before calling Init(). The wrapper passes their values to the native DVR engine during initialization; changing the properties alone does not reconfigure an initialized DVR session.
DvrLocalBufferSize
Sets the capacity of the local recording buffer in KB, where 1 KB = 1,024 bytes. The SDK default is 10000 KB. This property specifies a memory size, not a duration.
Estimate the required size from the incoming stream bitrate and the desired retention time:
buffer size (KB) ≈ stream bitrate (bits/second) × retention time (seconds) / (8 × 1024)
Use the total stream bitrate, including audio and metadata, rather than the video bitrate alone. For example, a 20000 KB buffer holds approximately 41 seconds at 4 Mbit/s. Actual retention varies with the bitrate; allow additional capacity for bitrate peaks.
DvrRefTimeMatchMode
Selects the timestamp reference used to match the live source and recorded content. The enum is defined in the StCoreWr namespace.
| Value | Usage |
|---|---|
DVR_RefTimeMatchMode.RefTimeMatchMode_VideoPts |
Matches video presentation timestamps (PTS). This is the SDK default. Use it when the recorded content preserves the live source's video PTS values. |
DVR_RefTimeMatchMode.RefTimeMatchMode_Klv |
Matches KLV timestamps. Use it when video PTS values have changed but both sources retain matching KLV timestamps. |
If neither video PTS nor KLV timestamps provide a common reference, the player cannot reliably match the live and recorded sources.
TimeMatchPid
When using KLV timestamp matching, this property selects the KLV PID used as the time reference. The SDK default is -1, which can be used when the stream has only one synchronized KLV PID. Set an explicit PID when you need to select among multiple KLV streams.
m_KlvPlayer.DvrRefTimeMatchMode = DVR_RefTimeMatchMode.RefTimeMatchMode_Klv;
m_KlvPlayer.TimeMatchPid = 500; // Example: replace with the stream's KLV PID.
Initializing and Registering a Recording
Follow the standard initialization steps described in Playback, including licensing and video output configuration. The following example shows the DVR-specific settings and call order:
// DVR_RefTimeMatchMode is defined in StCoreWr.
m_KlvPlayer = new CKlvPlayer(true);
m_KlvPlayer.DvrLocalBufferSize = 20000;
m_KlvPlayer.DvrRefTimeMatchMode = DVR_RefTimeMatchMode.RefTimeMatchMode_VideoPts;
// Apply the usual license, video output, and other playback settings here.
if (!m_KlvPlayer.Init(m_Url))
{
throw new System.InvalidOperationException("Could not initialize DVR playback.");
}
// Optional: register an existing external recording after initialization.
// This may be an HLS playlist URL or a local .m3u8 file path.
if (!m_KlvPlayer.AddRecordedUrl(m_RecordingUrl))
{
throw new System.InvalidOperationException("Could not register the DVR recording.");
}
m_KlvPlayer.Start();
Omit AddRecordedUrl() for in-memory-only DVR playback. You can also register a recording later, after the recorder has started and its playlist is available. AddRecordedUrl() returns false if the DVR configuration is unavailable or the native engine rejects the recording URL. It does not start a recorder.
Controlling DVR Playback
Call Pause() to freeze playback. Incoming data continues to enter the rolling buffer. Call Start() to resume from the paused position while that position remains available locally or in an external recording.
m_KlvPlayer.Pause();
m_KlvPlayer.StepForward();
m_KlvPlayer.StepBackward();
m_KlvPlayer.Start();
Frame stepping is intended for paused playback. For frame accuracy settings and requirements, see Frame Accuracy.
Use SetPosition() to seek to a position in seconds on the player's DVR timeline. Use the range reported by GetAvailableRange() to constrain a seek slider or other navigation control:
double posStart, posEnd;
if (m_KlvPlayer.GetAvailableRange(out posStart, out posEnd))
{
// Example: seek to the midpoint of the currently available range.
double pos = posStart + (posEnd - posStart) / 2;
if (!m_KlvPlayer.SetPosition(pos))
{
// Handle an unsuccessful seek in the application.
}
}
GetAvailableRange() returns true when a range is available. Both endpoints are in seconds; the start reflects the retained recording range and the end represents the live edge. Refresh the range during playback because it changes as new data arrives and old data expires. A position can become unavailable between querying the range and seeking.
If the currently displayed position has expired and cannot be recovered from an external recording, the engine can report Player_State.VideoDeleted. Handle this state in the application, for example by updating navigation controls and returning to live playback.
To return to live playback, call:
m_KlvPlayer.GoToLive();