gnome: prevent crash if video is stopped too early
This is done by connecting to the signals of the
Video::Renderer right away so that the 'stopped'
signal is never missed
Refs #71387
Change-Id: I1eac9c63f5d1ddf41f1a29d979173e328fbdc594
diff --git a/src/video/video_widget.cpp b/src/video/video_widget.cpp
index 4a9f26b..e60f65e 100644
--- a/src/video/video_widget.cpp
+++ b/src/video/video_widget.cpp
@@ -37,10 +37,8 @@
#include <video/devicemodel.h>
#include <QtCore/QUrl>
#include "../defines.h"
-
#include <stdlib.h>
#include <atomic>
-
#include "xrectsel.h"
#define VIDEO_LOCAL_SIZE 150
@@ -86,6 +84,7 @@
};
struct _VideoWidgetRenderer {
+ VideoRendererType type;
ClutterActor *actor;
Video::Renderer *renderer;
std::atomic_bool running;
@@ -100,13 +99,14 @@
#define VIDEO_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), VIDEO_WIDGET_TYPE, VideoWidgetPrivate))
/* static prototypes */
-static gboolean check_frame_queue(VideoWidget *self);
-static void renderer_stop(VideoWidgetRenderer *renderer);
-static void renderer_start(VideoWidgetRenderer *renderer);
-static void video_widget_set_renderer(VideoWidgetRenderer *renderer);
-static void on_drag_data_received(GtkWidget *, GdkDragContext *, gint, gint, GtkSelectionData *, guint, guint32, gpointer);
+static gboolean check_frame_queue (VideoWidget *);
+static void renderer_stop (VideoWidgetRenderer *);
+static void renderer_start (VideoWidgetRenderer *);
+static void on_drag_data_received (GtkWidget *, GdkDragContext *, gint, gint, GtkSelectionData *, guint, guint32, gpointer);
static gboolean on_button_press_in_screen_event(GtkWidget *, GdkEventButton *, gpointer);
-static gboolean check_renderer_queue(VideoWidget *);
+static gboolean check_renderer_queue (VideoWidget *);
+static void free_video_widget_renderer (VideoWidgetRenderer *);
+static void video_widget_add_renderer (VideoWidget *, VideoWidgetRenderer *);
/*
* video_widget_dispose()
@@ -119,14 +119,6 @@
VideoWidget *self = VIDEO_WIDGET(object);
VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self);
- QObject::disconnect(priv->remote->frame_update);
- QObject::disconnect(priv->remote->render_stop);
- QObject::disconnect(priv->remote->render_start);
-
- QObject::disconnect(priv->local->frame_update);
- QObject::disconnect(priv->local->render_stop);
- QObject::disconnect(priv->local->render_start);
-
/* dispose may be called multiple times, make sure
* not to call g_source_remove more than once */
if (priv->frame_timeout_source) {
@@ -159,8 +151,8 @@
VideoWidget *self = VIDEO_WIDGET(object);
VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self);
- g_free(priv->remote);
- g_free(priv->local);
+ free_video_widget_renderer(priv->local);
+ free_video_widget_renderer(priv->remote);
G_OBJECT_CLASS(video_widget_parent_class)->finalize(object);
}
@@ -247,7 +239,7 @@
NULL);
/* init new renderer queue */
- priv->new_renderer_queue = g_async_queue_new_full((GDestroyNotify)g_free);
+ priv->new_renderer_queue = g_async_queue_new_full((GDestroyNotify)free_video_widget_renderer);
/* check new render every 30 ms (30ms is "fast enough");
* we don't use an idle function so it doesn't consume cpu needlessly */
priv->renderer_timeout_source= g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,
@@ -471,7 +463,6 @@
static void
renderer_stop(VideoWidgetRenderer *renderer)
{
- g_return_if_fail(CLUTTER_IS_ACTOR(renderer->actor));
QObject::disconnect(renderer->frame_update);
renderer->running = false;
}
@@ -479,7 +470,6 @@
static void
renderer_start(VideoWidgetRenderer *renderer)
{
- g_return_if_fail(CLUTTER_IS_ACTOR(renderer->actor));
QObject::disconnect(renderer->frame_update);
renderer->running = true;
@@ -496,56 +486,44 @@
}
static void
-video_widget_set_renderer(VideoWidgetRenderer *renderer)
+free_video_widget_renderer(VideoWidgetRenderer *renderer)
{
- if (renderer == nullptr) return;
-
- /* reset the content gravity so that the aspect ratio gets properly set if it chagnes */
- clutter_actor_set_content_gravity(renderer->actor, CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
-
- /* update the renderer */
QObject::disconnect(renderer->frame_update);
QObject::disconnect(renderer->render_stop);
QObject::disconnect(renderer->render_start);
-
- if (renderer->renderer->isRendering())
- renderer_start(renderer);
-
- renderer->render_stop = QObject::connect(
- renderer->renderer,
- &Video::Renderer::stopped,
- [=]() {
- renderer_stop(renderer);
- }
- );
-
- renderer->render_start = QObject::connect(
- renderer->renderer,
- &Video::Renderer::started,
- [=]() {
- renderer_start(renderer);
- }
- );
+ g_free(renderer);
}
static void
-video_widget_add_renderer(VideoWidget *self, const VideoRenderer *new_renderer)
+video_widget_add_renderer(VideoWidget *self, VideoWidgetRenderer *new_video_renderer)
{
g_return_if_fail(IS_VIDEO_WIDGET(self));
- if (new_renderer == NULL || new_renderer->renderer == NULL)
- return;
+ g_return_if_fail(new_video_renderer);
+ g_return_if_fail(new_video_renderer->renderer);
VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self);
/* update the renderer */
- switch(new_renderer->type) {
+ switch(new_video_renderer->type) {
case VIDEO_RENDERER_REMOTE:
- priv->remote->renderer = new_renderer->renderer;
- video_widget_set_renderer(priv->remote);
+ /* swap the remote renderer */
+ new_video_renderer->actor = priv->remote->actor;
+ free_video_widget_renderer(priv->remote);
+ priv->remote = new_video_renderer;
+ /* reset the content gravity so that the aspect ratio gets properly
+ * reset if it chagnes */
+ clutter_actor_set_content_gravity(priv->remote->actor,
+ CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
break;
case VIDEO_RENDERER_LOCAL:
- priv->local->renderer = new_renderer->renderer;
- video_widget_set_renderer(priv->local);
+ /* swap the remote renderer */
+ new_video_renderer->actor = priv->local->actor;
+ free_video_widget_renderer(priv->local);
+ priv->local = new_video_renderer;
+ /* reset the content gravity so that the aspect ratio gets properly
+ * reset if it chagnes */
+ clutter_actor_set_content_gravity(priv->local->actor,
+ CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
break;
case VIDEO_RENDERER_COUNT:
break;
@@ -559,11 +537,10 @@
VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self);
/* get all the renderers in the queue */
- gpointer new_video_renderer = g_async_queue_try_pop(priv->new_renderer_queue);
+ VideoWidgetRenderer *new_video_renderer = (VideoWidgetRenderer *)g_async_queue_try_pop(priv->new_renderer_queue);
while (new_video_renderer) {
- video_widget_add_renderer(self, (const VideoRenderer *)new_video_renderer);
- g_free(new_video_renderer);
- new_video_renderer = g_async_queue_try_pop(priv->new_renderer_queue);
+ video_widget_add_renderer(self, new_video_renderer);
+ new_video_renderer = (VideoWidgetRenderer *)g_async_queue_try_pop(priv->new_renderer_queue);
}
return G_SOURCE_CONTINUE;
@@ -593,9 +570,31 @@
g_return_if_fail(IS_VIDEO_WIDGET(self));
VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self);
- VideoRenderer *new_video_renderer = g_new0(VideoRenderer, 1);
+ /* if the renderer is nullptr, there is nothing to be done */
+ if (!renderer) return;
+
+ VideoWidgetRenderer *new_video_renderer = g_new0(VideoWidgetRenderer, 1);
new_video_renderer->renderer = renderer;
new_video_renderer->type = type;
+ if (new_video_renderer->renderer->isRendering())
+ renderer_start(new_video_renderer);
+
+ new_video_renderer->render_stop = QObject::connect(
+ new_video_renderer->renderer,
+ &Video::Renderer::stopped,
+ [=]() {
+ renderer_stop(new_video_renderer);
+ }
+ );
+
+ new_video_renderer->render_start = QObject::connect(
+ new_video_renderer->renderer,
+ &Video::Renderer::started,
+ [=]() {
+ renderer_start(new_video_renderer);
+ }
+ );
+
g_async_queue_push(priv->new_renderer_queue, new_video_renderer);
}
diff --git a/src/video/video_widget.h b/src/video/video_widget.h
index 96a63ff..b456a4e 100644
--- a/src/video/video_widget.h
+++ b/src/video/video_widget.h
@@ -44,7 +44,6 @@
typedef struct _VideoWidgetClass VideoWidgetClass;
typedef struct _VideoWidget VideoWidget;
-typedef struct _VideoRenderer VideoRenderer;
typedef enum {
VIDEO_RENDERER_REMOTE,
@@ -52,16 +51,11 @@
VIDEO_RENDERER_COUNT
} VideoRendererType;
-struct _VideoRenderer
-{
- VideoRendererType type;
- Video::Renderer *renderer;
-};
-
/* Public interface */
GType video_widget_get_type (void) G_GNUC_CONST;
GtkWidget* video_widget_new (void);
void video_widget_push_new_renderer (VideoWidget *, Video::Renderer *, VideoRendererType);
+
G_END_DECLS
#endif /* __VIDEO_WIDGET_H__ */