[Spice-devel] [RFC spice-server 2/3] stream-channel: Use the preferred codec list instead of supported
Kevin Pouget
kpouget at redhat.com
Tue Aug 6 15:34:46 UTC 2019
This patch computes and sends the list of the video codecs preferred
by all the clients when requesting to start or reset a video stream.
It used to be the list of the supported codecs.
The MJPEG codec is used as a fallback if there is no codec preferred
by all the clients.
Note: at the moment, the server's list of allowed video-stream codecs
is used to disable the usage of some codecs. This may not be the best
option. To be further discussed ...
Signed-off-by: Kevin Pouget <kpouget at redhat.com>
---
server/stream-channel.c | 84 +++++++++++++++++++++++++++++++++--------
1 file changed, 69 insertions(+), 15 deletions(-)
diff --git a/server/stream-channel.c b/server/stream-channel.c
index fa4804f1..e0e41895 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -356,12 +356,17 @@ stream_channel_new(RedsState *server, uint32_t id)
#define MAX_SUPPORTED_CODECS SPICE_VIDEO_CODEC_TYPE_ENUM_END
-// find common codecs supported by all clients
+// find common codecs preferred by all clients
static uint8_t
-stream_channel_get_supported_codecs(StreamChannel *channel, uint8_t *out_codecs)
+stream_channel_get_preferred_codecs(StreamChannel *channel, uint8_t *out_codecs)
{
+ RedChannel *red_channel = RED_CHANNEL(channel);
+ RedsState *reds = red_channel_get_server(red_channel);
+ GArray *allowed_codecs = reds_get_video_codecs(reds);
+
RedChannelClient *rcc;
int codec;
+ int i;
static const uint16_t codec2cap[] = {
0, // invalid
@@ -372,29 +377,78 @@ stream_channel_get_supported_codecs(StreamChannel *channel, uint8_t *out_codecs)
SPICE_DISPLAY_CAP_CODEC_H265,
};
- bool supported[SPICE_N_ELEMENTS(codec2cap)];
+ unsigned int weight[SPICE_N_ELEMENTS(codec2cap)];
+
+ /* fill the weight array with a preference weight: 0 is not
+ * supported, otherwise: weight := sum(position in preference
+ * array, for each client). */
- for (codec = 0; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
- supported[codec] = true;
+ // disable codecs not allowed by the server configuration
+ for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
+ weight[codec] = 0;
+ for (i = 0; i < allowed_codecs->len; i++) {
+ RedVideoCodec pref_codec = g_array_index(allowed_codecs, RedVideoCodec, i);
+
+ if (pref_codec.type == codec) {
+ weight[codec] = 1;
+ break;
+ }
+ }
}
FOREACH_CLIENT(channel, rcc) {
+ StreamChannelClient *scc = STREAM_CHANNEL_CLIENT(rcc);
+ GArray *preferred_codecs = scc->client_preferred_video_codecs;
+
+ g_assert(preferred_codecs == NULL ||
+ preferred_codecs->len == SPICE_VIDEO_CODEC_TYPE_ENUM_END);
+
for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
- // if do not support codec delete from list
+ // skip the codec if it is already not supported
+ if (!weight[codec]) {
+ continue;
+ }
+
+ // delete from the list if it's not supported by this client
if (!red_channel_client_test_remote_cap(rcc, codec2cap[codec])) {
- supported[codec] = false;
+ weight[codec] = 0;
+ continue;
}
+
+ // the client didn't provide a preferred codecs list
+ if (preferred_codecs == NULL) {
+ continue;
+ }
+
+ // delete the codec from the list if it's not in the preferred list
+ weight[codec] += g_array_index(preferred_codecs, gint, codec);
}
}
- // surely mjpeg is supported
- supported[SPICE_VIDEO_CODEC_TYPE_MJPEG] = true;
-
+ /* sort the codec by the preferrence weight, lower is better */
int num = 0;
- for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
- if (supported[codec]) {
- out_codecs[num++] = codec;
+
+ while (true) {
+ unsigned int min_codec, min_weight = UINT_MAX;
+
+ for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
+
+ if (weight[codec] && weight[codec] < min_weight) {
+ min_codec = codec;
+ min_weight = weight[codec];
+ }
+ }
+ if (min_weight == UINT_MAX) {
+ break;
}
+
+ out_codecs[num++] = min_codec;
+ weight[min_codec] = 0;
+ }
+
+ if (num == 0) {
+ // fallback, surely mjpeg is supported
+ out_codecs[num++] = SPICE_VIDEO_CODEC_TYPE_MJPEG;
}
return num;
@@ -432,7 +486,7 @@ stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedStream
spice_return_if_fail(client != NULL);
// request new stream
- start->num_codecs = stream_channel_get_supported_codecs(channel, start->codecs);
+ start->num_codecs = stream_channel_get_preferred_codecs(channel, start->codecs);
// send in any case, even if list is not changed
// notify device about changes
request_new_stream(channel, start);
@@ -647,7 +701,7 @@ stream_channel_reset(StreamChannel *channel)
// try to request a new stream, this should start a new stream
// if the guest is connected to the device and a client is already connected
- start->num_codecs = stream_channel_get_supported_codecs(channel, start->codecs);
+ start->num_codecs = stream_channel_get_preferred_codecs(channel, start->codecs);
// send in any case, even if list is not changed
// notify device about changes
request_new_stream(channel, start);
--
2.21.0
More information about the Spice-devel
mailing list