HACK: add 444 support and other hacks.

This commit is contained in:
Michael Scherle 2025-05-23 15:44:56 +02:00
parent d561f81855
commit c464464005
3 changed files with 90 additions and 15 deletions

View File

@ -2230,6 +2230,15 @@ DisplayChannel::DisplayChannel(RedsState *reds,
set_cap(SPICE_DISPLAY_CAP_PREF_VIDEO_CODEC_TYPE);
set_cap(SPICE_DISPLAY_CAP_STREAM_REPORT);
//TODO actualy check
set_cap(SPICE_DISPLAY_CAP_CODEC_H264);
set_cap(SPICE_DISPLAY_CAP_CODEC_VP9);
set_cap(SPICE_DISPLAY_CAP_CODEC_H265);
set_cap(SPICE_DISPLAY_CAP_CODEC_AV1);
set_cap(SPICE_DISPLAY_CAP_CODEC_VP9_444);
set_cap(SPICE_DISPLAY_CAP_CODEC_H265_444);
// set_cap(SPICE_DISPLAY_CAP_CODEC_VP9_U);
reds_register_channel(reds, this);
}

View File

@ -919,10 +919,17 @@ static const gchar* get_gst_codec_name(const SpiceGstEncoder *encoder)
return "avenc_mjpeg";
case SPICE_VIDEO_CODEC_TYPE_VP8:
return "vp8enc";
case SPICE_VIDEO_CODEC_TYPE_H264_444:
case SPICE_VIDEO_CODEC_TYPE_H264:
return "x264enc";
case SPICE_VIDEO_CODEC_TYPE_VP9_444:
case SPICE_VIDEO_CODEC_TYPE_VP9:
return "vp9enc";
case SPICE_VIDEO_CODEC_TYPE_H265_444:
case SPICE_VIDEO_CODEC_TYPE_H265:
return "x265enc";
case SPICE_VIDEO_CODEC_TYPE_AV1:
return "av1enc";
default:
/* gstreamer_encoder_new() should have rejected this codec type */
spice_warning("unsupported codec type %d", encoder->base.codec_type);
@ -937,6 +944,16 @@ static const char video_codecs[][8] = {
{ "h264" },
{ "vp9" },
{ "h265" },
{ "av1" },
{ "h264" },
{ "vp9" },
{ "h265" },
{ "av1" },
{ "h264"},
{ "vp9"},
{ "h265"},
{ "av1"},
};
static bool gst_features_lookup(const gchar *feature_name)
@ -990,7 +1007,7 @@ static gchar *find_best_hw_plugin(const gchar *codec_name)
}
g_free(feature_name);
if(i == 1 && codec_name){
feature_name = g_strconcat(plugins[i], "lpenc", NULL);
feature_name = g_strconcat(plugins[i], codec_name, "lpenc", NULL);
if (gst_features_lookup(feature_name)) {
return feature_name;
}
@ -1022,7 +1039,7 @@ static gchar *get_hw_gstenc_opts(const gchar *encoder, const gchar *codec_name)
}
} else {
if (strcmp(codec_name, "vp9") == 0) {
gstenc_opts = g_strdup("min-qp=15 max-qp=35 rate-control=16 ref-frames=0 target-usage=7");
gstenc_opts = g_strdup("min-qp=15 max-qp=35 rate-control=16 target-usage=7 gf-group-size=1");
} else {
gstenc_opts = g_strdup("rate-control=16 b-frames=0 target-usage=7 min-qp=15 max-qp=35");
}
@ -1030,10 +1047,12 @@ static gchar *get_hw_gstenc_opts(const gchar *encoder, const gchar *codec_name)
return gstenc_opts;
}
static void try_intel_hw_plugins(const gchar *codec_name, gchar **converter,
static void try_intel_hw_plugins(SpiceGstEncoder* spice_encoder, gchar **converter,
gchar **gstenc_name, gchar **gstenc_opts)
{
gchar *encoder, *vpp;
SpiceVideoCodecType codec_type = spice_encoder->base.codec_type;
const char *codec_name = video_codecs[codec_type];
if (strcmp(codec_name, "vp8") == 0) {
return;
@ -1055,11 +1074,20 @@ static void try_intel_hw_plugins(const gchar *codec_name, gchar **converter,
*gstenc_name = encoder;
*gstenc_opts = get_hw_gstenc_opts(encoder, codec_name);
if (g_str_has_prefix(vpp, "vaapi")) {
*converter = g_strconcat(vpp, " ! video/x-raw(memory:VASurface),format=NV12", NULL);
} else {
*converter = g_strconcat(vpp, " ! video/x-raw(memory:VAMemory),format=NV12", NULL);
char format[5] = "NV12";
if( codec_type == SPICE_VIDEO_CODEC_TYPE_AV1_444 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_H264_444 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_H265_444 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_VP9_444 ) {
g_strlcpy(format,"VUYA",5);
}
char memory[11] = "VASurface";
if(!g_str_has_prefix(vpp, "vaapi")){
g_strlcpy(memory,"VAMemory",11);
}
*converter = g_strdup_printf(" %s ! capsfilter name=vpp caps=\"video/x-raw(memory:%s),format=%s\"",
vpp, memory,format);
g_free(vpp);
}
@ -1113,6 +1141,7 @@ static gboolean create_pipeline(SpiceGstEncoder *encoder)
case SPICE_VIDEO_CODEC_TYPE_MJPEG:
gstenc_opts = g_strdup("");
break;
case SPICE_VIDEO_CODEC_TYPE_VP9_444:
case SPICE_VIDEO_CODEC_TYPE_VP9:
case SPICE_VIDEO_CODEC_TYPE_VP8: {
/* See http://www.webmproject.org/docs/encoder-parameters/
@ -1134,6 +1163,7 @@ static gboolean create_pipeline(SpiceGstEncoder *encoder)
gstenc_opts = g_strdup_printf("end-usage=cbr min-quantizer=10 error-resilient=default lag-in-frames=0 deadline=1 cpu-used=4");
break;
}
case SPICE_VIDEO_CODEC_TYPE_H264_444:
case SPICE_VIDEO_CODEC_TYPE_H264:
/* - Set tune and sliced-threads to ensure a zero-frame latency
* - qp-min ensures the bitrate does not get needlessly high.
@ -1146,6 +1176,23 @@ static gboolean create_pipeline(SpiceGstEncoder *encoder)
*/
gstenc_opts = g_strdup("byte-stream=true aud=true qp-min=15 qp-max=35 tune=4 sliced-threads=true speed-preset=ultrafast intra-refresh=true");
break;
case SPICE_VIDEO_CODEC_TYPE_H265_444:
case SPICE_VIDEO_CODEC_TYPE_H265:
/* - Set tune and sliced-threads to ensure a zero-frame latency
* - qp-min ensures the bitrate does not get needlessly high.
* - qp-max ensures the compression does not go so high that the videoclear
* is unrecognizable. When that threshold is reached it is better to
* drop frames to lower the bit rate further.
* - Set speed-preset to get realtime speed.
* - Set intra-refresh to get more uniform compressed frame sizes,
* thus helping with streaming.
*/
gstenc_opts = g_strdup("qp=15 tune=4 speed-preset=ultrafast ");
break;
case SPICE_VIDEO_CODEC_TYPE_AV1_444:
case SPICE_VIDEO_CODEC_TYPE_AV1:
gstenc_opts = g_strdup("");
break;
default:
/* gstreamer_encoder_new() should have rejected this codec type */
spice_warning("unsupported codec type %d", encoder->base.codec_type);
@ -1154,10 +1201,9 @@ static gboolean create_pipeline(SpiceGstEncoder *encoder)
return FALSE;
}
const char *codec_name = video_codecs[encoder->base.codec_type];
GpuVendor vendor = spice_udev_detect_gpu(INTEL_VENDOR_ID);
if (vendor == VENDOR_GPU_DETECTED) {
try_intel_hw_plugins(codec_name, &converter, &gstenc_name,
try_intel_hw_plugins(encoder, &converter, &gstenc_name,
&gstenc_opts);
}
@ -1673,9 +1719,9 @@ spice_gst_encoder_configure_pipeline(SpiceGstEncoder *encoder,
return VIDEO_ENCODER_FRAME_UNSUPPORTED;
}
if (width != encoder->width || height != encoder->height ||
if ((width != encoder->width || height != encoder->height ||
encoder->spice_format != spice_format ||
encoder->drm_format != drm_format) {
encoder->drm_format != drm_format) && (width > 0 && height > 0)) {
spice_debug("video format change: width %d -> %d, height %d -> %d,"
"spice format %d -> %d, drm format %u -> %u",
encoder->width, width, encoder->height, height,
@ -1716,7 +1762,7 @@ spice_gst_encoder_configure_pipeline(SpiceGstEncoder *encoder,
if (handle_server_drops(encoder, frame_mm_time) ||
frame_mm_time < encoder->next_frame_mm_time) {
/* Drop the frame to limit the outgoing bit rate. */
return VIDEO_ENCODER_FRAME_DROP;
//return VIDEO_ENCODER_FRAME_DROP;
}
if (!configure_pipeline(encoder)) {
@ -2023,7 +2069,13 @@ VideoEncoder *gstreamer_encoder_new(SpiceVideoCodecType codec_type,
spice_return_val_if_fail(codec_type == SPICE_VIDEO_CODEC_TYPE_MJPEG ||
codec_type == SPICE_VIDEO_CODEC_TYPE_VP8 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_VP9 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_H264, NULL);
codec_type == SPICE_VIDEO_CODEC_TYPE_H264||
codec_type == SPICE_VIDEO_CODEC_TYPE_H264 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_H265 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_H264_444 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_H265_444 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_VP9_444 ||
codec_type == SPICE_VIDEO_CODEC_TYPE_AV1, NULL);
GError *err = NULL;
if (!gst_init_check(NULL, NULL, &err)) {

View File

@ -3461,11 +3461,11 @@ err:
static const char default_renderer[] = "sw";
#if defined(HAVE_GSTREAMER_1_0)
#define GSTREAMER_CODECS "gstreamer:mjpeg;gstreamer:h264;gstreamer:vp8;gstreamer:vp9;"
#define GSTREAMER_CODECS "gstreamer:h264;gstreamer:h265;gstreamer:vp8;gstreamer:vp9;gstreamer:av1;gstreamer:h265_444;gstreamer:vp9_444;gstreamer:mjpeg;"
#else
#define GSTREAMER_CODECS ""
#endif
static const char default_video_codecs[] = "spice:mjpeg;" GSTREAMER_CODECS;
static const char default_video_codecs[] = GSTREAMER_CODECS "spice:mjpeg;";
/* new interface */
SPICE_GNUC_VISIBLE SpiceServer *spice_server_new(void)
@ -3583,6 +3583,13 @@ static const EnumNames video_codec_names[] = {
{SPICE_VIDEO_CODEC_TYPE_VP8, "vp8"},
{SPICE_VIDEO_CODEC_TYPE_H264, "h264"},
{SPICE_VIDEO_CODEC_TYPE_VP9, "vp9"},
{SPICE_VIDEO_CODEC_TYPE_H265, "h265"},
{SPICE_VIDEO_CODEC_TYPE_AV1, "av1"},
{SPICE_VIDEO_CODEC_TYPE_H264_444, "h264_444"},
{SPICE_VIDEO_CODEC_TYPE_VP9_444, "vp9_444"},
{SPICE_VIDEO_CODEC_TYPE_H265_444, "h265_444"},
{SPICE_VIDEO_CODEC_TYPE_AV1_444, "av1_444"},
{0, nullptr},
};
@ -3591,6 +3598,13 @@ static const int video_codec_caps[] = {
SPICE_DISPLAY_CAP_CODEC_VP8,
SPICE_DISPLAY_CAP_CODEC_H264,
SPICE_DISPLAY_CAP_CODEC_VP9,
SPICE_DISPLAY_CAP_CODEC_H265,
SPICE_DISPLAY_CAP_CODEC_AV1,
SPICE_DISPLAY_CAP_CODEC_H264_444,
SPICE_DISPLAY_CAP_CODEC_VP9_444,
SPICE_DISPLAY_CAP_CODEC_H265_444,
SPICE_DISPLAY_CAP_CODEC_AV1_444,
};
char *reds_get_video_codec_fullname(RedVideoCodec *codec)