Hi On Fri, Apr 18, 2025 at 3:30 PM Dietmar Maurer <diet...@proxmox.com> wrote: > > Some encoders can hang indefinetly (i.e. nvh264enc) if
indefinitely > the pipeline is not stopped before it is destroyed > (Observed on Debian bookworm). but why do you need the extra shutdown notifier? > > Signed-off-by: Dietmar Maurer <diet...@proxmox.com> > --- > ui/vnc-enc-h264.c | 50 ++++++++++++++++++++++++++++++++++++++--------- > ui/vnc.h | 1 + > 2 files changed, 42 insertions(+), 9 deletions(-) > > diff --git a/ui/vnc-enc-h264.c b/ui/vnc-enc-h264.c > index 840674dbdb..9dbfba3a16 100644 > --- a/ui/vnc-enc-h264.c > +++ b/ui/vnc-enc-h264.c > @@ -23,6 +23,8 @@ > */ > > #include "qemu/osdep.h" > +#include "system/runstate.h" > + > #include "vnc.h" > > #include <gst/gst.h> > @@ -114,13 +116,33 @@ static GstElement *create_encoder(const char > *encoder_name) > return encoder; > } > > -static void destroy_encoder_context(VncState *vs) > +static void destroy_encoder_context(VncH264 *h264) > { > - gst_clear_object(&vs->h264->source); > - gst_clear_object(&vs->h264->convert); > - gst_clear_object(&vs->h264->gst_encoder); > - gst_clear_object(&vs->h264->sink); > - gst_clear_object(&vs->h264->pipeline); > + GstStateChangeReturn state_change_ret; > + > + g_assert(h264 != NULL); > + > + VNC_DEBUG("Destroy h264 context.\n"); > + > + /* > + * Some encoders can hang indefinetly (i.e. nvh264enc) if > + * the pipeline is not stopped before it is destroyed > + * (Observed on Debian bookworm). > + */ > + if (h264->pipeline != NULL) { > + state_change_ret = gst_element_set_state( > + h264->pipeline, GST_STATE_NULL); > + > + if (state_change_ret == GST_STATE_CHANGE_FAILURE) { > + VNC_DEBUG("Unable to stop the GST pipeline\n"); > + } > + } > + > + gst_clear_object(&h264->source); > + gst_clear_object(&h264->convert); > + gst_clear_object(&h264->gst_encoder); > + gst_clear_object(&h264->sink); > + gst_clear_object(&h264->pipeline); > } > > static bool create_encoder_context(VncState *vs, int w, int h) > @@ -132,7 +154,7 @@ static bool create_encoder_context(VncState *vs, int w, > int h) > > if (vs->h264->sink) { > if (w != vs->h264->width || h != vs->h264->height) { > - destroy_encoder_context(vs); > + destroy_encoder_context(vs->h264); > } > } > > @@ -239,10 +261,16 @@ static bool create_encoder_context(VncState *vs, int w, > int h) > return TRUE; > > error: > - destroy_encoder_context(vs); > + destroy_encoder_context(vs->h264); > return FALSE; > } > > +static void shutdown_h264(Notifier *n, void *opaque) > +{ > + VncH264 *h264 = container_of(n, VncH264, shutdown_notifier); > + destroy_encoder_context(h264); > +} > + > bool vnc_h264_encoder_init(VncState *vs) > { > char *encoder_name; > @@ -259,6 +287,8 @@ bool vnc_h264_encoder_init(VncState *vs) > > vs->h264 = g_new0(VncH264, 1); > vs->h264->encoder_name = encoder_name; > + vs->h264->shutdown_notifier.notify = shutdown_h264; > + qemu_register_shutdown_notifier(&vs->h264->shutdown_notifier); > > VNC_DEBUG("Allow H264 using encoder '%s`\n", encoder_name); > > @@ -362,7 +392,9 @@ void vnc_h264_clear(VncState *vs) > return; > } > > - destroy_encoder_context(vs); > + notifier_remove(&vs->h264->shutdown_notifier); > + > + destroy_encoder_context(vs->h264); > g_free(vs->h264->encoder_name); > > g_clear_pointer(&vs->h264, g_free); > diff --git a/ui/vnc.h b/ui/vnc.h > index 789b18806b..ea52085b19 100644 > --- a/ui/vnc.h > +++ b/ui/vnc.h > @@ -248,6 +248,7 @@ typedef struct VncH264 { > size_t width; > size_t height; > guint keep_dirty; > + Notifier shutdown_notifier; > } VncH264; > #endif > > -- > 2.39.5 >