Quick Start¶
Get started with MediaX in 5 minutes.
Transmitting Video¶
C++ Example¶
#include "rtp/rtp.h"
int main() {
// Create a transmitter with SAP/SDP announcements
mediax::RtpSapTransmit<mediax::rtp::uncompressed::RtpUncompressedPayloader> rtp(
"239.192.1.1", // Multicast IP address
5004, // Port
"my-stream", // Session name
640, 480, // Width x Height
30, // Framerate
"RGB24" // Colorspace
);
// Get a test pattern buffer
std::vector<uint8_t> &buffer = rtp.GetBufferTestPattern();
// Transmit 100 frames
for (int i = 0; i < 100; i++) {
rtp.Transmit(buffer.data(), false);
}
return 0;
}
Python Example¶
import sys
sys.path.append('/usr/local/lib/python3/dist-packages')
from mediax import rtp_uncompressed_payloader
from mediax import rtp_types
# Create payloader
payloader = rtp_uncompressed_payloader.RtpUncompressedPayloader()
# Configure stream
stream_info = rtp_types.StreamInformation()
stream_info.session_name = "my-stream"
stream_info.hostname = "239.192.1.1"
stream_info.port = 5004
stream_info.width = 640
stream_info.height = 480
stream_info.framerate = 30
stream_info.encoding = rtp_types.ColourspaceType_kColourspaceRgb24
payloader.SetStreamInfo(stream_info)
payloader.Open()
payloader.Start()
# Transmit frame data (any contiguous buffer: bytes, bytearray or a numpy array)
frame_data = bytes(640 * 480 * 3) # RGB24 buffer
payloader.Transmit(frame_data)
payloader.Stop()
payloader.Close()
Receiving Video¶
C++ Example¶
The RtpSapRecieve wrapper listens for a SAP announcement for the named session,
then automatically opens the depayloader once the stream is found.
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
#include "rtp/rtp.h"
#include "uncompressed/rtp_uncompressed_depayloader.h"
int main() {
// Create a receiver — waits for SAP announcement for "my-stream"
mediax::RtpSapRecieve<mediax::rtp::uncompressed::RtpUncompressedDepayloader> rtp(
"239.192.1.1", 5004, "my-stream", 480, 640, 30, "RGB24");
// Poll for frames — blocks up to 80 ms per call
mediax::rtp::RtpFrameData frame;
std::vector<uint8_t>& buffer = rtp.GetBuffer();
for (int i = 0; i < 100; i++) {
if (rtp.Receive(&frame, buffer.size())) {
std::cout << "Received frame " << i
<< " (" << frame.resolution.width
<< "x" << frame.resolution.height << ")\n";
} else {
// SAP not yet seen or timeout — wait and retry
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
return 0;
}
Receive without known stream parameters
If you do not know the stream's IP/port/resolution in advance, use the
SapListener to discover streams first (see SAP/SDP Discovery),
then construct RtpSapRecieve with the discovered StreamInformation.
Discovering Streams¶
Use SAP/SDP to discover available streams on the network:
import sys
sys.path.append('/usr/local/lib/python3/dist-packages')
from mediax import sap_listener
import time
# Get SAP listener instance
listener = sap_listener.SapListener.GetInstance()
listener.Start()
# Wait for announcements
time.sleep(5)
listener.Stop()
# Get discovered streams
streams = listener.GetSapAnnouncements()
for name, sdp in streams.items():
print(f"Found: {sdp.session_name} at {sdp.ip_address}:{sdp.port}")
Command Line Tools¶
MediaX includes command-line tools for testing:
# Transmit a test pattern
./rtp-transmit --ipaddr 239.192.1.1 --port 5004 --width 640 --height 480
# Receive and display video
./rtp-receive --ipaddr 239.192.1.1 --port 5004
GigE Vision Quick Start¶
Experimental
GigE Vision support is experimental. Validate it with your own cameras before relying on it.
MediaX has two GigE Vision implementations:
| Library | Namespace | Use it for |
|---|---|---|
libmediax_gige (standalone) |
mediax::gev |
Real GigE Vision cameras and third party GigE Vision software |
libmediax (BUILD_GIGE) |
mediax::gige |
MediaX to MediaX streaming, see the end of this section |
This quick start uses the standalone library, which follows the GigE Vision wire format exactly. It needs only a C++17 compiler, POSIX sockets and pthreads.
1. Build¶
# Standalone, binaries are written to build-gige/bin
cmake -S gige -B build-gige
cmake --build build-gige -j$(nproc)
# Or inside the MediaX tree, binaries are written to build/bin
cmake -B build -DBUILD_GIGE_LIB=ON -DEXAMPLES=ON ..
make -C build -j$(nproc)
2. Try it without a camera¶
gev_transmit emulates a camera and sends a moving colour-bar pattern. Run it in one terminal and read it
from another, on the same machine or a different one:
# Terminal 1: the emulated camera, needs UDP port 3956
./gev_transmit 1280 720 30
# Terminal 2: find it, then receive 50 frames and save the first as a PPM image
./gev_discover 127.0.0.1
./gev_receive 127.0.0.1 50 first.ppm
gev_receive prints the device and its image format, then a summary:
Astute Systems MediaX GigE Vision (serial 0000001)
1280x720 RGB8 30 fps
Wrote first.ppm
50 frames, 0 incomplete, 0 packets lost
3. Find a real camera¶
Connect the camera and host to the same subnet, then list the cameras:
./gev_discover # broadcast on every interface
./gev_discover 10.0.5.20 # also ask a camera on another subnet directly
The same from C++:
#include <iostream>
#include <mediax/gev/gev.h>
int main() {
for (const auto& device : mediax::gev::Discover()) {
std::cout << device.ip << " " << device.mac << " " << device.manufacturer << " " << device.model
<< " serial " << device.serial << "\n";
}
return 0;
}
4. Receive video from a camera¶
Open the camera, start the acquisition and pull frames from the queue:
#include <iostream>
#include <mediax/gev/gev.h>
int main() {
auto camera = mediax::gev::Camera::Open("192.168.1.201"); // address from gev_discover
if (!camera) {
std::cerr << "Cannot open the camera: " << camera.message() << "\n";
return 1;
}
const auto format = camera.value()->GetImageFormat();
if (format) {
std::cout << format.value().width << "x" << format.value().height << " "
<< mediax::gev::PixelFormatName(format.value().pixel_format) << "\n";
}
const mediax::gev::Status started = camera.value()->StartAcquisition();
if (!started) {
std::cerr << "Cannot start the acquisition: " << started.message() << "\n";
return 1;
}
mediax::gev::Frame frame;
for (int i = 0; i < 100 && camera.value()->PopFrame(&frame, 2000 /* ms */); i++) {
std::cout << "Frame " << i << ": " << frame.width << "x" << frame.height << " " << frame.data.size()
<< " bytes" << (frame.complete ? "" : " (packets lost)") << "\n";
}
camera.value()->StopAcquisition();
const mediax::gev::StreamStats stats = camera.value()->Stats();
std::cout << stats.frames << " frames, " << stats.lost_packets << " packets lost\n";
return 0;
}
Build it against the installed library:
g++ -std=c++17 receive.cc $(pkg-config --cflags --libs mediax_gige) -o receive
or with CMake:
find_package(MediaXGige REQUIRED)
add_executable(receive receive.cc)
target_link_libraries(receive PRIVATE MediaX::Gige)
5. Receive with a callback¶
Pass a callback to StartAcquisition() instead of polling. It runs on the receive thread, so hand the frame to
another thread and return quickly:
#include <mediax/gev/gev.h>
mediax::gev::StreamOptions stream;
stream.port = 55100; // fixed receive port, easier to open in a firewall
stream.destination_ip = "192.168.1.10"; // the host address on the camera network (optional)
camera.value()->StartAcquisition(stream, [](mediax::gev::Frame&& frame) {
if (!frame.complete) return; // skip images with lost packets
// push frame.data to your own queue or display thread
});
6. Convert a frame for display¶
Frames are delivered exactly as the camera sent them (Mono8, Bayer, RGB8, YUV 4:2:2 and so on).
ConvertToRgb8() turns the common formats into RGB8:
std::vector<uint8_t> rgb;
if (mediax::gev::CanConvertToRgb8(frame.pixel_format) && mediax::gev::ConvertToRgb8(frame, &rgb)) {
// rgb holds width * height * 3 bytes, ready for a display or an encoder
}
To stream the camera on as H.264 or uncompressed RTP, pass the RGB8 data to a MediaX payloader as shown in Transmitting Video.
7. Send video as a GigE Vision camera¶
mediax::gev::Transmitter makes your application look like a camera. Any GigE Vision host can discover it,
take control and start the stream:
#include <chrono>
#include <thread>
#include <vector>
#include <mediax/gev/gev.h>
int main() {
mediax::gev::TransmitterConfig config;
config.user_name = "my-camera";
config.format.width = 1280;
config.format.height = 720;
config.format.frame_rate = 30.0;
config.format.pixel_format = mediax::gev::Code(mediax::gev::PixelFormat::kRgb8);
mediax::gev::Transmitter transmitter;
const mediax::gev::Status opened = transmitter.Open(config); // needs UDP port 3956
if (!opened) return 1;
std::vector<uint8_t> frame(transmitter.FrameBytes());
for (;;) {
// ... fill frame with your RGB8 image ...
transmitter.SendFrame(frame.data(), frame.size()); // does nothing until a host starts the acquisition
std::this_thread::sleep_for(std::chrono::milliseconds(33));
}
}
8. Troubleshooting¶
| Symptom | Check |
|---|---|
| No device found | Same subnet as the camera? UDP 3956 allowed? Try gev_discover <camera ip> |
| "could not take control" | Another application, such as the vendor viewer, holds the camera. Close it |
| Acquisition starts but no frames | Firewall blocking the stream port? Set StreamOptions::port and allow it |
| Packets lost, incomplete frames | sudo sysctl -w net.core.rmem_max=33554432, use jumbo frames, a dedicated NIC |
See the GigE Vision Cameras guide for features, stream options, network setup and the full troubleshooting table.
MediaX to MediaX streaming (mediax::gige)¶
The classes in libmediax (requires -DBUILD_GIGE=ON) stream between MediaX applications. They use the older
mediax::gige API and are not intended for third party cameras:
#include <iostream>
#include "gige/gige_receiver.h"
#include "gige/gvsp/gvsp_receiver.h"
int main() {
mediax::gige::GigEReceiver receiver;
receiver.SetReceivePort(55100);
if (!receiver.Connect("192.168.1.100")) { // camera IP
std::cerr << "Connect failed\n";
return 1;
}
receiver.Open(); // sends AcquisitionStart
mediax::gige::gvsp::GvspFrameData frame;
for (int i = 0; i < 100; i++) {
if (receiver.Receive(&frame, 2000))
std::cout << "Frame " << i << ": "
<< frame.width << "x" << frame.height
<< " " << frame.pixels.size() << " bytes\n";
}
receiver.Close();
return 0;
}
See the GigE Vision user guide for protocol details and the GigE Vision Cameras guide for working with real cameras.
Next Steps¶
- Streaming Formats - Learn about supported codecs
- SAP/SDP Discovery - Automatic stream discovery
- C++ API Reference - Complete API documentation
Support¶
Questions about getting started?
- Website: https://astutesys.com/support
- Email: support@astutesys.com