-
-
Save will127534/6dc1b4e219be6d3afdf19e6a39a2cd98 to your computer and use it in GitHub Desktop.
network Preview Stage for libcamera-apps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <time.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <netinet/tcp.h> | |
#include <unistd.h> | |
#include <libcamera/stream.h> | |
#include "core/frame_info.hpp" | |
#include "core/libcamera_app.hpp" | |
#include "post_processing_stages/post_processing_stage.hpp" | |
using Stream = libcamera::Stream; | |
class networkPreviewStage : public PostProcessingStage | |
{ | |
public: | |
networkPreviewStage(LibcameraApp *app); | |
~networkPreviewStage(); | |
char const *Name() const override; | |
void Read(boost::property_tree::ptree const ¶ms) override; | |
void Configure() override; | |
bool Process(CompletedRequestPtr &completed_request) override; | |
private: | |
Stream *stream_; | |
StreamInfo info_; | |
int sockfd_; | |
std::string ip_; | |
int port_; | |
int config_port_; | |
int64_t last_timestamp_ns_; | |
void sendInfoToServer(const std::string &ip, int port, int width, int height, int stride); | |
int init_socket(const std::string &ip, int port); | |
}; | |
#define NAME "networkPreview" | |
char const *networkPreviewStage::Name() const | |
{ | |
return NAME; | |
} | |
void networkPreviewStage::Read(boost::property_tree::ptree const ¶ms) | |
{ | |
ip_ = params.get<std::string>("ip"); | |
port_ = params.get<int>("port", 255); | |
config_port_ = params.get<int>("config_port", 255); | |
} | |
networkPreviewStage::networkPreviewStage(LibcameraApp *app) : PostProcessingStage(app) | |
{ | |
} | |
networkPreviewStage::~networkPreviewStage() | |
{ | |
if (sockfd_ >= 0) | |
{ | |
close(sockfd_); | |
} | |
} | |
void networkPreviewStage::sendInfoToServer(const std::string &ip, int port, int width, int height, int stride) { | |
int sockfd = socket(AF_INET, SOCK_STREAM, 0); | |
if (sockfd < 0) { | |
perror("Error creating socket"); | |
return; | |
} | |
struct sockaddr_in server_addr; | |
memset(&server_addr, 0, sizeof(server_addr)); | |
server_addr.sin_family = AF_INET; | |
server_addr.sin_port = htons(port); | |
if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0) { | |
perror("Error setting up IP address"); | |
close(sockfd); | |
return; | |
} | |
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { | |
perror("Error connecting to server"); | |
close(sockfd); | |
return; | |
} | |
char buffer[256]; | |
snprintf(buffer, sizeof(buffer), "%d,%d,%d\n", width, height, stride); | |
send(sockfd, buffer, strlen(buffer), 0); | |
close(sockfd); | |
} | |
void networkPreviewStage::Configure() | |
{ | |
stream_ = app_->GetMainStream(); | |
if (!stream_ || stream_->configuration().pixelFormat != libcamera::formats::YUV420) | |
throw std::runtime_error("networkPreviewStage: only YUV420 format supported"); | |
info_ = app_->GetStreamInfo(stream_); | |
LOG(1, "networkPreviewStage:" << info_.width << "x" << info_.height << " " << info_.stride); | |
LOG(1, "Setting up NetworkPreview: " << ip_ << ":" << port_); | |
sendInfoToServer(ip_, config_port_, info_.width, info_.height, info_.stride); | |
sockfd_ = init_socket(ip_, port_); | |
} | |
bool networkPreviewStage::Process(CompletedRequestPtr &completed_request) | |
{ | |
BufferWriteSync w(app_, completed_request->buffers[stream_]); | |
libcamera::Span<uint8_t> buffer = w.Get()[0]; | |
int64_t timestamp_ns = completed_request->buffers[stream_]->metadata().timestamp; | |
float framerate = 1000000000.0 / (timestamp_ns - last_timestamp_ns_); | |
LOG(1, "Sending Frame:" << timestamp_ns <<" buffer size:" << buffer.size() << " " << framerate); | |
last_timestamp_ns_ = timestamp_ns; | |
if (sockfd_ >= 0) | |
{ | |
send(sockfd_, buffer.data(), buffer.size(), 0); | |
return false; | |
} | |
return true; | |
} | |
int networkPreviewStage::init_socket(const std::string &ip, int port) | |
{ | |
int sockfd = socket(AF_INET, SOCK_STREAM, 0); | |
if (sockfd < 0) | |
{ | |
perror("Error creating socket"); | |
return -1; | |
} | |
struct sockaddr_in server_addr; | |
server_addr.sin_family = AF_INET; | |
server_addr.sin_port = htons(port); | |
inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr); | |
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) | |
{ | |
perror("Error connecting to server"); | |
close(sockfd); | |
return -1; | |
} | |
int flag = 1; | |
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); | |
int bufsize = 32*1024*1024; // e.g., 1MB | |
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); | |
return sockfd; | |
} | |
static PostProcessingStage *Create(LibcameraApp *app) | |
{ | |
return new networkPreviewStage(app); | |
} | |
static RegisterStage reg(NAME, &Create); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment