mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-21 00:40:13 +00:00
Added+use dynamic rate limiter
Added a rate limiter that occasionally allows excessive frames. It permits using 1.5x frame time for frame 2x bigger that moving average if 4 normal frames (using .75x frame time) were emitted inbetween. This mode is now default (for video, audio doesn't use rate limiter).
This commit is contained in:
@@ -117,8 +117,10 @@ int get_audio_delay(void);
|
||||
void set_audio_delay(int val);
|
||||
|
||||
#define RATE_UNLIMITED 0
|
||||
#define RATE_AUTO (-1)
|
||||
#define RATE_DEFAULT (-2)
|
||||
#define RATE_AUTO (-1) ///< spread packets evenly across frame time (currently 3/4)
|
||||
#define RATE_DYNAMIC (-2) ///< same as @ref RATE_AUTO but occasional excess frame allowed
|
||||
#define RATE_MIN RATE_DYNAMIC
|
||||
#define RATE_DEFAULT (-3) ///< imaginary value, must not be passed to trasmit module
|
||||
#define RATE_FLAG_FIXED_RATE (1ll<<62ll) ///< use the bitrate as fixed, not capped
|
||||
|
||||
struct init_data;
|
||||
|
||||
@@ -505,6 +505,7 @@ static void *capture_thread(void *arg)
|
||||
static bool parse_bitrate(char *optarg, long long int *bitrate) {
|
||||
map<const char *, long long int> bitrate_spec_map = {
|
||||
{ "auto", RATE_AUTO },
|
||||
{ "dynamic", RATE_DYNAMIC },
|
||||
{ "unlimited", RATE_UNLIMITED },
|
||||
};
|
||||
|
||||
@@ -515,9 +516,10 @@ static bool parse_bitrate(char *optarg, long long int *bitrate) {
|
||||
if (strcmp(optarg, "help") == 0) {
|
||||
const char numeric_pattern[] = "{1-9}{0-9}*[kMG][!][E]";
|
||||
cout << "Usage:\n" <<
|
||||
"\tuv " << BOLD("-l [auto | unlimited | " << numeric_pattern << "]\n") <<
|
||||
"\tuv " << BOLD("-l [auto | dynamic | unlimited | " << numeric_pattern << "]\n") <<
|
||||
"\twhere\n"
|
||||
"\t\t" << BOLD("auto") << " - spread packets across frame time\n"
|
||||
"\t\t" << BOLD("dynamic") << " - similar to \"auto\" but more relaxed - occasional huge frame can spread 1.5x frame time (default)\n"
|
||||
"\t\t" << BOLD("unlimited") << " - send packets at a wire speed (in bursts)\n"
|
||||
"\t\t" << BOLD(numeric_pattern) << " - send packets at most at specified bitrate\n\n" <<
|
||||
BOLD("Notes: ") << "Use an exclamation mark to indicate intentionally very low bitrate. 'E' to use the value as a fixed bitrate, not cap /i. e. even the frames that may be sent at lower bitrate are sent at the nominal bitrate)\n" <<
|
||||
@@ -1306,7 +1308,7 @@ static int adjust_params(struct ug_options *opt) {
|
||||
opt->bitrate = opt->bitrate == RATE_DEFAULT ? RATE_UNLIMITED : opt->bitrate;
|
||||
} else {
|
||||
opt->requested_mtu = opt->requested_mtu == 0 ? 1500 : opt->requested_mtu;
|
||||
opt->bitrate = opt->bitrate == RATE_DEFAULT ? RATE_AUTO : opt->bitrate;
|
||||
opt->bitrate = opt->bitrate == RATE_DEFAULT ? RATE_DYNAMIC : opt->bitrate;
|
||||
}
|
||||
|
||||
if((strcmp("none", opt->audio.send_cfg) != 0 || strcmp("none", opt->audio.recv_cfg) != 0) && strcmp(opt->video_protocol, "rtsp") == 0){
|
||||
|
||||
@@ -126,6 +126,12 @@ tx_send_base(struct tx *tx, struct video_frame *frame, struct rtp *rtp_session,
|
||||
static bool set_fec(struct tx *tx, const char *fec);
|
||||
static void fec_check_messages(struct tx *tx);
|
||||
|
||||
struct rate_limit_dyn {
|
||||
long avg_frame_size; ///< moving average
|
||||
long long last_excess; ///< nr of frames last excessive frame was emitted
|
||||
static constexpr int EXCESS_GAP = 4; ///< minimal gap between excessive frames
|
||||
};
|
||||
|
||||
struct tx {
|
||||
struct module mod;
|
||||
|
||||
@@ -150,6 +156,7 @@ struct tx {
|
||||
const struct openssl_encrypt_info *enc_funcs;
|
||||
struct openssl_encrypt *encryption;
|
||||
long long int bitrate;
|
||||
struct rate_limit_dyn dyn_rate_limit_state;
|
||||
|
||||
char tmp_packet[RTP_MAX_MTU];
|
||||
};
|
||||
@@ -199,6 +206,11 @@ struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bitrate < RATE_MIN) {
|
||||
log_msg(LOG_LEVEL_ERROR, "Invalid bitrate value %lld passed (either positive bitrate or magic values from %d supported)!\n", bitrate, RATE_MIN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tx = (struct tx *) calloc(1, sizeof(struct tx));
|
||||
if (tx != NULL) {
|
||||
module_init_default(&tx->mod);
|
||||
@@ -331,7 +343,7 @@ static void fec_check_messages(struct tx *tx)
|
||||
} else if (strstr(text, "rate ") == text) {
|
||||
text += strlen("rate ");
|
||||
auto new_rate = unit_evaluate(text);
|
||||
if (new_rate > 0 || new_rate == RATE_UNLIMITED || new_rate == RATE_AUTO) {
|
||||
if (new_rate >= RATE_MIN) {
|
||||
tx->bitrate = new_rate;
|
||||
r = new_response(RESPONSE_OK, nullptr);
|
||||
LOG(LOG_LEVEL_NOTICE) << "[Transmit] Bitrate set to: " << text << (new_rate > 0 ? "B" : "") << "\n";
|
||||
@@ -566,6 +578,17 @@ get_packet_rate(struct tx *tx, struct video_frame *frame, int substream, long pa
|
||||
if (tx->bitrate == RATE_AUTO) { // adaptive (spread packets to 75% frame time)
|
||||
return packet_rate_auto;
|
||||
}
|
||||
if (tx->bitrate == RATE_DYNAMIC) {
|
||||
if (frame->tiles[substream].data_len > 2 * tx->dyn_rate_limit_state.avg_frame_size
|
||||
&& tx->dyn_rate_limit_state.last_excess > rate_limit_dyn::EXCESS_GAP) {
|
||||
packet_rate_auto /= 2; // double packet rate for this frame
|
||||
tx->dyn_rate_limit_state.last_excess = 0;
|
||||
} else {
|
||||
tx->dyn_rate_limit_state.last_excess += 1;
|
||||
}
|
||||
tx->dyn_rate_limit_state.avg_frame_size = (9 * tx->dyn_rate_limit_state.avg_frame_size + frame->tiles[substream].data_len) / 10;
|
||||
return packet_rate_auto;
|
||||
}
|
||||
long long int bitrate = tx->bitrate & ~RATE_FLAG_FIXED_RATE;
|
||||
int avg_packet_size = frame->tiles[substream].data_len / packet_count;
|
||||
long packet_rate = 1000'000'000L * avg_packet_size * 8 / bitrate; // fixed rate
|
||||
@@ -796,13 +819,14 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, const audio_frame2 *
|
||||
check_symbol_size(fec_symbol_size, tx->mtu - hdrs_len);
|
||||
}
|
||||
|
||||
int packet_rate;
|
||||
int packet_rate = 0;
|
||||
#if 0
|
||||
if (tx->bitrate > 0) {
|
||||
//packet_rate = 1000ll * 1000 * 1000 * tx->mtu * 8 / tx->bitrate;
|
||||
packet_rate = 0;
|
||||
} else if (tx->bitrate == RATE_UNLIMITED) {
|
||||
packet_rate = 0;
|
||||
} else if (tx->bitrate == RATE_AUTO) {
|
||||
} else if (tx->bitrate == RATE_AUTO || tx->bitrate == RATE_DYNAMIC) {
|
||||
/**
|
||||
* @todo
|
||||
* Following code would actually work but seems to be useless in most of cases (eg.
|
||||
@@ -810,7 +834,6 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, const audio_frame2 *
|
||||
* unexpectable problems (I'd write them here but if I'd expect them they wouldn't
|
||||
* be unexpectable.)
|
||||
*/
|
||||
#if 0
|
||||
double time_for_frame = buffer->get_duration() / buffer->get_channel_count();
|
||||
if (time_for_frame > 0.0) {
|
||||
long long req_bitrate = buffer->get_data_len(channel) * 8 / time_for_frame * tx->mult_count;
|
||||
@@ -820,11 +843,11 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, const audio_frame2 *
|
||||
} else {
|
||||
packet_rate = 0;
|
||||
}
|
||||
#endif
|
||||
packet_rate = 0;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
do {
|
||||
if(tx->fec_scheme == FEC_MULT) {
|
||||
|
||||
Reference in New Issue
Block a user