summaryrefslogtreecommitdiffstats
path: root/server/mjpeg_encoder.c
diff options
context:
space:
mode:
authorYonit Halperin <yhalperi@redhat.com>2013-02-20 21:01:22 -0500
committerYonit Halperin <yhalperi@redhat.com>2013-04-22 16:30:53 -0400
commit622d7159c26876d9a579b0dadee52091a87220b9 (patch)
tree7e1625725842f74cc9930509452bc7a50a208a88 /server/mjpeg_encoder.c
parentff1bde1d81d3f28c9079e8c274748253eb93b8d8 (diff)
downloadspice-622d7159c26876d9a579b0dadee52091a87220b9.tar.gz
spice-622d7159c26876d9a579b0dadee52091a87220b9.tar.xz
spice-622d7159c26876d9a579b0dadee52091a87220b9.zip
mjpeg_encoder: add stream warmup time, in which we avoid server and client drops
The stream starts after lossless frames were sent to the client, and without rate control (except for pipe congestion). Thus, on the beginning of the stream, we might observe frame drops on the client and server side which are not necessarily related to mis-estimation of the bit rate, and we would like to wait till the stream stabilizes.
Diffstat (limited to 'server/mjpeg_encoder.c')
-rw-r--r--server/mjpeg_encoder.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
index 41d234ec..7328ea26 100644
--- a/server/mjpeg_encoder.c
+++ b/server/mjpeg_encoder.c
@@ -59,6 +59,15 @@ static const int mjpeg_quality_samples[MJPEG_QUALITY_SAMPLE_NUM] = {20, 30, 40,
*/
#define MJPEG_MAX_CLIENT_PLAYBACK_DELAY 5000 // 5 sec
+/*
+ * The stream starts after lossless frames were sent to the client,
+ * and without rate control (except for pipe congestion). Thus, on the beginning
+ * of the stream, we might observe frame drops on the client and server side which
+ * are not necessarily related to mis-estimation of the bit rate, and we would
+ * like to wait till the stream stabilizes.
+ */
+#define MJPEG_WARMUP_TIME 3000L // 3 sec
+
enum {
MJPEG_QUALITY_EVAL_TYPE_SET,
MJPEG_QUALITY_EVAL_TYPE_UPGRADE,
@@ -140,6 +149,7 @@ typedef struct MJpegEncoderRateControl {
uint64_t sum_recent_enc_size;
uint32_t num_recent_enc_frames;
+ uint64_t warmup_start_time;
} MJpegEncoderRateControl;
struct MJpegEncoder {
@@ -182,12 +192,16 @@ MJpegEncoder *mjpeg_encoder_new(int bit_rate_control, uint64_t starting_bit_rate
enc->rate_control_is_active = bit_rate_control;
enc->rate_control.byte_rate = starting_bit_rate / 8;
if (bit_rate_control) {
+ struct timespec time;
+
+ clock_gettime(CLOCK_MONOTONIC, &time);
enc->cbs = *cbs;
enc->cbs_opaque = opaque;
mjpeg_encoder_reset_quality(enc, MJPEG_QUALITY_SAMPLE_NUM / 2, 5, 0);
enc->rate_control.during_quality_eval = TRUE;
enc->rate_control.quality_eval_data.type = MJPEG_QUALITY_EVAL_TYPE_SET;
enc->rate_control.quality_eval_data.reason = MJPEG_QUALITY_EVAL_REASON_RATE_CHANGE;
+ enc->rate_control.warmup_start_time = ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
} else {
mjpeg_encoder_reset_quality(enc, MJPEG_LEGACY_STATIC_QUALITY_ID, MJPEG_MAX_FPS, 0);
}
@@ -904,6 +918,19 @@ static void mjpeg_encoder_decrease_bit_rate(MJpegEncoder *encoder)
rate_control->client_state.max_video_latency = 0;
rate_control->client_state.max_audio_latency = 0;
+ if (rate_control->warmup_start_time) {
+ struct timespec time;
+ uint64_t now;
+
+ clock_gettime(CLOCK_MONOTONIC, &time);
+ now = ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
+ if (now - rate_control->warmup_start_time < MJPEG_WARMUP_TIME*1000*1000) {
+ spice_debug("during warmup. ignoring");
+ return;
+ } else {
+ rate_control->warmup_start_time = 0;
+ }
+ }
if (bit_rate_info->num_enc_frames > MJPEG_BIT_RATE_EVAL_MIN_NUM_FRAMES ||
bit_rate_info->num_enc_frames > rate_control->fps) {