A simple program that accepts RTMP streams and then restreams them directly to other services. I use it to record at a higher rate but stream to target services at the rate they want. It's also useful for streaming to multiple sites.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
distributary/server.cpp

84 lines
2.0 KiB

#include "server.hpp"
#include <nlohmann/json.hpp>
#include <fmt/core.h>
#include <fmt/chrono.h>
#include <thread>
#include "dbc.hpp"
using namespace fmt;
FILE *run_ffmpeg(Config &config) {
string ffmpeg_cmd = format("ffmpeg -listen 1 -i {} -bufsize 3000k",
config.listen_at);
for(auto &el : config.send_to) {
SendTo send_spec = el.second;
ffmpeg_cmd += format(" -maxrate {} -flags +global_header -c:v libx264 -preset veryfast -tune zerolatency -g:v 60 -vb {} -c:a copy -f flv {}",
send_spec.bitrate, send_spec.bitrate, send_spec.url);
}
println("RUNNING: {}", ffmpeg_cmd);
return popen(ffmpeg_cmd.c_str(), "re");
}
bool Server::stopped() {
return in_state(ServerState::STOP);
}
void Server::event(ServerEvent ev) {
switch(_state) {
FSM_STATE(ServerState, START, ev);
FSM_STATE(ServerState, READING, ev);
FSM_STATE(ServerState, STOP, ev);
FSM_STATE(ServerState, ERROR, ev);
}
}
void Server::START(ServerEvent ev) {
handle = run_ffmpeg(config);
if(handle == nullptr) {
dbc::log("ERROR when launching ffmpeg");
state(ServerState::ERROR);
} else {
wait_time = 200ms;
fail_count = 0;
state(ServerState::READING);
}
}
void Server::READING(ServerEvent ev) {
res = fgets(buffer, BUF_MAX, handle);
if(res == nullptr) {
dbc::log("STOP shutting down...");
state(ServerState::STOP);
} else {
state(ServerState::READING);
}
}
void Server::STOP(ServerEvent ev) {
int rc = pclose(handle);
if(rc != 0) {
dbc::log("ERROR when calling pclose on ffmpeg");
state(ServerState::ERROR);
} else {
state(ServerState::STOP);
}
}
void Server::ERROR(ServerEvent ev) {
fail_count++;
if(fail_count < config.fail_max) {
println("Error in server, waiting {}...", wait_time);
wait_time *= 2;
std::this_thread::sleep_for(wait_time);
dbc::log("Attempting to run it again...");
state(ServerState::START);
} else {
dbc::log("ffmpeg failed to many times, exiting.");
state(ServerState::STOP);
}
}