summaryrefslogtreecommitdiffstats
path: root/gtk/src/preview.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/src/preview.c')
-rw-r--r--gtk/src/preview.c456
1 files changed, 391 insertions, 65 deletions
diff --git a/gtk/src/preview.c b/gtk/src/preview.c
index d8cfd64bf..d62026e7c 100644
--- a/gtk/src/preview.c
+++ b/gtk/src/preview.c
@@ -23,7 +23,11 @@
#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
@@ -151,8 +155,13 @@ ghb_preview_init(signal_user_data_t *ud)
ud->preview = g_malloc0(sizeof(preview_t));
ud->preview->view = GHB_WIDGET(ud->builder, "preview_image");
gtk_widget_realize(ud->preview->view);
+#if GTK_CHECK_VERSION(3, 0, 0)
+ g_signal_connect(G_OBJECT(ud->preview->view), "draw",
+ G_CALLBACK(preview_expose_cb), ud);
+#else
g_signal_connect(G_OBJECT(ud->preview->view), "expose_event",
G_CALLBACK(preview_expose_cb), ud);
+#endif
ud->preview->pause = TRUE;
ud->preview->encode_frame = -1;
@@ -209,7 +218,11 @@ ghb_preview_init(signal_user_data_t *ud)
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;
}
@@ -241,6 +254,12 @@ create_window(GstBus *bus, GstMessage *msg, gpointer data)
{
case GST_MESSAGE_ELEMENT:
{
+#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)
@@ -250,6 +269,7 @@ create_window(GstBus *bus, GstMessage *msg, gpointer data)
gst_directdraw_sink_set_window_id(
GST_X_OVERLAY(GST_MESSAGE_SRC(msg)), preview->xid);
#endif
+#endif
gst_message_unref(msg);
return GST_BUS_DROP;
} break;
@@ -261,52 +281,6 @@ create_window(GstBus *bus, GstMessage *msg, gpointer data)
return GST_BUS_PASS;
}
-static GList *
-get_stream_info_objects_for_type (GstElement *play, const gchar *typestr)
-{
- GValueArray *info_arr = NULL;
- GList *ret = NULL;
- guint ii;
-
- if (play == NULL)
- return NULL;
-
- g_object_get(play, "stream-info-value-array", &info_arr, NULL);
- if (info_arr == NULL)
- return NULL;
-
- for (ii = 0; ii < info_arr->n_values; ++ii)
- {
- GObject *info_obj;
- GValue *val;
-
- val = g_value_array_get_nth(info_arr, ii);
- info_obj = g_value_get_object(val);
- 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));
- }
- }
- }
- }
- g_value_array_free (info_arr);
- return g_list_reverse (ret);
-}
-
static void
caps_set(GstCaps *caps, signal_user_data_t *ud)
{
@@ -366,6 +340,87 @@ 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)
+{
+ GstPad *vpad = NULL;
+ gint n_video;
+
+ g_object_get(G_OBJECT(ud->preview->play), "n-video", &n_video, NULL);
+ if (n_video > 0)
+ {
+ gint ii;
+ for (ii = 0; ii < n_video && vpad == NULL; ii++)
+ {
+ g_signal_emit_by_name(ud->preview->play, "get-video-pad", ii, &vpad);
+ }
+ }
+
+ if (vpad)
+ {
+ GstCaps *caps;
+
+ caps = gst_pad_get_current_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);
+ }
+}
+
+#else
+
+static GList *
+get_stream_info_objects_for_type (GstElement *play, const gchar *typestr)
+{
+ GValueArray *info_arr = NULL;
+ GList *ret = NULL;
+ guint ii;
+
+ if (play == NULL)
+ return NULL;
+
+ g_object_get(play, "stream-info-value-array", &info_arr, NULL);
+ if (info_arr == NULL)
+ return NULL;
+
+ for (ii = 0; ii < info_arr->n_values; ++ii)
+ {
+ GObject *info_obj;
+ GValue *val;
+
+ val = g_value_array_get_nth(info_arr, ii);
+ //val = &((GValue*)info_arr->values)[ii];
+ info_obj = g_value_get_object(val);
+ 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));
+ }
+ }
+ }
+ }
+ g_value_array_free (info_arr);
+ return g_list_reverse (ret);
+}
+
static void
update_stream_info(signal_user_data_t *ud)
{
@@ -397,6 +452,8 @@ update_stream_info(signal_user_data_t *ud)
g_list_free(vstreams);
}
+#endif
+
G_MODULE_EXPORT gboolean
live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data)
{
@@ -404,8 +461,30 @@ live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data)
switch (GST_MESSAGE_TYPE(msg))
{
+ case GST_MESSAGE_UNKNOWN:
+ {
+ //printf("unknown");
+ } break;
+
+ case GST_MESSAGE_EOS:
+ {
+ // Done
+ GtkImage *img;
+
+ //printf("eos");
+ img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
+ gtk_image_set_from_stock(img, "gtk-media-play", 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_ERROR:
{
+ //printf("error\n");
GError *err;
gchar *debug;
@@ -415,8 +494,64 @@ live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data)
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)
+ {
+ update_stream_info(ud);
+ }
+ } break;
+
+ case GST_MESSAGE_STATE_DIRTY:
+ {
+ //printf("state dirty\n");
+ } break;
+
+ case GST_MESSAGE_STEP_DONE:
+ {
+ //printf("step done\n");
+ } break;
+
+ case GST_MESSAGE_CLOCK_PROVIDE:
+ {
+ //printf("clock provide\n");
+ } break;
+
+ case GST_MESSAGE_CLOCK_LOST:
+ {
+ //printf("clock lost\n");
+ } break;
+
+ case GST_MESSAGE_NEW_CLOCK:
+ {
+ //printf("new clock\n");
+ } break;
+
+ case GST_MESSAGE_STRUCTURE_CHANGE:
+ {
+ //printf("structure change\n");
+ } break;
+
+ case GST_MESSAGE_STREAM_STATUS:
+ {
+ //printf("stream status\n");
+ } break;
+
+ case GST_MESSAGE_APPLICATION:
+ {
+ //printf("application\n");
+ } break;
+
case GST_MESSAGE_ELEMENT:
{
+ //printf("element\n");
if (gst_is_missing_plugin_message(msg))
{
gst_element_set_state(ud->preview->play, GST_STATE_PAUSED);
@@ -432,34 +567,85 @@ live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data)
}
} break;
- case GST_MESSAGE_STATE_CHANGED:
+ case GST_MESSAGE_SEGMENT_START:
{
- 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);
- }
+ //printf("segment start\n");
} break;
- case GST_MESSAGE_EOS:
+ case GST_MESSAGE_SEGMENT_DONE:
{
- // Done
- GtkImage *img;
+ //printf("segment done\n");
+ } break;
- img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image"));
- gtk_image_set_from_stock(img, "gtk-media-play", 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);
+#if GST_CHECK_VERSION(1, 0, 0)
+ case GST_MESSAGE_DURATION_CHANGED:
+ {
+ //printf("duration change\n");
+ };
+#endif
+
+ case GST_MESSAGE_LATENCY:
+ {
+ //printf("latency\n");
+ };
+
+ case GST_MESSAGE_ASYNC_START:
+ {
+ //printf("async start\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_STEP_START:
+ {
+ //printf("step start\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_TOC:
+ {
+ //printf("toc\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_ANY:
+ {
+ //printf("any\n");
+ } break;
+
+
default:
{
// Ignore
+ //printf("?msg? %x\n", GST_MESSAGE_TYPE(msg));
}
}
return TRUE;
@@ -645,14 +831,22 @@ 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)
{
@@ -798,6 +992,31 @@ ghb_set_preview_image(signal_user_data_t *ud)
}
#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)
{
@@ -822,6 +1041,27 @@ delayed_expose_cb(signal_user_data_t *ud)
return FALSE;
}
#endif
+#endif
+
+#if GTK_CHECK_VERSION(3, 0, 0)
+G_MODULE_EXPORT gboolean
+position_overlay_cb(
+ GtkWidget *overlay,
+ GtkWidget *widget,
+ GdkRectangle *rect,
+ signal_user_data_t *ud)
+{
+ GtkRequisition min_size, size;
+ gtk_widget_get_preferred_size(widget, &min_size, &size);
+
+ rect->width = MAX(min_size.width, size.width);
+ rect->height = MAX(min_size.height, size.height);
+ rect->x = MAX(0, ud->preview->width / 2 - rect->width / 2);
+ rect->y = MAX(0, ud->preview->height - rect->height - 50);
+
+ return TRUE;
+}
+#endif
G_MODULE_EXPORT gboolean
preview_expose_cb(
@@ -830,6 +1070,30 @@ preview_expose_cb(
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;
+ }
+ return TRUE;
+ }
+#else
if (ud->preview->live_enabled && ud->preview->state == PREVIEW_STATE_LIVE)
{
if (GST_STATE(ud->preview->play) >= GST_STATE_PAUSED)
@@ -853,10 +1117,12 @@ preview_expose_cb(
return TRUE;
}
#endif
+#endif
if (ud->preview->pix != NULL)
{
- _draw_pixbuf(gtk_widget_get_window(widget), ud->preview->pix);
+ _draw_pixbuf(gtk_widget_get_window(ud->preview->view), ud->preview->pix);
+ //_draw_pixbuf(gtk_widget_get_window(widget), ud->preview->pix);
}
return TRUE;
}
@@ -1166,6 +1432,56 @@ preview_motion_cb(
return FALSE;
}
+#if GTK_CHECK_VERSION(3, 0, 0)
+cairo_region_t*
+ghb_curved_rect_mask(gint width, gint height, gint radius)
+{
+ cairo_region_t *shape;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ double w, h;
+
+ if (!width || !height)
+ return NULL;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_A8, width, height);
+ cr = cairo_create (surface);
+
+ w = width;
+ h = height;
+ if (radius > width / 2)
+ radius = width / 2;
+ if (radius > height / 2)
+ radius = height / 2;
+
+ // fill shape with black
+ cairo_save(cr);
+ cairo_rectangle (cr, 0, 0, width, height);
+ 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;
+}
+#else
GdkDrawable*
ghb_curved_rect_mask(gint width, gint height, gint radius)
{
@@ -1212,6 +1528,7 @@ ghb_curved_rect_mask(gint width, gint height, gint radius)
return shape;
}
+#endif
G_MODULE_EXPORT void
preview_hud_size_alloc_cb(
@@ -1219,7 +1536,11 @@ preview_hud_size_alloc_cb(
GtkAllocation *allocation,
signal_user_data_t *ud)
{
+#if GTK_CHECK_VERSION(3, 0, 0)
+ cairo_region_t *shape;
+#else
GdkDrawable *shape;
+#endif
//g_message("preview_hud_size_alloc_cb()");
if (gtk_widget_get_visible(widget) && allocation->height > 50)
@@ -1228,8 +1549,13 @@ preview_hud_size_alloc_cb(
allocation->height, allocation->height/4);
if (shape != NULL)
{
+#if GTK_CHECK_VERSION(3, 0, 0)
+ gtk_widget_shape_combine_region(widget, shape);
+ cairo_region_destroy(shape);
+#else
gtk_widget_shape_combine_mask(widget, shape, 0, 0);
gdk_pixmap_unref(shape);
+#endif
}
}
}