summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Stebbins <[email protected]>2016-03-15 11:35:07 -0600
committerJohn Stebbins <[email protected]>2016-03-15 11:36:54 -0600
commit0e309a8f0deb18f759904fa865506f341ff207bd (patch)
tree1c68e4ee5fbcd7c5af6e52a7fd69d74396a3592b
parentd961c289a20d9e2e84fd8c763baa1c6abdb4b414 (diff)
LinGui: simplify live preview and preview hud code
This makes live preview playback somewhat less efficient. But the code is more portable and doesn't have some of the glitchy issues with rendering the HUD.
-rw-r--r--gtk/src/ghb-3.12.ui8
-rw-r--r--gtk/src/ghb-3.14.ui8
-rw-r--r--gtk/src/ghb.ui8
-rw-r--r--gtk/src/main.c7
-rw-r--r--gtk/src/preview.c989
5 files changed, 319 insertions, 701 deletions
diff --git a/gtk/src/ghb-3.12.ui b/gtk/src/ghb-3.12.ui
index 023f79c73..f2a06c0c7 100644
--- a/gtk/src/ghb-3.12.ui
+++ b/gtk/src/ghb-3.12.ui
@@ -8158,7 +8158,7 @@ Setting this to 0 means there is no maximum height.</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkLayout" id="preview_image">
+ <object class="GtkEventBox" id="preview_image">
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
@@ -8175,7 +8175,6 @@ Setting this to 0 means there is no maximum height.</property>
<child>
<object class="GtkEventBox" id="preview_hud">
<property name="visible">False</property>
- <property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
@@ -8187,7 +8186,6 @@ Setting this to 0 means there is no maximum height.</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK</property>
<signal name="enter-notify-event" handler="hud_enter_cb" swapped="no"/>
<signal name="leave-notify-event" handler="hud_leave_cb" swapped="no"/>
- <signal name="size-allocate" handler="hud_size_alloc_cb" swapped="no"/>
<child>
<object class="GtkBox" id="vbox35">
<property name="orientation">vertical</property>
@@ -8383,10 +8381,6 @@ Setting this to 0 means there is no maximum height.</property>
</object>
</child>
</object>
- <packing>
- <property name="x">0</property>
- <property name="y">0</property>
- </packing>
</child>
</object>
</child>
diff --git a/gtk/src/ghb-3.14.ui b/gtk/src/ghb-3.14.ui
index e9c0421a9..2ec972040 100644
--- a/gtk/src/ghb-3.14.ui
+++ b/gtk/src/ghb-3.14.ui
@@ -8163,7 +8163,7 @@ Setting this to 0 means there is no maximum height.</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkLayout" id="preview_image">
+ <object class="GtkEventBox" id="preview_image">
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
@@ -8180,7 +8180,6 @@ Setting this to 0 means there is no maximum height.</property>
<child>
<object class="GtkEventBox" id="preview_hud">
<property name="visible">False</property>
- <property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
@@ -8192,7 +8191,6 @@ Setting this to 0 means there is no maximum height.</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK</property>
<signal name="enter-notify-event" handler="hud_enter_cb" swapped="no"/>
<signal name="leave-notify-event" handler="hud_leave_cb" swapped="no"/>
- <signal name="size-allocate" handler="hud_size_alloc_cb" swapped="no"/>
<child>
<object class="GtkBox" id="vbox35">
<property name="orientation">vertical</property>
@@ -8388,10 +8386,6 @@ Setting this to 0 means there is no maximum height.</property>
</object>
</child>
</object>
- <packing>
- <property name="x">0</property>
- <property name="y">0</property>
- </packing>
</child>
</object>
</child>
diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui
index 9e327ed53..150819954 100644
--- a/gtk/src/ghb.ui
+++ b/gtk/src/ghb.ui
@@ -8192,7 +8192,7 @@ Setting this to 0 means there is no maximum height.</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkLayout" id="preview_image">
+ <object class="GtkEventBox" id="preview_image">
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
@@ -8209,7 +8209,6 @@ Setting this to 0 means there is no maximum height.</property>
<child>
<object class="GtkEventBox" id="preview_hud">
<property name="visible">False</property>
- <property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
@@ -8221,7 +8220,6 @@ Setting this to 0 means there is no maximum height.</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK</property>
<signal name="enter-notify-event" handler="hud_enter_cb" swapped="no"/>
<signal name="leave-notify-event" handler="hud_leave_cb" swapped="no"/>
- <signal name="size-allocate" handler="hud_size_alloc_cb" swapped="no"/>
<child>
<object class="GtkBox" id="vbox35">
<property name="orientation">vertical</property>
@@ -8417,10 +8415,6 @@ Setting this to 0 means there is no maximum height.</property>
</object>
</child>
</object>
- <packing>
- <property name="x">0</property>
- <property name="y">0</property>
- </packing>
</child>
</object>
</child>
diff --git a/gtk/src/main.c b/gtk/src/main.c
index fcde54d1e..4f2a80579 100644
--- a/gtk/src/main.c
+++ b/gtk/src/main.c
@@ -745,7 +745,12 @@ GtkEntry { \n\
@define-color gray46 #757575; \n\
@define-color white #ffffff; \n\
\n\
-#preview_hud, \n\
+#preview_hud \n\
+{ \n\
+ border-radius: 20px; \n\
+ background-color: alpha(@gray18, 0.8); \n\
+ color: @white; \n\
+} \n\
#live_preview_play, \n\
#live_duration, \n\
#preview_fullscreen \n\
diff --git a/gtk/src/preview.c b/gtk/src/preview.c
index 865702b05..361a5e09d 100644
--- a/gtk/src/preview.c
+++ b/gtk/src/preview.c
@@ -29,19 +29,8 @@
#include <glib-object.h>
#include "ghbcompat.h"
-#if !defined(_WIN32)
-#include <gdk/gdkx.h>
-#else
-#include <gdk/gdkwin32.h>
-#endif
-
#if defined(_ENABLE_GST)
#include <gst/gst.h>
-#if GST_CHECK_VERSION(1, 0, 0)
-#include <gst/video/videooverlay.h>
-#else
-#include <gst/interfaces/xoverlay.h>
-#endif
#include <gst/video/video.h>
#include <gst/pbutils/missing-plugins.h>
#endif
@@ -62,83 +51,40 @@ struct preview_s
{
#if defined(_ENABLE_GST)
GstElement *play;
- gulong xid;
+ GstElement *vsink;
#endif
- gint64 len;
- gint64 pos;
- gboolean seek_lock;
- gboolean progress_lock;
- gint width;
- gint height;
- GtkWidget *view;
- GdkPixbuf *pix;
- gint button_width;
- gint button_height;
- gint frame;
- gint state;
- gboolean pause;
- gboolean encoded[GHB_PREVIEW_MAX];
- gint encode_frame;
- gint live_id;
- gchar *current;
- gint live_enabled;
+ gint64 len;
+ gint64 pos;
+ gboolean seek_lock;
+ gboolean progress_lock;
+ gint width;
+ gint height;
+ GtkWidget * view;
+ GdkPixbuf * pix;
+ gint button_width;
+ gint button_height;
+ gint frame;
+ gint state;
+ gboolean pause;
+ gboolean encoded[GHB_PREVIEW_MAX];
+ gint encode_frame;
+ gint live_id;
+ gchar * current;
+ gint live_enabled;
};
#if defined(_ENABLE_GST)
G_MODULE_EXPORT gboolean live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data);
-static GstBusSyncReply create_window(GstBus *bus, GstMessage *msg,
- gpointer data);
#endif
void
ghb_screen_par(signal_user_data_t *ud, gint *par_n, gint *par_d)
{
-#if defined(_ENABLE_GST)
- GValue disp_par = {0,};
- GstElement *xover;
- GObjectClass *klass;
- GParamSpec *pspec;
-
- if (!ud->preview->live_enabled)
- goto fail;
-
- g_value_init(&disp_par, GST_TYPE_FRACTION);
- gst_value_set_fraction(&disp_par, 1, 1);
- g_object_get(ud->preview->play, "video-sink", &xover, NULL);
- if (xover == NULL)
- goto fail;
-
- klass = G_OBJECT_GET_CLASS(xover);
- if (klass == NULL)
- goto fail;
-
- pspec = g_object_class_find_property(klass, "pixel-aspect_ratio");
- if (pspec)
- {
- GValue par_prop = {0,};
-
- g_value_init(&par_prop, pspec->value_type);
- g_object_get_property(G_OBJECT(xover), "pixel-aspect-ratio",
- &par_prop);
- if (!g_value_transform(&par_prop, &disp_par))
- {
- g_warning("transform failed");
- gst_value_set_fraction(&disp_par, 1, 1);
- }
- g_value_unset(&par_prop);
- }
- *par_n = gst_value_get_fraction_numerator(&disp_par);
- *par_d = gst_value_get_fraction_denominator(&disp_par);
- g_value_unset(&disp_par);
- return;
-
-fail:
+ // Assume 1:1
+ // I could get it from GtkWindow->GdkScreen monitor methods.
+ // But it's going to be 1:1 anyway, so why bother.
*par_n = 1;
*par_d = 1;
-#else
- *par_n = 1;
- *par_d = 1;
-#endif
}
void
@@ -162,12 +108,6 @@ ghb_par_scale(signal_user_data_t *ud, gint *width, gint *height, gint par_n, gin
*height = *height * den / num;
}
-static GdkWindow*
-preview_window(GtkWidget *widget)
-{
- return gtk_layout_get_bin_window(GTK_LAYOUT(widget));
-}
-
void
preview_set_size(signal_user_data_t *ud, int width, int height)
{
@@ -175,7 +115,6 @@ preview_set_size(signal_user_data_t *ud, int width, int height)
widget = GHB_WIDGET (ud->builder, "preview_image");
gtk_widget_set_size_request(widget, width, height);
- gtk_layout_set_size(GTK_LAYOUT(widget), width, height);
widget = GHB_WIDGET (ud->builder, "preview_hud_box");
gtk_widget_set_size_request(widget, width, height);
@@ -188,61 +127,21 @@ ghb_preview_init(signal_user_data_t *ud)
{
GtkWidget *widget;
- ud->preview = g_malloc0(sizeof(preview_t));
- ud->preview->view = GHB_WIDGET(ud->builder, "preview_image");
- gtk_widget_realize(ud->preview->view);
-
- ud->preview->pause = TRUE;
+ ud->preview = g_malloc0(sizeof(preview_t));
+ ud->preview->pause = TRUE;
ud->preview->encode_frame = -1;
- ud->preview->live_id = -1;
- widget = GHB_WIDGET(ud->builder, "preview_button_image");
- gtk_widget_get_size_request(widget, &ud->preview->button_width, &ud->preview->button_height);
+ ud->preview->live_id = -1;
- widget = GHB_WIDGET(ud->builder, "preview_hud");
- gtk_widget_realize(widget);
- // Use a native window for the HUD. Client side windows don't get
- // updated properly as video changes benieth them.
- // This also seems to be required to make the preview hud visible
- // on win32. otherwise it is transparent for some reason.
- if (!gdk_window_ensure_native(gtk_widget_get_window(widget)))
- {
- g_message("Couldn't create native window for HUD.");
- }
+ widget = GHB_WIDGET(ud->builder, "preview_button_image");
+ gtk_widget_get_size_request(widget, &ud->preview->button_width,
+ &ud->preview->button_height);
#if defined(_ENABLE_GST)
GstBus *bus;
- GstElement *xover;
-
- if (!gdk_window_ensure_native(preview_window(ud->preview->view)))
- {
- g_message("Couldn't create native window for GstXOverlay. Disabling live preview.");
- GtkWidget *widget = GHB_WIDGET(ud->builder, "live_preview_box");
- gtk_widget_hide (widget);
- widget = GHB_WIDGET(ud->builder, "live_preview_duration_box");
- gtk_widget_hide (widget);
- return;
- }
-#if !defined(_WIN32)
- ud->preview->xid = GDK_WINDOW_XID(preview_window(ud->preview->view));
-#else
- ud->preview->xid = GDK_WINDOW_HWND(preview_window(ud->preview->view));
-#endif
- ud->preview->play = gst_element_factory_make("playbin", "play");
- xover = gst_element_factory_make("gconfvideosink", "xover");
- if (xover == NULL)
- {
- xover = gst_element_factory_make("xvimagesink", "xover");
- }
- if (xover == NULL)
- {
- xover = gst_element_factory_make("ximagesink", "xover");
- }
- if (xover == NULL)
- {
- xover = gst_element_factory_make("autovideosink", "xover");
- }
- if (ud->preview->play == NULL || xover == NULL)
+ ud->preview->play = gst_element_factory_make("playbin", "play");
+ ud->preview->vsink = gst_element_factory_make("gdkpixbufsink", "pixsink");
+ if (ud->preview->play == NULL || ud->preview->vsink == NULL)
{
g_message("Couldn't initialize gstreamer. Disabling live preview.");
GtkWidget *widget = GHB_WIDGET(ud->builder, "live_preview_box");
@@ -253,18 +152,14 @@ ghb_preview_init(signal_user_data_t *ud)
}
else
{
-
- g_object_set(G_OBJECT(ud->preview->play), "video-sink", xover, NULL);
+ g_object_set(ud->preview->vsink, "qos", FALSE,
+ "max-lateness", (gint64) - 1, NULL);
+ g_object_set(ud->preview->play, "video-sink", ud->preview->vsink, NULL);
g_object_set(ud->preview->play, "subtitle-font-desc",
- "sans bold 20", NULL);
+ "sans bold 20", NULL);
bus = gst_pipeline_get_bus(GST_PIPELINE(ud->preview->play));
gst_bus_add_watch(bus, live_preview_cb, ud);
-#if GST_CHECK_VERSION(1, 0, 0)
- gst_bus_set_sync_handler(bus, create_window, ud->preview, NULL);
-#else
- gst_bus_set_sync_handler(bus, create_window, ud->preview);
-#endif
gst_object_unref(bus);
ud->preview->live_enabled = 1;
}
@@ -287,42 +182,101 @@ ghb_preview_cleanup(signal_user_data_t *ud)
}
#if defined(_ENABLE_GST)
-static GstBusSyncReply
-create_window(GstBus *bus, GstMessage *msg, gpointer data)
+void
+live_preview_start(signal_user_data_t *ud)
{
- preview_t *preview = (preview_t*)data;
+ GtkImage *img;
+ gchar *uri;
- switch (GST_MESSAGE_TYPE(msg))
+ if (!ud->preview->live_enabled)
+ return;
+
+ img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
+ if (!ud->preview->encoded[ud->preview->frame])
{
- case GST_MESSAGE_ELEMENT:
+ gtk_image_set_from_icon_name(img, GHB_PLAY_ICON, GTK_ICON_SIZE_BUTTON);
+ gst_element_set_state(ud->preview->play, GST_STATE_NULL);
+ ud->preview->pause = TRUE;
+ return;
+ }
+
+ if (ud->preview->state != PREVIEW_STATE_LIVE)
{
-#if GST_CHECK_VERSION(1, 0, 0)
- if (!gst_is_video_overlay_prepare_window_handle_message(msg))
- return GST_BUS_PASS;
- gst_video_overlay_set_window_handle(
- GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(msg)), preview->xid);
-#else
- if (!gst_structure_has_name(msg->structure, "prepare-xwindow-id"))
- return GST_BUS_PASS;
-#if !defined(_WIN32)
- gst_x_overlay_set_xwindow_id(
- GST_X_OVERLAY(GST_MESSAGE_SRC(msg)), preview->xid);
+#if defined(_WIN32)
+ uri = g_strdup_printf("file:///%s", ud->preview->current);
#else
- gst_directdraw_sink_set_window_id(
- GST_X_OVERLAY(GST_MESSAGE_SRC(msg)), preview->xid);
+ uri = g_strdup_printf("file://%s", ud->preview->current);
+#endif
+ gtk_image_set_from_icon_name(img, GHB_PAUSE_ICON, GTK_ICON_SIZE_BUTTON);
+ ud->preview->state = PREVIEW_STATE_LIVE;
+ g_object_set(G_OBJECT(ud->preview->play), "uri", uri, NULL);
+ g_free(uri);
+ }
+ gst_element_set_state(ud->preview->play, GST_STATE_PLAYING);
+ ud->preview->pause = FALSE;
+}
+
+void
+live_preview_pause(signal_user_data_t *ud)
+{
+ GtkImage *img;
+
+ if (!ud->preview->live_enabled)
+ return;
+
+ img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
+ gtk_image_set_from_icon_name(img, GHB_PLAY_ICON, GTK_ICON_SIZE_BUTTON);
+ gst_element_set_state(ud->preview->play, GST_STATE_PAUSED);
+ ud->preview->pause = TRUE;
+}
#endif
+
+void
+live_preview_stop(signal_user_data_t *ud)
+{
+ GtkImage *img;
+ GtkRange *progress;
+
+ if (!ud->preview->live_enabled)
+ return;
+
+ img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
+ gtk_image_set_from_icon_name(img, GHB_PLAY_ICON, GTK_ICON_SIZE_BUTTON);
+#if defined(_ENABLE_GST)
+ gst_element_set_state(ud->preview->play, GST_STATE_NULL);
#endif
- gst_message_unref(msg);
- return GST_BUS_DROP;
- } break;
+ ud->preview->pause = TRUE;
+ ud->preview->state = PREVIEW_STATE_IMAGE;
+
+ progress = GTK_RANGE(GHB_WIDGET(ud->builder, "live_preview_progress"));
+ gtk_range_set_value(progress, 0);
+}
- default:
+void
+ghb_live_reset(signal_user_data_t *ud)
+{
+ gboolean encoded;
+
+ if (ud->preview->live_id >= 0)
{
- } break;
+ ghb_stop_live_encode();
}
- return GST_BUS_PASS;
+ ud->preview->live_id = -1;
+ ud->preview->encode_frame = -1;
+ if (!ud->preview->pause)
+ live_preview_stop(ud);
+ if (ud->preview->current)
+ {
+ g_free(ud->preview->current);
+ ud->preview->current = NULL;
+ }
+ encoded = ud->preview->encoded[ud->preview->frame];
+ memset(ud->preview->encoded, 0, sizeof(gboolean) * GHB_PREVIEW_MAX);
+ if (encoded)
+ ghb_set_preview_image(ud);
}
+#if defined(_ENABLE_GST)
static void
caps_set(GstCaps *caps, signal_user_data_t *ud)
{
@@ -380,7 +334,6 @@ caps_set(GstCaps *caps, signal_user_data_t *ud)
}
}
-#if GST_CHECK_VERSION(1, 0, 0)
static void
update_stream_info(signal_user_data_t *ud)
{
@@ -407,88 +360,10 @@ update_stream_info(signal_user_data_t *ud)
caps_set(caps, ud);
gst_caps_unref(caps);
}
- //g_signal_connect(vpad, "notify::caps", G_CALLBACK(caps_set_cb), preview);
gst_object_unref(vpad);
}
}
-#else
-
-static GList *
-get_stream_info_objects_for_type (GstElement *play, const gchar *typestr)
-{
- GList *info_list = NULL, *link;
- GList *ret = NULL;
-
- if (play == NULL)
- return NULL;
-
- g_object_get(play, "stream-info", &info_list, NULL);
- if (info_list == NULL)
- return NULL;
-
- link = info_list;
- while (link)
- {
- GObject *info_obj = (GObject*)link->data;
- if (info_obj)
- {
- GParamSpec *pspec;
- GEnumValue *value;
- gint type = -1;
-
- g_object_get(info_obj, "type", &type, NULL);
- pspec = g_object_class_find_property(
- G_OBJECT_GET_CLASS (info_obj), "type");
- value = g_enum_get_value(
- G_PARAM_SPEC_ENUM (pspec)->enum_class, type);
- if (value)
- {
- if (g_ascii_strcasecmp (value->value_nick, typestr) == 0 ||
- g_ascii_strcasecmp (value->value_name, typestr) == 0)
- {
- ret = g_list_prepend (ret, g_object_ref (info_obj));
- }
- }
- }
- if (link) link = link->next;
- }
- return g_list_reverse (ret);
-}
-
-static void
-update_stream_info(signal_user_data_t *ud)
-{
- GList *vstreams, *ll;
- GstPad *vpad = NULL;
-
- vstreams = get_stream_info_objects_for_type(ud->preview->play, "video");
- if (vstreams)
- {
- for (ll = vstreams; vpad == NULL && ll != NULL; ll = ll->next)
- {
- g_object_get(ll->data, "object", &vpad, NULL);
- }
- }
- if (vpad)
- {
- GstCaps *caps;
-
- caps = gst_pad_get_negotiated_caps(vpad);
- if (caps)
- {
- caps_set(caps, ud);
- gst_caps_unref(caps);
- }
- //g_signal_connect(vpad, "notify::caps", G_CALLBACK(caps_set_cb), preview);
- gst_object_unref(vpad);
- }
- g_list_foreach(vstreams, (GFunc)g_object_unref, NULL);
- g_list_free(vstreams);
-}
-
-#endif
-
G_MODULE_EXPORT gboolean
live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data)
{
@@ -496,290 +371,232 @@ live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data)
switch (GST_MESSAGE_TYPE(msg))
{
- case GST_MESSAGE_UNKNOWN:
- {
- //printf("unknown");
- } break;
+ case GST_MESSAGE_UNKNOWN:
+ {
+ //printf("unknown");
+ } break;
- case GST_MESSAGE_EOS:
- {
- // Done
- GtkImage *img;
+ case GST_MESSAGE_EOS:
+ {
+ // Done
+ //printf("eos\n");
+ live_preview_stop(ud);
+ gst_element_seek(ud->preview->play, 1.0,
+ GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
+ GST_SEEK_TYPE_SET, 0,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+ } break;
+
+ case GST_MESSAGE_ERROR:
+ {
+ //printf("error\n");
+ GError *err;
+ gchar *debug;
+
+ gst_message_parse_error(msg, &err, &debug);
+ g_warning("Gstreamer Error: %s", err->message);
+ g_error_free(err);
+ g_free(debug);
+ } break;
+
+ case GST_MESSAGE_WARNING:
+ case GST_MESSAGE_INFO:
+ case GST_MESSAGE_TAG:
+ case GST_MESSAGE_BUFFERING:
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ //printf("state change %x\n", state);
+ GstState state, pending;
+ gst_element_get_state(ud->preview->play, &state, &pending, 0);
+ if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)
+ {
+ update_stream_info(ud);
+ }
+ } break;
- //printf("eos");
- img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
- gtk_image_set_from_icon_name(img, GHB_PLAY_ICON, GTK_ICON_SIZE_BUTTON);
- gst_element_set_state(ud->preview->play, GST_STATE_PAUSED);
- ud->preview->pause = TRUE;
- gst_element_seek(ud->preview->play, 1.0,
- GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
- GST_SEEK_TYPE_SET, 0,
- GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
- } break;
+ case GST_MESSAGE_STATE_DIRTY:
+ {
+ //printf("state dirty\n");
+ } break;
- case GST_MESSAGE_ERROR:
- {
- //printf("error\n");
- GError *err;
- gchar *debug;
-
- gst_message_parse_error(msg, &err, &debug);
- g_warning("Gstreamer Error: %s", err->message);
- g_error_free(err);
- g_free(debug);
- } break;
-
- case GST_MESSAGE_WARNING:
- case GST_MESSAGE_INFO:
- case GST_MESSAGE_TAG:
- case GST_MESSAGE_BUFFERING:
- case GST_MESSAGE_STATE_CHANGED:
- {
- GstState state, pending;
- gst_element_get_state(ud->preview->play, &state, &pending, 0);
- //printf("state change %x\n", state);
- if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)
+ case GST_MESSAGE_STEP_DONE:
{
- update_stream_info(ud);
- }
- } break;
+ //printf("step done\n");
+ } break;
- case GST_MESSAGE_STATE_DIRTY:
- {
- //printf("state dirty\n");
- } break;
+ case GST_MESSAGE_CLOCK_PROVIDE:
+ {
+ //printf("clock provide\n");
+ } break;
- case GST_MESSAGE_STEP_DONE:
- {
- //printf("step done\n");
- } break;
+ case GST_MESSAGE_CLOCK_LOST:
+ {
+ //printf("clock lost\n");
+ } break;
- case GST_MESSAGE_CLOCK_PROVIDE:
- {
- //printf("clock provide\n");
- } break;
+ case GST_MESSAGE_NEW_CLOCK:
+ {
+ //printf("new clock\n");
+ } break;
- case GST_MESSAGE_CLOCK_LOST:
- {
- //printf("clock lost\n");
- } break;
+ case GST_MESSAGE_STRUCTURE_CHANGE:
+ {
+ //printf("structure change\n");
+ } break;
- case GST_MESSAGE_NEW_CLOCK:
- {
- //printf("new clock\n");
- } break;
+ case GST_MESSAGE_STREAM_STATUS:
+ {
+ //printf("stream status\n");
+ } break;
- case GST_MESSAGE_STRUCTURE_CHANGE:
- {
- //printf("structure change\n");
- } break;
+ case GST_MESSAGE_APPLICATION:
+ {
+ //printf("application\n");
+ } break;
- case GST_MESSAGE_STREAM_STATUS:
- {
- //printf("stream status\n");
- } break;
+ case GST_MESSAGE_ELEMENT:
+ {
+ //printf("element\n");
+ if (gst_is_missing_plugin_message(msg))
+ {
+ GtkWindow *hb_window;
+ hb_window = GTK_WINDOW(GHB_WIDGET(ud->builder, "hb_window"));
+ gst_element_set_state(ud->preview->play, GST_STATE_PAUSED);
+ gchar *message, *desc;
+ desc = gst_missing_plugin_message_get_description(msg);
+ message = g_strdup_printf(
+ _("Missing GStreamer plugin\n"
+ "Audio or Video may not play as expected\n\n%s"),
+ desc);
+ ghb_message_dialog(hb_window, GTK_MESSAGE_WARNING,
+ message, "Ok", NULL);
+ g_free(message);
+ gst_element_set_state(ud->preview->play, GST_STATE_PLAYING);
+ }
+ else if (msg->src == GST_OBJECT_CAST(ud->preview->vsink))
+ {
+ const GstStructure *gstStruct;
+ const GValue *val;
- case GST_MESSAGE_APPLICATION:
- {
- //printf("application\n");
- } break;
+ gstStruct = gst_message_get_structure(msg);
+ if (gstStruct != NULL &&
+ (gst_structure_has_name(gstStruct, "preroll-pixbuf") ||
+ gst_structure_has_name(gstStruct, "pixbuf")))
+ {
+ val = gst_structure_get_value(gstStruct, "pixbuf");
+ if (val != NULL)
+ {
+ GdkPixbuf *pixbuf;
+ GtkWidget *widget;
+ int width, height;
+
+ pixbuf = GDK_PIXBUF(g_value_dup_object(val));
+ width = gdk_pixbuf_get_width(pixbuf);
+ height = gdk_pixbuf_get_height(pixbuf);
+ if (width != ud->preview->width ||
+ height != ud->preview->height)
+ {
+ GdkPixbuf *tmp;
+ tmp = gdk_pixbuf_scale_simple(pixbuf,
+ ud->preview->width,
+ ud->preview->height,
+ GDK_INTERP_BILINEAR);
+ g_object_unref(pixbuf);
+ pixbuf = tmp;
+ }
+ if (ud->preview->pix != NULL)
+ {
+ g_object_unref(ud->preview->pix);
+ }
+ ud->preview->pix = pixbuf;
+ widget = GHB_WIDGET (ud->builder, "preview_image");
+ gtk_widget_queue_draw(widget);
+ }
+ }
+ }
+ } break;
- case GST_MESSAGE_ELEMENT:
- {
- //printf("element\n");
- if (gst_is_missing_plugin_message(msg))
+ case GST_MESSAGE_SEGMENT_START:
{
- GtkWindow *hb_window;
- hb_window = GTK_WINDOW(GHB_WIDGET(ud->builder, "hb_window"));
- gst_element_set_state(ud->preview->play, GST_STATE_PAUSED);
- gchar *message, *desc;
- desc = gst_missing_plugin_message_get_description(msg);
- message = g_strdup_printf(
- _("Missing GStreamer plugin\n"
- "Audio or Video may not play as expected\n\n%s"),
- desc);
- ghb_message_dialog(hb_window, GTK_MESSAGE_WARNING,
- message, "Ok", NULL);
- g_free(message);
- gst_element_set_state(ud->preview->play, GST_STATE_PLAYING);
- }
- } break;
-
- case GST_MESSAGE_SEGMENT_START:
- {
- //printf("segment start\n");
- } break;
+ //printf("segment start\n");
+ } break;
- case GST_MESSAGE_SEGMENT_DONE:
- {
- //printf("segment done\n");
- } break;
+ case GST_MESSAGE_SEGMENT_DONE:
+ {
+ //printf("segment done\n");
+ } break;
-#if GST_CHECK_VERSION(1, 0, 0)
- case GST_MESSAGE_DURATION_CHANGED:
- {
- //printf("duration change\n");
- };
-#endif
+ case GST_MESSAGE_DURATION_CHANGED:
+ {
+ //printf("duration change\n");
+ };
- case GST_MESSAGE_LATENCY:
- {
- //printf("latency\n");
- };
+ case GST_MESSAGE_LATENCY:
+ {
+ //printf("latency\n");
+ };
- case GST_MESSAGE_ASYNC_START:
- {
- //printf("async start\n");
- } break;
+ case GST_MESSAGE_ASYNC_START:
+ {
+ //printf("async start\n");
+ } break;
- case GST_MESSAGE_ASYNC_DONE:
- {
- //printf("async done\n");
- } break;
+ case GST_MESSAGE_ASYNC_DONE:
+ {
+ //printf("async done\n");
+ } break;
- case GST_MESSAGE_REQUEST_STATE:
- {
- //printf("request state\n");
- } break;
+ case GST_MESSAGE_REQUEST_STATE:
+ {
+ //printf("request state\n");
+ } break;
- case GST_MESSAGE_STEP_START:
- {
- //printf("step start\n");
- } break;
+ case GST_MESSAGE_STEP_START:
+ {
+ //printf("step start\n");
+ } break;
- case GST_MESSAGE_QOS:
- {
- //printf("qos\n");
- } break;
+ case GST_MESSAGE_QOS:
+ {
+ //printf("qos\n");
+ } break;
-#if GST_CHECK_VERSION(1, 0, 0)
- case GST_MESSAGE_PROGRESS:
- {
- //printf("progress\n");
- } break;
+ case GST_MESSAGE_PROGRESS:
+ {
+ //printf("progress\n");
+ } break;
- case GST_MESSAGE_TOC:
- {
- //printf("toc\n");
- } break;
+ case GST_MESSAGE_TOC:
+ {
+ //printf("toc\n");
+ } break;
- case GST_MESSAGE_RESET_TIME:
- {
- //printf("reset time\n");
- } break;
+ case GST_MESSAGE_RESET_TIME:
+ {
+ //printf("reset time\n");
+ } break;
- case GST_MESSAGE_STREAM_START:
- {
- //printf("stream start\n");
- };
-#endif
+ case GST_MESSAGE_STREAM_START:
+ {
+ //printf("stream start\n");
+ };
- case GST_MESSAGE_ANY:
- {
- //printf("any\n");
- } break;
+ case GST_MESSAGE_ANY:
+ {
+ //printf("any\n");
+ } break;
- default:
- {
- // Ignore
- //printf("?msg? %x\n", GST_MESSAGE_TYPE(msg));
- }
+ default:
+ {
+ // Ignore
+ //printf("?msg? %x\n", GST_MESSAGE_TYPE(msg));
+ }
}
return TRUE;
}
-
-void
-live_preview_start(signal_user_data_t *ud)
-{
- GtkImage *img;
- gchar *uri;
-
- if (!ud->preview->live_enabled)
- return;
-
- img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
- if (!ud->preview->encoded[ud->preview->frame])
- {
- gtk_image_set_from_icon_name(img, GHB_PLAY_ICON, GTK_ICON_SIZE_BUTTON);
- gst_element_set_state(ud->preview->play, GST_STATE_NULL);
- ud->preview->pause = TRUE;
- return;
- }
-
-#if defined(_WIN32)
- uri = g_strdup_printf("file:///%s", ud->preview->current);
-#else
- uri = g_strdup_printf("file://%s", ud->preview->current);
-#endif
- gtk_image_set_from_icon_name(img, GHB_PAUSE_ICON, GTK_ICON_SIZE_BUTTON);
- ud->preview->state = PREVIEW_STATE_LIVE;
- g_object_set(G_OBJECT(ud->preview->play), "uri", uri, NULL);
- gst_element_set_state(ud->preview->play, GST_STATE_PLAYING);
- ud->preview->pause = FALSE;
- g_free(uri);
-}
-
-void
-live_preview_pause(signal_user_data_t *ud)
-{
- GtkImage *img;
-
- if (!ud->preview->live_enabled)
- return;
-
- img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
- gtk_image_set_from_icon_name(img, GHB_PLAY_ICON, GTK_ICON_SIZE_BUTTON);
- gst_element_set_state(ud->preview->play, GST_STATE_PAUSED);
- ud->preview->pause = TRUE;
-}
#endif
-void
-live_preview_stop(signal_user_data_t *ud)
-{
- GtkImage *img;
- GtkRange *progress;
-
- if (!ud->preview->live_enabled)
- return;
-
- img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
- gtk_image_set_from_icon_name(img, GHB_PLAY_ICON, GTK_ICON_SIZE_BUTTON);
-#if defined(_ENABLE_GST)
- gst_element_set_state(ud->preview->play, GST_STATE_NULL);
-#endif
- ud->preview->pause = TRUE;
- ud->preview->state = PREVIEW_STATE_IMAGE;
-
- progress = GTK_RANGE(GHB_WIDGET(ud->builder, "live_preview_progress"));
- gtk_range_set_value(progress, 0);
-}
-
-void
-ghb_live_reset(signal_user_data_t *ud)
-{
- gboolean encoded;
-
- if (ud->preview->live_id >= 0)
- {
- ghb_stop_live_encode();
- }
- ud->preview->live_id = -1;
- ud->preview->encode_frame = -1;
- if (!ud->preview->pause)
- live_preview_stop(ud);
- if (ud->preview->current)
- {
- g_free(ud->preview->current);
- ud->preview->current = NULL;
- }
- encoded = ud->preview->encoded[ud->preview->frame];
- memset(ud->preview->encoded, 0, sizeof(gboolean) * GHB_PREVIEW_MAX);
- if (encoded)
- ghb_set_preview_image(ud);
-}
-
G_MODULE_EXPORT void
live_preview_start_cb(GtkWidget *xwidget, signal_user_data_t *ud)
{
@@ -885,22 +702,14 @@ ghb_live_preview_progress(signal_user_data_t *ud)
return;
ud->preview->progress_lock = TRUE;
-#if GST_CHECK_VERSION(1, 0, 0)
if (gst_element_query_duration(ud->preview->play, fmt, &len))
-#else
- if (gst_element_query_duration(ud->preview->play, &fmt, &len))
-#endif
{
if (len != -1 && fmt == GST_FORMAT_TIME)
{
ud->preview->len = len / GST_MSECOND;
}
}
-#if GST_CHECK_VERSION(1, 0, 0)
if (gst_element_query_position(ud->preview->play, fmt, &pos))
-#else
- if (gst_element_query_position(ud->preview->play, &fmt, &pos))
-#endif
{
if (pos != -1 && fmt == GST_FORMAT_TIME)
{
@@ -1040,181 +849,12 @@ ghb_set_preview_image(signal_user_data_t *ud)
}
}
-static cairo_region_t*
-curved_rect_mask(GtkWidget *widget)
-{
- GdkWindow *window;
- cairo_region_t *shape;
- cairo_surface_t *surface;
- cairo_t *cr;
- double w, h;
- int radius;
-
- if (!gtk_widget_get_realized(widget))
- return NULL;
-
- window = gtk_widget_get_window(widget);
- w = gdk_window_get_width(window);
- h = gdk_window_get_height(window);
- if (w <= 50 || h <= 50)
- return NULL;
- radius = h / 4;
- surface = gdk_window_create_similar_surface(window,
- CAIRO_CONTENT_COLOR_ALPHA,
- w, h);
- cr = cairo_create (surface);
-
- if (radius > w / 2)
- radius = w / 2;
- if (radius > h / 2)
- radius = h / 2;
-
- // fill shape with black
- cairo_save(cr);
- cairo_rectangle (cr, 0, 0, w, h);
- cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
- cairo_fill (cr);
- cairo_restore (cr);
-
- cairo_move_to (cr, 0, radius);
- cairo_curve_to (cr, 0 , 0, 0 , 0, radius, 0);
- cairo_line_to (cr, w - radius, 0);
- cairo_curve_to (cr, w, 0, w, 0, w, radius);
- cairo_line_to (cr, w , h - radius);
- cairo_curve_to (cr, w, h, w, h, w - radius, h);
- cairo_line_to (cr, 0 + radius, h);
- cairo_curve_to (cr, 0, h, 0, h, 0, h - radius);
-
- cairo_close_path(cr);
-
- cairo_set_source_rgb(cr, 1, 1, 1);
- cairo_fill(cr);
-
- cairo_destroy(cr);
- shape = gdk_cairo_region_create_from_surface(surface);
- cairo_surface_destroy(surface);
-
- return shape;
-}
-
-static void
-hud_update_shape(GtkWidget *widget)
-{
- cairo_region_t *shape;
- shape = curved_rect_mask(widget);
- if (shape != NULL)
- {
- gtk_widget_shape_combine_region(widget, shape);
- cairo_region_destroy(shape);
- }
-}
-
-#if defined(_ENABLE_GST)
-#if GST_CHECK_VERSION(1, 0, 0)
-G_MODULE_EXPORT gboolean
-delayed_expose_cb(signal_user_data_t *ud)
-{
- GstElement *vsink;
- GstVideoOverlay *vover;
-
- if (!ud->preview->live_enabled)
- return FALSE;
-
- g_object_get(ud->preview->play, "video-sink", &vsink, NULL);
- if (vsink == NULL)
- return FALSE;
-
- if (GST_IS_BIN(vsink))
- vover = GST_VIDEO_OVERLAY(gst_bin_get_by_interface(
- GST_BIN(vsink), GST_TYPE_VIDEO_OVERLAY));
- else
- vover = GST_VIDEO_OVERLAY(vsink);
- gst_video_overlay_expose(vover);
- // This function is initiated by g_idle_add. Must return false
- // so that it is not called again
- return FALSE;
-}
-#else
-G_MODULE_EXPORT gboolean
-delayed_expose_cb(signal_user_data_t *ud)
-{
- GstElement *vsink;
- GstXOverlay *xover;
-
- if (!ud->preview->live_enabled)
- return FALSE;
-
- g_object_get(ud->preview->play, "video-sink", &vsink, NULL);
- if (vsink == NULL)
- return FALSE;
-
- if (GST_IS_BIN(vsink))
- xover = GST_X_OVERLAY(gst_bin_get_by_interface(
- GST_BIN(vsink), GST_TYPE_X_OVERLAY));
- else
- xover = GST_X_OVERLAY(vsink);
- gst_x_overlay_expose(xover);
- // This function is initiated by g_idle_add. Must return false
- // so that it is not called again
- return FALSE;
-}
-#endif
-#endif
-
G_MODULE_EXPORT gboolean
preview_draw_cb(
GtkWidget *widget,
cairo_t *cr,
signal_user_data_t *ud)
{
-#if defined(_ENABLE_GST)
-#if GST_CHECK_VERSION(1, 0, 0)
- if (ud->preview->live_enabled && ud->preview->state == PREVIEW_STATE_LIVE)
- {
- if (GST_STATE(ud->preview->play) >= GST_STATE_PAUSED)
- {
- GstElement *vsink;
- GstVideoOverlay *vover;
-
- g_object_get(ud->preview->play, "video-sink", &vsink, NULL);
- if (GST_IS_BIN(vsink))
- vover = GST_VIDEO_OVERLAY(gst_bin_get_by_interface(
- GST_BIN(vsink), GST_TYPE_VIDEO_OVERLAY));
- else
- vover = GST_VIDEO_OVERLAY(vsink);
- gst_video_overlay_expose(vover);
- // For some reason, the exposed region doesn't always get
- // cleaned up here. But a delayed gst_x_overlay_expose()
- // takes care of it.
- g_idle_add((GSourceFunc)delayed_expose_cb, ud);
- }
- return FALSE;
- }
-#else
- if (ud->preview->live_enabled && ud->preview->state == PREVIEW_STATE_LIVE)
- {
- if (GST_STATE(ud->preview->play) >= GST_STATE_PAUSED)
- {
- GstElement *vsink;
- GstXOverlay *xover;
-
- g_object_get(ud->preview->play, "video-sink", &vsink, NULL);
- if (GST_IS_BIN(vsink))
- xover = GST_X_OVERLAY(gst_bin_get_by_interface(
- GST_BIN(vsink), GST_TYPE_X_OVERLAY));
- else
- xover = GST_X_OVERLAY(vsink);
- gst_x_overlay_expose(xover);
- // For some reason, the exposed region doesn't always get
- // cleaned up here. But a delayed gst_x_overlay_expose()
- // takes care of it.
- g_idle_add((GSourceFunc)delayed_expose_cb, ud);
- }
- return FALSE;
- }
-#endif
-#endif
-
if (ud->preview->pix != NULL)
{
_draw_pixbuf(cr, ud->preview->pix);
@@ -1487,15 +1127,6 @@ preview_motion_cb(
return FALSE;
}
-G_MODULE_EXPORT void
-hud_size_alloc_cb(
- GtkWidget *widget,
- GtkAllocation *allocation,
- signal_user_data_t *ud)
-{
- hud_update_shape(widget);
-}
-
G_MODULE_EXPORT gboolean
preview_configure_cb(
GtkWidget *widget,