set internal random port for zmq

This commit is contained in:
jb-alvarado 2022-06-15 21:27:16 +02:00
parent c6f81fa8a3
commit efa6dfa5ea
9 changed files with 70 additions and 37 deletions

View File

@ -105,14 +105,10 @@ text:
help_text: Overlay text in combination with libzmq for remote text manipulation.
On windows fontfile path need to be like this 'C\:/WINDOWS/fonts/DejaVuSans.ttf'.
In a standard environment the filter drawtext node is Parsed_drawtext_2.
'over_pre' if True text will be overlay in pre processing. Continue same text
over multiple files is in that mode not possible. 'text_from_filename' activate the
extraction from text of a filename. With 'style' you can define the drawtext
parameters like position, color, etc. Post Text over API will override this.
With 'regex' you can format file names, to get a title from it.
'text_from_filename' activate the extraction from text of a filename. With 'style'
you can define the drawtext parameters like position, color, etc. Post Text over
API will override this. With 'regex' you can format file names, to get a title from it.
add_text: false
over_pre: false
bind_address: "127.0.0.1:5555"
fontfile: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
text_from_filename: false
style: "x=(w-tw)/2:y=(h-line_h)*0.9:fontsize=24:fontcolor=#ffffff:box=1:boxcolor=#000000:boxborderw=4"

View File

