Common Vision Blox 15.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Friends Modules Pages
RTPStreaming/Cvb++/CppRTPStreaming

This example program is located in your CVB installation under %CVB%Tutorial/RTPStreaming/Cvb++/CppRTPStreaming.

DeviceSimulator.cpp:

#include "DeviceSimulator.hpp"
#include <cvb/block.hpp>
#include <cvb/global.hpp>
// helper method to create test pattern images
static std::vector<std::shared_ptr<Cvb::Image>> CreateImages(size_t count)
{
std::vector<std::shared_ptr<Cvb::Image>> images;
images.reserve(count);
std::generate_n(std::back_inserter(images), count, [count, i = 0]() mutable
{
auto image = Cvb::Image::FromPixelFormat(Cvb::Size2D<int>(320, 240), Cvb::PfncFormat::RGB8);
Cvb::VisitAs<uint8_t>([i, count](auto red, auto green, auto blue) {
for (int y = 0; y < red.Height(); ++y)
for (int x = 0; x < red.Width(); ++x)
{
red(x, y) = static_cast<uint8_t>(i + x + y);
green(x, y) = static_cast<uint8_t>((count - 1 - i) + x + y);
blue(x, y) = static_cast<uint8_t>(i + x + y + 128);
}
},
image->Plane(0), image->Plane(1), image->Plane(2));
++i;
return image;
});
return images;
}
DeviceSimulator::DeviceSimulator(size_t numImages)
{
_images = CreateImages(numImages);
}
std::shared_ptr<Cvb::Image> DeviceSimulator::GetNextImage()
{
const std::shared_ptr<Cvb::Image> img = _images[_currentImageIndex];
if (++_currentImageIndex >= _images.size())
_currentImageIndex = 0;
return img;
}
static std::unique_ptr< Image > FromPixelFormat(const Cvb::Size2D< int > &size, Cvb::PfncFormat format)

DeviceSimulator.hpp:

#include <vector>
#include <cvb/global.hpp>
// Simple helper class to 'simulate' a camera.
class DeviceSimulator
{
public:
DeviceSimulator(size_t numImages);
std::shared_ptr<Cvb::Image> GetNextImage();
private:
std::vector<std::shared_ptr<Cvb::Image>> _images;
int _currentImageIndex = 0;
};

main.cpp:

// Example for RTP streaming.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <chrono>
#include <future>
#include <exception>
#include <cvb/global.hpp>
#include <cvb/block.hpp>
#include <cvb/rtpstreaming/rtpstreaming.hpp>
#include <cvb/rtpstreaming/stream_config.hpp>
#include <cvb/rtpstreaming/stream.hpp>
#include "DeviceSimulator.hpp"
// flag to cancel the streaming
std::atomic<bool> cancelFlag(false);
// Waits for 'Enter' key to be pressed
void CheckForCancel()
{
std::cin.get();
cancelFlag.store(true);
}
int main()
{
try
{
// create stream configuration
auto config = Cvb::RTPStreaming::StreamConfig::Create();
config->SetDstAddr("127.0.0.1");
config->SetDstPort(6005);
// load preconfigured h264 configuration
auto codecFile = Cvb::InstallPath() + Cvb::String(CVB_LIT("tutorial\\RTPStreaming\\Images\\h264.json"));
std::ifstream codecFileStream(codecFile);
if (!codecFileStream)
throw std::runtime_error("h264.json file not found");
std::stringstream buffer;
buffer << codecFileStream.rdbuf();
config->SetupCodecFromJSON(buffer.str());
// write sdp file for ffplay
auto sdp = config->ReadSessionDescriptionProtocol();
std::ofstream sdpFile("h264.sdp");
sdpFile << sdp;
sdpFile.close();
std::cout << "Wrote h264.sdp file to the current working directory" << std::endl;
// create stream with config
auto stream = Cvb::RTPStreaming::Stream::Create(*config);
// create test images (4 seconds with the preconfigured 25 fps)
auto deviceSim = DeviceSimulator(100);
std::cout.clear();
std::cout << "Stream successfully set up. You should now start ffplay to receive the stream images." << std::endl;
std::cout << "ffplay should be started via the command line like this: " << std::endl;
std::cout << "ffplay -protocol_whitelist rtp,file,udp -i h264.sdp" << std::endl;
std::cout << "Press 'Enter' once ffplay is running to continue" << std::endl;
// wait for user input
std::cin.get();
std::cout << "Streaming images... press 'Enter' to stop streaming" << std::endl;
std::thread cancelThread(CheckForCancel);
// stream the images
auto streamTask = std::async(std::launch::async, [&]() {
while (!cancelFlag.load())
{
auto start = std::chrono::high_resolution_clock::now();
stream->PushImage(*deviceSim.GetNextImage());
auto end = std::chrono::high_resolution_clock::now();
// calculate frame delay
// stream is preconfigured via the json file with 25 fps (which corresponds to a period of 40ms)
// additionally, subtract measured encoding length
std::this_thread::sleep_for(std::chrono::milliseconds(40) - (end - start));
}
});
// Wait for 'Enter' to be pressed to cancel
cancelThread.join();
// Wait for the asynchronous task to finish
streamTask.wait();
}
catch (const std::exception& e)
{
std::string msg = e.what();
if (msg.find("avutil") != std::string::npos)
std::cout << "FFmpeg not found. Make sure you have installed FFmpeg and added it to your PATH environment variable. Error message: " << msg << std::endl;
else
std::cout << msg << std::endl;
}
return 0;
}
static std::unique_ptr< Stream > Create(const StreamConfig &streamConfig)
std::string String
String InstallPath()