Table of Contents

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:

  1. Creates a VirtualRtpSource and registers an H.264 video stream with its RTP payload type
  2. Creates a publishing point with the source
  3. Parses an embedded rtpdump file containing captured RTP packets
  4. 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