| #include <gst/gst.h> |
| #include <gtk/gtk.h> |
| #include <gdk/gdkx.h> |
| #include <gst/video/video.h> |
| |
| #define WINDOW_GLADE "window.glade" |
| #define INT_PROPERTY_GLADE "int_property.glade" |
| #define ENUM_PROPERTY_GLADE "enum_property.glade" |
| #define BOOL_PROPERTY_GLADE "boolean_property.glade" |
| |
| #define PROPERTY_TO_VBOX \ |
| properties[i].dynamic ? GTK_BOX (dynamic_vbox) : GTK_BOX (static_vbox) |
| |
| #define GET_WIDGET(object, type, name) \ |
| type (gtk_builder_get_object ((object)->builder, name)) |
| |
| #define GET_PROP_WIDGET(type, name) GET_WIDGET (&(properties[i]), type, name) |
| |
| static guint h264_xid, preview_xid; |
| |
| typedef struct |
| { |
| GtkBuilder *builder; |
| GstElement *src; |
| enum |
| { NONE, INT, ENUM, BOOL } type; |
| const gchar *property_name; |
| gboolean readonly; |
| gboolean dynamic; |
| } Prop; |
| |
| typedef struct |
| { |
| GtkBuilder *builder; |
| GstElement *bin; |
| GstElement *src; |
| GstElement *identity; |
| GstElement *vid_capsfilter; |
| GstElement *vf_capsfilter; |
| } Main; |
| |
| Prop properties[] = { |
| {NULL, NULL, INT, "initial-bitrate", FALSE, FALSE}, |
| {NULL, NULL, INT, "slice-units", FALSE, FALSE}, |
| {NULL, NULL, ENUM, "slice-mode", FALSE, FALSE}, |
| {NULL, NULL, INT, "iframe-period", FALSE, FALSE}, |
| {NULL, NULL, ENUM, "usage-type", FALSE, FALSE}, |
| {NULL, NULL, ENUM, "entropy", FALSE, FALSE}, |
| {NULL, NULL, BOOL, "enable-sei", FALSE, FALSE}, |
| {NULL, NULL, INT, "num-reorder-frames", FALSE, FALSE}, |
| {NULL, NULL, BOOL, "preview-flipped", FALSE, FALSE}, |
| {NULL, NULL, INT, "leaky-bucket-size", FALSE, FALSE}, |
| {NULL, NULL, INT, "num-clock-samples", FALSE, TRUE}, |
| {NULL, NULL, ENUM, "rate-control", FALSE, TRUE}, |
| {NULL, NULL, BOOL, "fixed-framerate", FALSE, TRUE}, |
| {NULL, NULL, INT, "max-mbps", TRUE, TRUE}, |
| {NULL, NULL, INT, "level-idc", FALSE, TRUE}, |
| {NULL, NULL, INT, "peak-bitrate", FALSE, TRUE}, |
| {NULL, NULL, INT, "average-bitrate", FALSE, TRUE}, |
| {NULL, NULL, INT, "min-iframe-qp", FALSE, TRUE}, |
| {NULL, NULL, INT, "max-iframe-qp", FALSE, TRUE}, |
| {NULL, NULL, INT, "min-pframe-qp", FALSE, TRUE}, |
| {NULL, NULL, INT, "max-pframe-qp", FALSE, TRUE}, |
| {NULL, NULL, INT, "min-bframe-qp", FALSE, TRUE}, |
| {NULL, NULL, INT, "max-bframe-qp", FALSE, TRUE}, |
| {NULL, NULL, INT, "ltr-buffer-size", FALSE, TRUE}, |
| {NULL, NULL, INT, "ltr-encoder-control", FALSE, TRUE}, |
| }; |
| |
| static void set_drop_probability (Main * self); |
| static void get_all_properties (void); |
| static void probe_all_properties (gboolean playing); |
| |
| /* Callbacks */ |
| void on_button_toggled (GtkToggleButton * button, gpointer user_data); |
| void on_get_button_clicked (GtkButton * button, gpointer user_data); |
| void on_set_button_clicked (GtkButton * button, gpointer user_data); |
| void on_button_ready_clicked (GtkButton * button, gpointer user_data); |
| void on_button_null_clicked (GtkButton * button, gpointer user_data); |
| void on_button_playing_clicked (GtkButton * button, gpointer user_data); |
| void on_iframe_button_clicked (GtkButton * button, gpointer user_data); |
| void on_renegotiate_button_clicked (GtkButton * button, gpointer user_data); |
| void on_start_capture_button_clicked (GtkButton * button, gpointer user_data); |
| void on_stop_capture_button_clicked (GtkButton * button, gpointer user_data); |
| void on_window_destroyed (GtkWindow * window, gpointer user_data); |
| |
| static GstEvent * |
| new_upstream_force_key_unit (GstClockTime running_time, |
| gboolean all_headers, guint count) |
| { |
| GstEvent *force_key_unit_event; |
| GstStructure *s; |
| |
| s = gst_structure_new ("GstForceKeyUnit", |
| "running-time", GST_TYPE_CLOCK_TIME, running_time, |
| "all-headers", G_TYPE_BOOLEAN, all_headers, |
| "count", G_TYPE_UINT, count, NULL); |
| force_key_unit_event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s); |
| |
| return force_key_unit_event; |
| } |
| |
| void |
| on_get_button_clicked (GtkButton * button, gpointer user_data) |
| { |
| Prop *property = user_data; |
| |
| switch (property->type) { |
| case INT: |
| { |
| gchar *val; |
| gint val_int; |
| g_object_get (property->src, property->property_name, &val_int, NULL); |
| val = g_strdup_printf ("%d", val_int); |
| gtk_entry_set_text (GET_WIDGET (property, GTK_ENTRY, "value"), val); |
| g_free (val); |
| } |
| break; |
| case ENUM: |
| { |
| GParamSpec *param; |
| gint val; |
| |
| g_object_get (property->src, property->property_name, &val, NULL); |
| param = g_object_class_find_property (G_OBJECT_GET_CLASS (property->src), |
| property->property_name); |
| if (G_IS_PARAM_SPEC_ENUM (param)) { |
| GEnumValue *values; |
| guint i = 0; |
| |
| values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values; |
| |
| while (values[i].value_name) { |
| if (values[i].value == val) { |
| gtk_combo_box_set_active (GET_WIDGET (property, |
| (GtkComboBox *), "value"), i); |
| break; |
| } |
| i++; |
| } |
| } |
| } |
| break; |
| case BOOL: |
| { |
| gboolean val; |
| |
| g_object_get (property->src, property->property_name, &val, NULL); |
| gtk_toggle_button_set_active (GET_WIDGET (property, |
| (GtkToggleButton *), "value"), val); |
| } |
| break; |
| case NONE: |
| default: |
| break; |
| } |
| } |
| |
| void |
| on_set_button_clicked (GtkButton * button, gpointer user_data) |
| { |
| Prop *property = user_data; |
| |
| switch (property->type) { |
| case INT: |
| { |
| int val_int; |
| const gchar *val; |
| |
| val = gtk_entry_get_text (GET_WIDGET (property, GTK_ENTRY, "value")); |
| val_int = (int) g_ascii_strtoll (val, NULL, 0); |
| g_object_set (property->src, property->property_name, val_int, NULL); |
| } |
| break; |
| case ENUM: |
| { |
| GParamSpec *param; |
| |
| param = g_object_class_find_property (G_OBJECT_GET_CLASS (property->src), |
| property->property_name); |
| if (G_IS_PARAM_SPEC_ENUM (param)) { |
| GEnumValue *values; |
| guint val = 0; |
| |
| values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values; |
| |
| val = gtk_combo_box_get_active (GET_WIDGET (property, |
| (GtkComboBox *), "value")); |
| g_object_set (property->src, property->property_name, |
| values[val].value, NULL); |
| } |
| } |
| break; |
| case BOOL: |
| { |
| gboolean val; |
| |
| val = gtk_toggle_button_get_active (GET_WIDGET (property, |
| (GtkToggleButton *), "value")); |
| g_object_set (property->src, property->property_name, val, NULL); |
| } |
| break; |
| case NONE: |
| default: |
| break; |
| } |
| get_all_properties (); |
| } |
| |
| void |
| on_button_toggled (GtkToggleButton * button, gpointer user_data) |
| { |
| if (gtk_toggle_button_get_active (button)) |
| gtk_button_set_label (GTK_BUTTON (button), " Enabled "); |
| else |
| gtk_button_set_label (GTK_BUTTON (button), " Disabled "); |
| } |
| |
| static gboolean |
| set_caps (Main * self, gboolean send_event) |
| { |
| const gchar *h264_filter; |
| const gchar *raw_filter; |
| GstCaps *h264_caps = NULL; |
| GstCaps *raw_caps = NULL; |
| gboolean ret = TRUE; |
| |
| h264_filter = gtk_entry_get_text (GET_WIDGET (self, GTK_ENTRY, "h264_caps")); |
| raw_filter = |
| gtk_entry_get_text (GET_WIDGET (self, GTK_ENTRY, "preview_caps")); |
| if (h264_filter) |
| h264_caps = gst_caps_from_string (h264_filter); |
| if (raw_filter) |
| raw_caps = gst_caps_from_string (raw_filter); |
| |
| g_debug ("H264 caps : %s", gst_caps_to_string (h264_caps)); |
| g_debug ("Preview caps : %s", gst_caps_to_string (raw_caps)); |
| if (!h264_caps || !raw_caps) { |
| g_debug ("Invalid caps"); |
| ret = FALSE; |
| goto end; |
| } |
| |
| g_object_set (self->vid_capsfilter, "caps", h264_caps, NULL); |
| g_object_set (self->vf_capsfilter, "caps", raw_caps, NULL); |
| |
| if (send_event) { |
| gst_element_send_event (GST_ELEMENT (self->src), |
| gst_event_new_reconfigure ()); |
| } |
| |
| end: |
| if (h264_caps) |
| gst_caps_unref (h264_caps); |
| if (raw_caps) |
| gst_caps_unref (raw_caps); |
| |
| return ret; |
| } |
| |
| void |
| on_button_ready_clicked (GtkButton * button, gpointer user_data) |
| { |
| Main *self = user_data; |
| |
| set_caps (self, FALSE); |
| gst_element_set_state (self->bin, GST_STATE_READY); |
| probe_all_properties (FALSE); |
| get_all_properties (); |
| } |
| |
| void |
| on_button_null_clicked (GtkButton * button, gpointer user_data) |
| { |
| Main *self = user_data; |
| |
| gst_element_set_state (self->bin, GST_STATE_NULL); |
| probe_all_properties (FALSE); |
| get_all_properties (); |
| } |
| |
| void |
| on_button_playing_clicked (GtkButton * button, gpointer user_data) |
| { |
| Main *self = user_data; |
| |
| if (gst_element_set_state (self->bin, GST_STATE_PLAYING) == |
| GST_STATE_CHANGE_FAILURE) { |
| g_debug ("Unable to go to state PLAYING"); |
| } |
| set_caps (self, FALSE); |
| probe_all_properties (TRUE); |
| get_all_properties (); |
| |
| set_drop_probability (self); |
| } |
| |
| void |
| on_iframe_button_clicked (GtkButton * button, gpointer user_data) |
| { |
| Main *self = user_data; |
| GstEvent *event; |
| gboolean pps_sps; |
| |
| set_drop_probability (self); |
| pps_sps = gtk_toggle_button_get_active (GET_WIDGET (self, (GtkToggleButton *), |
| "pps_sps")); |
| |
| event = new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, pps_sps, 0); |
| gst_element_send_event (GST_ELEMENT (self->src), event); |
| } |
| |
| void |
| on_renegotiate_button_clicked (GtkButton * button, gpointer user_data) |
| { |
| Main *self = user_data; |
| |
| set_caps (self, TRUE); |
| probe_all_properties (GST_STATE (self->bin) >= GST_STATE_PAUSED); |
| get_all_properties (); |
| } |
| |
| void |
| on_start_capture_button_clicked (GtkButton * button, gpointer user_data) |
| { |
| Main *self = user_data; |
| |
| set_caps (self, FALSE); |
| g_signal_emit_by_name (G_OBJECT (self->src), "start-capture", NULL); |
| probe_all_properties (GST_STATE (self->bin) >= GST_STATE_PAUSED); |
| get_all_properties (); |
| } |
| |
| void |
| on_stop_capture_button_clicked (GtkButton * button, gpointer user_data) |
| { |
| Main *self = user_data; |
| |
| set_caps (self, FALSE); |
| g_signal_emit_by_name (G_OBJECT (self->src), "stop-capture", NULL); |
| probe_all_properties (GST_STATE (self->bin) >= GST_STATE_PAUSED); |
| get_all_properties (); |
| } |
| |
| void |
| on_window_destroyed (GtkWindow * window, gpointer user_data) |
| { |
| gtk_main_quit (); |
| } |
| |
| static gboolean |
| _bus_callback (GstBus * bus, GstMessage * message, gpointer user_data) |
| { |
| const GstStructure *s = gst_message_get_structure (message); |
| GstObject *source = NULL; |
| |
| if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT && |
| gst_structure_has_name (s, "prepare-window-handle")) { |
| source = GST_MESSAGE_SRC (message); |
| if (!g_strcmp0 (gst_object_get_name (source), "h264_sink")) |
| gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (source), |
| h264_xid); |
| else |
| gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (source), |
| preview_xid); |
| } |
| |
| return TRUE; |
| } |
| |
| static void |
| set_drop_probability (Main * self) |
| { |
| const gchar *drop; |
| gdouble drop_probability = 0.0; |
| |
| drop = gtk_entry_get_text (GET_WIDGET (self, GTK_ENTRY, "drop")); |
| drop_probability = g_ascii_strtod (drop, NULL); |
| g_debug ("Setting drop probability to : %f", drop_probability); |
| g_object_set (self->identity, "drop-probability", drop_probability, NULL); |
| } |
| |
| static void |
| get_all_properties (void) |
| { |
| int i; |
| |
| for (i = 0; i < G_N_ELEMENTS (properties); i++) |
| on_get_button_clicked (NULL, &properties[i]); |
| |
| } |
| |
| static void |
| probe_all_properties (gboolean playing) |
| { |
| int i; |
| |
| for (i = 0; i < G_N_ELEMENTS (properties); i++) { |
| gboolean return_value, changeable, default_bool; |
| guint mask, minimum, maximum, default_int; |
| GParamSpec *param; |
| |
| /* When playing, ignore static controls */ |
| if (playing && !properties[i].dynamic) |
| continue; |
| |
| switch (properties[i].type) { |
| case INT: |
| g_signal_emit_by_name (G_OBJECT (properties[i].src), "get-int-setting", |
| properties[i].property_name, &minimum, &default_int, &maximum, |
| &return_value, NULL); |
| if (return_value) { |
| gchar *min, *def, *max; |
| |
| min = g_strdup_printf ("%d", minimum); |
| def = g_strdup_printf ("%d", default_int); |
| max = g_strdup_printf ("%d", maximum); |
| gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "minimum"), min); |
| gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "default"), def); |
| gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "maximum"), max); |
| g_free (min); |
| g_free (def); |
| g_free (max); |
| } else { |
| gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "minimum"), ""); |
| gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "default"), ""); |
| gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "maximum"), ""); |
| } |
| break; |
| case ENUM: |
| g_signal_emit_by_name (G_OBJECT (properties[i].src), "get-enum-setting", |
| properties[i].property_name, &mask, &default_int, &return_value, |
| NULL); |
| param = |
| g_object_class_find_property (G_OBJECT_GET_CLASS (properties |
| [i].src), properties[i].property_name); |
| if (G_IS_PARAM_SPEC_ENUM (param)) { |
| GEnumValue *values; |
| guint j = 0; |
| |
| values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values; |
| |
| if (return_value) { |
| while (values[j].value_name) { |
| if (values[j].value == default_int) { |
| gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "default"), |
| values[j].value_name); |
| break; |
| } |
| j++; |
| } |
| } else { |
| gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "default"), ""); |
| } |
| |
| j = 0; |
| while (values[j].value_name) { |
| #if !GTK_CHECK_VERSION (2, 24, 0) |
| gtk_combo_box_remove_text (GET_PROP_WIDGET ((GtkComboBox *), |
| "value"), 0); |
| #else |
| gtk_combo_box_text_remove (GET_PROP_WIDGET ((GtkComboBoxText *), |
| "value"), 0); |
| #endif |
| j++; |
| } |
| |
| j = 0; |
| while (values[j].value_name) { |
| gchar *val; |
| if (return_value && (mask & (1 << values[j].value)) != 0) |
| val = g_strdup_printf ("**%s**", values[j].value_name); |
| else |
| val = g_strdup (values[j].value_name); |
| |
| #if !GTK_CHECK_VERSION (2, 24, 0) |
| gtk_combo_box_append_text (GET_PROP_WIDGET ((GtkComboBox *), |
| "value"), val); |
| #else |
| gtk_combo_box_text_append_text (GET_PROP_WIDGET ((GtkComboBoxText |
| *), "value"), val); |
| #endif |
| g_free (val); |
| j++; |
| } |
| } |
| break; |
| case BOOL: |
| g_signal_emit_by_name (G_OBJECT (properties[i].src), |
| "get-boolean-setting", properties[i].property_name, |
| &changeable, &default_bool, &return_value, NULL); |
| if (return_value) { |
| gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "value"), |
| changeable); |
| gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "get"), |
| changeable); |
| gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "set"), |
| changeable); |
| gtk_toggle_button_set_active (GET_PROP_WIDGET ((GtkToggleButton *), |
| "default"), default_bool); |
| } |
| break; |
| case NONE: |
| default: |
| break; |
| } |
| } |
| } |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| Main self = { NULL, NULL, NULL, NULL }; |
| GstBus *bus = NULL; |
| GtkWidget *window, *static_vbox, *dynamic_vbox, *da; |
| gchar *drop; |
| gdouble drop_probability; |
| GdkWindow *gdk_win = NULL; |
| const char *device = "/dev/video0"; |
| GError *error = NULL; |
| int i; |
| |
| gtk_init (&argc, &argv); |
| gst_init (&argc, &argv); |
| |
| if (argc > 1) |
| device = argv[1]; |
| else |
| g_print ("Usage : %s [device]\nUsing default device : %s\n", |
| argv[0], device); |
| |
| |
| self.bin = gst_parse_launch ("uvch264src name=src src.vidsrc ! queue ! " |
| "capsfilter name=vid_cf ! identity name=identity ! decodebin ! " |
| "xvimagesink name=h264_sink async=false " |
| "src.vfsrc ! queue ! capsfilter name=vf_cf ! " |
| "xvimagesink name=preview_sink async=false", NULL); |
| |
| if (!self.bin) |
| return -1; |
| |
| /* Listen to the bus for messages */ |
| bus = gst_element_get_bus (self.bin); |
| gst_bus_add_watch (bus, _bus_callback, self.bin); |
| gst_object_unref (bus); |
| |
| self.src = gst_bin_get_by_name (GST_BIN (self.bin), "src"); |
| self.identity = gst_bin_get_by_name (GST_BIN (self.bin), "identity"); |
| self.vid_capsfilter = gst_bin_get_by_name (GST_BIN (self.bin), "vid_cf"); |
| self.vf_capsfilter = gst_bin_get_by_name (GST_BIN (self.bin), "vf_cf"); |
| |
| self.builder = gtk_builder_new (); |
| gtk_builder_add_from_file (self.builder, WINDOW_GLADE, &error); |
| if (error) { |
| g_debug ("Unable to load glade file : %s", error->message); |
| goto end; |
| } |
| gtk_builder_connect_signals (self.builder, &self); |
| |
| g_object_get (self.identity, "drop-probability", &drop_probability, NULL); |
| drop = g_strdup_printf ("%f", drop_probability); |
| gtk_entry_set_text (GET_WIDGET (&self, GTK_ENTRY, "drop"), drop); |
| g_free (drop); |
| window = GET_WIDGET (&self, GTK_WIDGET, "window"); |
| static_vbox = GET_WIDGET (&self, GTK_WIDGET, "static"); |
| dynamic_vbox = GET_WIDGET (&self, GTK_WIDGET, "dynamic"); |
| da = GET_WIDGET (&self, GTK_WIDGET, "h264"); |
| gtk_widget_realize (da); |
| gdk_win = gtk_widget_get_window (da); |
| h264_xid = GDK_WINDOW_XID (gdk_win); |
| da = GET_WIDGET (&self, GTK_WIDGET, "preview"); |
| gtk_widget_realize (da); |
| gdk_win = gtk_widget_get_window (da); |
| preview_xid = GDK_WINDOW_XID (gdk_win); |
| |
| set_caps (&self, FALSE); |
| |
| g_object_set (self.src, "device", device, NULL); |
| if (gst_element_set_state (self.bin, GST_STATE_READY) == |
| GST_STATE_CHANGE_FAILURE) { |
| g_debug ("Unable to go to state READY"); |
| goto end; |
| } |
| |
| for (i = 0; i < G_N_ELEMENTS (properties); i++) { |
| switch (properties[i].type) { |
| case INT: |
| properties[i].src = self.src; |
| properties[i].builder = gtk_builder_new (); |
| gtk_builder_add_from_file (properties[i].builder, INT_PROPERTY_GLADE, |
| NULL); |
| gtk_builder_connect_signals (properties[i].builder, &properties[i]); |
| gtk_box_pack_start (PROPERTY_TO_VBOX, |
| GET_PROP_WIDGET (GTK_WIDGET, "int-property"), TRUE, TRUE, 2); |
| gtk_label_set_label (GET_PROP_WIDGET (GTK_LABEL, "label"), |
| properties[i].property_name); |
| if (properties[i].readonly) |
| gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "set"), FALSE); |
| break; |
| case ENUM: |
| properties[i].src = self.src; |
| properties[i].builder = gtk_builder_new (); |
| #if !GTK_CHECK_VERSION (2, 24, 0) |
| gtk_builder_add_from_file (properties[i].builder, |
| "enum_property_gtk2.glade", NULL); |
| #else |
| gtk_builder_add_from_file (properties[i].builder, ENUM_PROPERTY_GLADE, |
| NULL); |
| #endif |
| gtk_builder_connect_signals (properties[i].builder, &properties[i]); |
| gtk_box_pack_start (PROPERTY_TO_VBOX, |
| GET_PROP_WIDGET (GTK_WIDGET, "enum-property"), TRUE, TRUE, 2); |
| gtk_label_set_label (GET_PROP_WIDGET (GTK_LABEL, "label"), |
| properties[i].property_name); |
| #if !GTK_CHECK_VERSION (2, 24, 0) |
| { |
| GtkComboBox *combo_box; |
| GtkCellRenderer *cell; |
| GtkListStore *store; |
| |
| combo_box = GET_PROP_WIDGET ((GtkComboBox *), "value"); |
| store = gtk_list_store_new (1, G_TYPE_STRING); |
| gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (store)); |
| g_object_unref (store); |
| |
| cell = gtk_cell_renderer_text_new (); |
| gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE); |
| gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell, |
| "text", 0, NULL); |
| } |
| #endif |
| if (properties[i].readonly) |
| gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "set"), FALSE); |
| break; |
| case BOOL: |
| properties[i].src = self.src; |
| properties[i].builder = gtk_builder_new (); |
| gtk_builder_add_from_file (properties[i].builder, BOOL_PROPERTY_GLADE, |
| NULL); |
| gtk_builder_connect_signals (properties[i].builder, &properties[i]); |
| gtk_box_pack_start (PROPERTY_TO_VBOX, |
| GET_PROP_WIDGET (GTK_WIDGET, "boolean-property"), TRUE, TRUE, 2); |
| gtk_label_set_label (GET_PROP_WIDGET (GTK_LABEL, "label"), |
| properties[i].property_name); |
| if (properties[i].readonly) |
| gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "set"), FALSE); |
| break; |
| case NONE: |
| default: |
| break; |
| } |
| } |
| probe_all_properties (FALSE); |
| get_all_properties (); |
| |
| gtk_widget_show (window); |
| gtk_main (); |
| |
| end: |
| g_object_unref (G_OBJECT (self.builder)); |
| for (i = 0; i < G_N_ELEMENTS (properties); i++) { |
| if (properties[i].builder) |
| g_object_unref (G_OBJECT (properties[i].builder)); |
| } |
| gst_element_set_state (self.bin, GST_STATE_NULL); |
| gst_object_unref (self.src); |
| gst_object_unref (self.identity); |
| gst_object_unref (self.vid_capsfilter); |
| gst_object_unref (self.vf_capsfilter); |
| gst_object_unref (self.bin); |
| |
| return 0; |
| } |