1 /* GStreamer
2 * Copyright (C) <2008> Stefan Kost <ensonic@users.sf.net>
3 *
4 * test-colorkey: test manual colorkey handling
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 /* FIXME: gdk_cairo_create() is deprecated nowadays */
27 #define GDK_DISABLE_DEPRECATION_WARNINGS
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <glib.h>
33 #include <gdk/gdkx.h>
34 #include <gtk/gtk.h>
35
36 #include <gst/gst.h>
37 #include <gst/video/videooverlay.h>
38
39 static GtkWidget *video_window = NULL;
40 static GstElement *sink = NULL;
41 static gulong embed_xid = 0;
42 static GdkRGBA trans_color;
43 static gboolean trans_color_set = FALSE;
44
45 static void
redraw_overlay(GtkWidget * widget)46 redraw_overlay (GtkWidget * widget)
47 {
48 GtkAllocation allocation;
49 GdkWindow *window = gtk_widget_get_window (widget);
50 cairo_t *cr;
51
52 cr = gdk_cairo_create (window);
53 gtk_widget_get_allocation (widget, &allocation);
54
55 cairo_set_source_rgb (cr, 1, 1, 1);
56 cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
57 cairo_fill (cr);
58
59 if (trans_color_set) {
60 guint x, y;
61 guint h = allocation.height * 0.75;
62
63 gdk_cairo_set_source_rgba (cr, &trans_color);
64 cairo_rectangle (cr, 0, 0, allocation.width, h);
65 cairo_fill (cr);
66
67 for (y = h; y < allocation.height; y++) {
68 for (x = 0; x < allocation.width; x++) {
69 if (((x & 1) || (y & 1)) && (x & 1) != (y & 1)) {
70 cairo_move_to (cr, x, y);
71 cairo_paint (cr);
72 }
73 }
74 }
75 }
76 }
77
78 static gboolean
handle_resize_cb(GtkWidget * widget,GdkEventConfigure * event,gpointer data)79 handle_resize_cb (GtkWidget * widget, GdkEventConfigure * event, gpointer data)
80 {
81 redraw_overlay (widget);
82 return FALSE;
83 }
84
85 static gboolean
draw_cb(GtkWidget * widget,cairo_t * cr,gpointer data)86 draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data)
87 {
88 redraw_overlay (widget);
89 return FALSE;
90 }
91
92 static void
realize_cb(GtkWidget * widget,gpointer data)93 realize_cb (GtkWidget * widget, gpointer data)
94 {
95 GdkWindow *window = gtk_widget_get_window (widget);
96
97 /* This is here just for pedagogical purposes, GDK_WINDOW_XID will call it
98 * as well */
99 if (!gdk_window_ensure_native (window))
100 g_error ("Couldn't create native window needed for GstVideoOverlay!");
101
102 embed_xid = GDK_WINDOW_XID (window);
103 g_print ("Window realize: video window XID = %lu\n", embed_xid);
104 }
105
106 static void
msg_state_changed(GstBus * bus,GstMessage * message,GstPipeline * pipeline)107 msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
108 {
109 const GstStructure *s;
110
111 s = gst_message_get_structure (message);
112
113 /* We only care about state changed on the pipeline */
114 if (s && GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) {
115 GstState old, new, pending;
116 gint color;
117
118 gst_message_parse_state_changed (message, &old, &new, &pending);
119
120 /* When state of the pipeline changes to paused or playing we start updating scale */
121 switch (GST_STATE_TRANSITION (old, new)) {
122 case GST_STATE_CHANGE_READY_TO_PAUSED:{
123 g_object_get (G_OBJECT (sink), "colorkey", &color, NULL);
124 if (color != -1) {
125 trans_color.red = (color & 0xff0000) >> 8;
126 trans_color.green = (color & 0xff00);
127 trans_color.blue = (color & 0xff) << 8;
128 trans_color_set = TRUE;
129 } else {
130 trans_color_set = FALSE;
131 }
132 handle_resize_cb (video_window, NULL, NULL);
133 break;
134 }
135 default:
136 break;
137 }
138 }
139 }
140
141 static void
window_closed(GtkWidget * widget,GdkEvent * event,gpointer user_data)142 window_closed (GtkWidget * widget, GdkEvent * event, gpointer user_data)
143 {
144 GstElement *pipeline = user_data;
145
146 g_print ("stopping\n");
147 gtk_widget_hide (widget);
148 gst_element_set_state (pipeline, GST_STATE_NULL);
149 gtk_main_quit ();
150 }
151
152 static gboolean
start_pipeline(gpointer user_data)153 start_pipeline (gpointer user_data)
154 {
155 GstElement *pipeline = GST_ELEMENT (user_data);
156 GstStateChangeReturn sret;
157
158 sret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
159 if (sret == GST_STATE_CHANGE_FAILURE) {
160 gst_element_set_state (pipeline, GST_STATE_NULL);
161 gst_object_unref (pipeline);
162 gtk_main_quit ();
163 }
164 return FALSE;
165 }
166
167 int
main(int argc,char ** argv)168 main (int argc, char **argv)
169 {
170 GtkWidget *window;
171 GstElement *pipeline, *src;
172 GstBus *bus;
173 GstStateChangeReturn sret;
174 #if 0
175 GstPropertyProbe *probe;
176 GValueArray *arr;
177 #endif
178
179 gst_init (&argc, &argv);
180 gtk_init (&argc, &argv);
181
182 /* prepare the pipeline */
183
184 pipeline = gst_pipeline_new ("xvoverlay");
185 src = gst_element_factory_make ("videotestsrc", NULL);
186 sink = gst_element_factory_make ("xvimagesink", NULL);
187 gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
188 gst_element_link (src, sink);
189
190 #define COLOR_GRAY 0x7F7F7F
191
192 g_object_set (G_OBJECT (sink), "autopaint-colorkey", FALSE,
193 "force-aspect-ratio", TRUE, "draw-borders", FALSE,
194 "colorkey", COLOR_GRAY, NULL);
195
196 /* check xvimagesink capabilities */
197 sret = gst_element_set_state (pipeline, GST_STATE_READY);
198 if (sret == GST_STATE_CHANGE_FAILURE) {
199 g_printerr ("Can't set pipeline to READY\n");
200 gst_object_unref (pipeline);
201 return -1;
202 }
203 #if 0
204 probe = GST_PROPERTY_PROBE (sink);
205 if (!probe) {
206 g_printerr ("Can't probe sink\n");
207 gst_element_set_state (pipeline, GST_STATE_NULL);
208 gst_object_unref (pipeline);
209 return -1;
210 }
211 arr =
212 gst_property_probe_probe_and_get_values_name (probe,
213 "autopaint-colorkey");
214 if (!arr || !arr->n_values) {
215 g_printerr ("Can't disable autopaint-colorkey property\n");
216 gst_element_set_state (pipeline, GST_STATE_NULL);
217 gst_object_unref (pipeline);
218 return -1;
219 }
220 if (arr)
221 g_value_array_free (arr);
222 #endif
223
224 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
225 gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
226 g_signal_connect (bus, "message::state-changed",
227 G_CALLBACK (msg_state_changed), pipeline);
228 gst_object_unref (bus);
229
230 /* prepare the ui */
231
232 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
233 g_signal_connect (G_OBJECT (window), "delete-event",
234 G_CALLBACK (window_closed), (gpointer) pipeline);
235 gtk_window_set_default_size (GTK_WINDOW (window), 320, 240);
236
237 video_window = gtk_drawing_area_new ();
238 g_signal_connect (G_OBJECT (video_window), "configure-event",
239 G_CALLBACK (handle_resize_cb), NULL);
240 g_signal_connect (G_OBJECT (video_window), "draw",
241 G_CALLBACK (draw_cb), NULL);
242 g_signal_connect (video_window, "realize", G_CALLBACK (realize_cb), NULL);
243 gtk_container_add (GTK_CONTAINER (window), video_window);
244
245 /* show the gui and play */
246
247 gtk_widget_show_all (window);
248
249 /* realize window now so that the video window gets created and we can
250 * obtain its XID before the pipeline is started up and the videosink
251 * asks for the XID of the window to render onto */
252 gtk_widget_realize (window);
253
254 /* we should have the XID now */
255 g_assert (embed_xid != 0);
256
257 /* we know what the video sink is in this case (xvimagesink), so we can
258 * just set it directly here now (instead of waiting for a
259 * prepare-window-handle element message in a sync bus handler and setting
260 * it there) */
261 g_print ("setting XID %lu\n", embed_xid);
262 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (sink), embed_xid);
263
264 g_idle_add (start_pipeline, pipeline);
265 gtk_main ();
266
267 gst_object_unref (pipeline);
268
269 return 0;
270 }
271