Publishing Point with User Push Source 4
This use-case demonstrates how to push raw RTP packets into the server using VirtualRtpSource. Unlike the other push sources that work with elementary stream data or pixel buffers, this source accepts complete RTP packets — including RTP headers — and handles depacketization internally.
Overview
The pushingRoutine4() method runs in a background task and performs the following:
- Creates a VirtualRtpSource and registers an H.264 video stream with its RTP payload type
- Creates a publishing point with the source
- Parses an embedded rtpdump file containing captured RTP packets
- Runs a loop that pushes RTP packets at the original timing pace
Difference from Other Push Sources
Push Source 1 pushes elementary stream data (raw H.264 NAL units and AAC frames) via VirtualNetworkSource. This use-case pushes complete RTP packets — the kind of data you would receive directly from a UDP socket during an RTP session. The VirtualRtpSource handles RTP depacketization, reordering, and reassembly internally, producing a clean media stream for the publishing point.
This is useful when you have an existing RTP receiver or capture pipeline and want to feed packets directly into the server without manual depacketization.
Creating the Source
var source = new VAST.RTP.VirtualRtpSource();
source.AddStream(new VAST.Common.MediaType
{
ContentType = VAST.Common.ContentType.Video,
CodecId = VAST.Common.Codec.H264,
Metadata = new Dictionary<string, string> { { "PayloadType", "96" } }
});
this.server.CreatePublishingPoint("builtin", source);
VirtualRtpSource is a virtual media source that accepts raw RTP packets pushed by user code. Each stream registered with AddStream must include a PayloadType entry in the media type's Metadata dictionary. The payload type is used to match incoming RTP packets to the correct stream.
Streams can also be registered from an SDP description string using AddStreams(sdp).
Parsing the RTP Dump
The sample reads RTP packets from an embedded rtpdump file:
byte[] dump = new byte[Properties.Resources.h264_rtpdump.Length];
Properties.Resources.h264_rtpdump.CopyTo(dump, 0);
long pushingStarted = VAST.Common.MediaTime.Get(1000);
long timestampBase = long.MinValue;
int pos = 13;
while (dump[pos] != 0x0A) ++pos;
pos += 17;
int startPos = pos;
The rtpdump format contains a text header followed by binary packet records. The parser skips the header and positions at the first packet record. Each record contains the packet length, timestamp, and the raw RTP packet data.
Push Loop
The loop reads packets from the dump and pushes them at the original timing:
Reading Packet Records
int fullLen = (dump[pos] << 8) | dump[pos + 1];
pos += 2;
int len = (dump[pos] << 8) | dump[pos + 1];
if (len == 0)
{
pos += fullLen - 2;
continue;
}
pos += 2;
long timestamp = (dump[pos] << 24) | (dump[pos + 1] << 16) | (dump[pos + 2] << 8) | dump[pos + 3];
pos += 4;
Each record has a full record length, the RTP packet length, and a millisecond timestamp. Records with zero packet length are skipped.
Pacing
if (timestampBase == long.MinValue)
{
timestampBase = timestamp - pushingTime;
}
timestamp -= timestampBase;
if (timestamp > pushingTime)
{
int sleep = (int)(timestamp - pushingTime);
if (sleep == 0) sleep = 1;
Task.Delay(sleep).Wait();
}
Timestamps from the dump file are rebased relative to the pushing start time. When a packet's timestamp is ahead of the current playback time, the loop sleeps until the correct moment.
Pushing RTP Packets
source.PushRtpPacket(dump, pos, len);
Each packet is pushed as a complete raw RTP packet including the RTP header. The VirtualRtpSource parses the RTP header, matches the payload type to the registered stream, and performs codec-specific depacketization (e.g., H.264 FU-A reassembly).
Looping
if (pos >= dump.Length)
{
pos = startPos;
timestampBase = long.MinValue;
}
When the dump is exhausted, the position resets to the beginning and the timestamp base is recalculated, allowing continuous playback.
PushRtpPacket Method
The VirtualRtpSource provides three PushRtpPacket overloads:
| Overload | Description |
|---|---|
PushRtpPacket(buffer, offset, length, discontinuity) |
Push a raw RTP packet from a byte array |
PushRtpPacket(rtpPacket) |
Push a raw RTP packet as a VersatileBuffer |
PushRtpPacket(payloadType, sequenceNo, timestamp, ssrc, marker, payload, payloadOffset, payloadLength, discontinuity) |
Push an already-parsed RTP packet with individual header fields |
The first two overloads expect a complete RTP packet with headers. The third overload accepts pre-parsed header fields and the payload data without the RTP header — useful when your application has already parsed the RTP header.
Parameters (byte array overload)
| Parameter | Type | Description |
|---|---|---|
rtpPacket |
byte[] |
Buffer containing the raw RTP packet including headers |
offset |
int |
Starting position in the buffer |
length |
int |
Number of bytes in the packet |
discontinuity |
bool |
Set to true to signal a gap in the packet sequence (default: false) |
Platform Support
This use-case requires the VAST.RTSP library (VAST_FEATURE_RTSP compilation symbol). The VirtualRtpSource class is part of the VAST.RTSP assembly and is available on all supported platforms.
See Also
- Sample Applications — overview of all demo projects
- .NET Server Demo — parent page with setup instructions, license key configuration, and access URL reference
- Multi-Protocol Server — overview and full publishing point table
- Initialization — server creation and protocol configuration
- Server Event Handlers — authorization, connections, and error handling
- User Push Source 1 — push pre-encoded H.264/AAC data
- VAST.Network Library — StreamingServer API reference
- VAST.RTSP Library — RTSP/RTP API reference