@ -184,7 +184,9 @@ fn extend_video(node: &mut Media, chain: &mut Filters) {
/// add drawtext filter for lower thirds messages
fn add_text(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) {
if config.text.add_text && config.text.over_pre {
if config.text.add_text
&& (config.text.text_from_filename || config.out.mode.to_lowercase() == "hls")
{
let filter = v_drawtext::filter_node(config, node);
chain.add_filter(&filter, "video");

View File

@ -4,7 +4,7 @@ use regex::Regex;
use crate::utils::{Media, PlayoutConfig};
pub fn filter_node(config: &PlayoutConfig, node: &mut Media) -> String {
pub fn filter_node(config: &PlayoutConfig, node: &Media) -> String {
let mut filter = String::new();
let mut font = String::new();
@ -13,7 +13,7 @@ pub fn filter_node(config: &PlayoutConfig, node: &mut Media) -> String {
font = format!(":fontfile='{}'", config.text.fontfile)
}
if config.text.over_pre && config.text.text_from_filename {
if config.text.text_from_filename {
let source = node.source.clone();
let regex: Regex = Regex::new(&config.text.regex).unwrap();
@ -27,10 +27,10 @@ pub fn filter_node(config: &PlayoutConfig, node: &mut Media) -> String {
.replace('%', "\\\\\\%")
.replace(':', "\\:");
filter = format!("drawtext=text='{escape}':{}{font}", config.text.style)
} else {
} else if let Some(socket) = config.text.bind_address.clone() {
filter = format!(
"zmq=b=tcp\\\\://'{}',drawtext=text=''{font}",
config.text.bind_address.replace(':', "\\:")
socket.replace(':', "\\:")
)
}
}

View File

@ -14,17 +14,19 @@ pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child {
let mut enc_cmd = vec_strings!["-hide_banner", "-nostats", "-v", log_format, "-i", "pipe:0"];
if config.text.add_text && !config.text.over_pre {
info!(
"Using drawtext filter, listening on address: <yellow>{}</>",
config.text.bind_address
);
if config.text.add_text && !config.text.text_from_filename {
if let Some(socket) = config.text.bind_address.clone() {
debug!(
"Using drawtext filter, listening on address: <yellow>{}</>",
socket
);
let mut filter: String = "null,".to_string();
filter.push_str(
v_drawtext::filter_node(config, &mut Media::new(0, String::new(), false)).as_str(),
);
enc_filter = vec!["-vf".to_string(), filter];
let mut filter: String = "null,".to_string();
filter.push_str(
v_drawtext::filter_node(config, &Media::new(0, String::new(), false)).as_str(),
);
enc_filter = vec!["-vf".to_string(), filter];
}
}
enc_cmd.append(&mut enc_filter);

View File

@ -13,7 +13,7 @@ out:
-hls_time 6
-hls_list_size 600
-hls_flags append_list+delete_segments+omit_endlist+program_date_time
-hls_segment_filename /var/www/html/live/stream-%09d.ts /var/www/html/live/stream.m3u8
-hls_segment_filename /var/www/html/live/stream-%d.ts /var/www/html/live/stream.m3u8
*/

View File

@ -25,19 +25,21 @@ pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child {
"pipe:0"
];
if config.text.add_text && !config.text.over_pre {
info!(
"Using drawtext filter, listening on address: <yellow>{}</>",
config.text.bind_address
);
if config.text.add_text && !config.text.text_from_filename {
if let Some(socket) = config.text.bind_address.clone() {
debug!(
"Using drawtext filter, listening on address: <yellow>{}</>",
socket
);
let mut filter = "[0:v]null,".to_string();
let mut filter = "[0:v]null,".to_string();
filter.push_str(
v_drawtext::filter_node(config, &mut Media::new(0, String::new(), false)).as_str(),
);
filter.push_str(
v_drawtext::filter_node(config, &Media::new(0, String::new(), false)).as_str(),
);
enc_filter = vec!["-filter_complex".to_string(), filter];
enc_filter = vec!["-filter_complex".to_string(), filter];
}
}
if config.out.preview {

View File

@ -8,7 +8,7 @@ use std::{
use serde::{Deserialize, Serialize};
use shlex::split;
use crate::utils::{time_to_sec, Args};
use crate::utils::{free_tcp_socket, time_to_sec, Args};
use crate::vec_strings;
/// Global Config
@ -137,8 +137,13 @@ pub struct Storage {
pub struct Text {
pub help_text: String,
pub add_text: bool,
pub over_pre: bool,
pub bind_address: String,
#[serde(skip_serializing, skip_deserializing)]
pub bind_address: Option<String>,
#[serde(skip_serializing, skip_deserializing)]
pub node_pos: Option<usize>,
pub fontfile: String,
pub text_from_filename: bool,
pub style: String,
@ -243,6 +248,17 @@ impl PlayoutConfig {
config.out.preview_cmd = split(config.out.preview_param.as_str());
config.out.output_cmd = split(config.out.output_param.as_str());
// when text overlay without text_from_filename is on, turn also the RPC server on,
// to get text messages from it
if config.text.add_text && !config.text.text_from_filename {
config.rpc_server.enable = true;
config.text.bind_address = free_tcp_socket();
config.text.node_pos = Some(2);
} else {
config.text.bind_address = None;
config.text.node_pos = None;
}
// Read command line arguments, and override the config with them.
if let Some(arg) = args {

View File

@ -142,7 +142,7 @@ pub fn read_json(
return set_defaults(playlist, current_file, start_sec);
}
error!("Read playlist error, on: <b><magenta>{current_file}</></b>!");
error!("Read playlist error, on: <b><magenta>{current_file}</></b>");
JsonPlaylist::new(date, start_sec)
}

View File

@ -1,6 +1,7 @@
use std::{
fs::{self, metadata},
io::{BufRead, BufReader, Error},
net::TcpListener,
path::Path,
process::{exit, ChildStderr, Command, Stdio},
time::{self, UNIX_EPOCH},
@ -9,6 +10,7 @@ use std::{
use chrono::{prelude::*, Duration};
use ffprobe::{ffprobe, Format, Stream};
use jsonrpc_http_server::hyper::HeaderMap;
use rand::prelude::*;
use regex::Regex;
use reqwest::header;
use serde::{Deserialize, Serialize};
@ -596,6 +598,19 @@ pub fn validate_ffmpeg(config: &PlayoutConfig) {
}
}
/// get a free tcp socket
pub fn free_tcp_socket() -> Option<String> {
for _ in 0..100 {
let port = rand::thread_rng().gen_range(45321..54268);
if TcpListener::bind(("127.0.0.1", port)).is_ok() {
return Some(format!("127.0.0.1:{port}"));
}
}
None
}
/// Get system time, in non test case.
#[cfg(not(test))]
pub fn time_now() -> DateTime<Local> {