675e5e23cae1ac2f3fadd32b84b1082d61410f90
[platform/upstream/gstreamer.git] / examples / directfb / gstdfb.c
1 /*
2    (c) Copyright 2000-2002  convergence integrated media GmbH.
3    All rights reserved.
4
5    Written by Denis Oliver Kropp <dok@directfb.org>,
6               Andreas Hundt <andi@fischlustig.de>,
7               Sven Neumann <neo@directfb.org> and
8               Julien Moutte <julien@moutte.net>.
9
10    This file is subject to the terms and conditions of the MIT License:
11
12    Permission is hereby granted, free of charge, to any person
13    obtaining a copy of this software and associated documentation
14    files (the "Software"), to deal in the Software without restriction,
15    including without limitation the rights to use, copy, modify, merge,
16    publish, distribute, sublicense, and/or sell copies of the Software,
17    and to permit persons to whom the Software is furnished to do so,
18    subject to the following conditions:
19
20    The above copyright notice and this permission notice shall be
21    included in all copies or substantial portions of the Software.
22
23    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <math.h>
36 #include <time.h>
37
38 #include <directfb.h>
39 #include <gst/gst.h>
40 #include <string.h>
41
42 /* macro for a safe call to DirectFB functions */
43 #define DFBCHECK(x...) \
44      {                                                                \
45           err = x;                                                    \
46           if (err != DFB_OK) {                                        \
47                fprintf( stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \
48                DirectFBErrorFatal( #x, err );                         \
49           }                                                           \
50      }
51
52 typedef struct
53 {
54   const gchar *padname;
55   GstPad *target;
56   GstElement *bin;
57 } dyn_link;
58
59 static inline long
60 myclock ()
61 {
62   struct timeval tv;
63
64   gettimeofday (&tv, NULL);
65   return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
66 }
67
68 static void
69 dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
70 {
71   dyn_link *connect = (dyn_link *) data;
72
73   if (connect->padname == NULL ||
74       !strcmp (gst_pad_get_name (newpad), connect->padname)) {
75     gst_pad_link (newpad, connect->target);
76   }
77 }
78
79 static void
80 size_changed (GObject * obj, GParamSpec * pspec, IDirectFBWindow * window)
81 {
82   GstPad *pad = GST_PAD (obj);
83   GstStructure *s;
84   GstCaps *caps;
85
86   if (!(caps = gst_pad_get_negotiated_caps (pad)))
87     return;
88
89   s = gst_caps_get_structure (caps, 0);
90   if (s) {
91     gint width, height;
92
93     if (!(gst_structure_get_int (s, "width", &width) &&
94             gst_structure_get_int (s, "height", &height)))
95       return;
96
97     window->Resize (window, width, height);
98   }
99 }
100
101 static void
102 setup_dynamic_link (GstElement * element, const gchar * padname,
103     GstPad * target, GstElement * bin)
104 {
105   dyn_link *connect;
106
107   connect = g_new0 (dyn_link, 1);
108   connect->padname = g_strdup (padname);
109   connect->target = target;
110   connect->bin = bin;
111
112   g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link),
113       connect);
114 }
115
116 int
117 main (int argc, char *argv[])
118 {
119   IDirectFB *dfb;
120   IDirectFBDisplayLayer *layer;
121
122   IDirectFBImageProvider *provider;
123   IDirectFBVideoProvider *video_provider;
124
125   IDirectFBSurface *bgsurface;
126
127   IDirectFBWindow *window1;
128   IDirectFBWindow *window2;
129   IDirectFBWindow *window3;
130   IDirectFBSurface *window_surface1;
131   IDirectFBSurface *window_surface2;
132   IDirectFBSurface *window_surface3;
133
134   GstElement *pipeline;
135
136   IDirectFBEventBuffer *buffer;
137
138   IDirectFBFont *font;
139
140   DFBDisplayLayerConfig layer_config;
141   DFBGraphicsDeviceDescription gdesc;
142   DFBWindowID id1;
143   DFBWindowID id2;
144   DFBWindowID id3;
145
146   int fontheight;
147   int err;
148   int quit = 0;
149
150
151   DFBCHECK (DirectFBInit (&argc, &argv));
152   gst_init (&argc, &argv);
153   DFBCHECK (DirectFBCreate (&dfb));
154
155   dfb->GetDeviceDescription (dfb, &gdesc);
156
157   DFBCHECK (dfb->GetDisplayLayer (dfb, DLID_PRIMARY, &layer));
158
159   layer->SetCooperativeLevel (layer, DLSCL_ADMINISTRATIVE);
160
161   if (!((gdesc.blitting_flags & DSBLIT_BLEND_ALPHACHANNEL) &&
162           (gdesc.blitting_flags & DSBLIT_BLEND_COLORALPHA))) {
163     layer_config.flags = DLCONF_BUFFERMODE;
164     layer_config.buffermode = DLBM_BACKSYSTEM;
165
166     layer->SetConfiguration (layer, &layer_config);
167   }
168
169   layer->GetConfiguration (layer, &layer_config);
170   layer->EnableCursor (layer, 1);
171
172   {
173     DFBFontDescription desc;
174
175     desc.flags = DFDESC_HEIGHT;
176     desc.height = layer_config.width / 50;
177
178     DFBCHECK (dfb->CreateFont (dfb, "decker.ttf", &desc, &font));
179     font->GetHeight (font, &fontheight);
180   }
181
182   if (argc < 2 ||
183       dfb->CreateVideoProvider (dfb, argv[1], &video_provider) != DFB_OK) {
184     video_provider = NULL;
185   }
186
187   {
188     DFBSurfaceDescription desc;
189
190     desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT;
191     desc.width = layer_config.width;
192     desc.height = layer_config.height;
193
194     DFBCHECK (dfb->CreateSurface (dfb, &desc, &bgsurface));
195
196     DFBCHECK (bgsurface->SetFont (bgsurface, font));
197
198     bgsurface->SetColor (bgsurface, 0xCF, 0xCF, 0xFF, 0xFF);
199     bgsurface->DrawString (bgsurface,
200         "Move the mouse over a window to activate it.",
201         -1, 0, 0, DSTF_LEFT | DSTF_TOP);
202
203     bgsurface->SetColor (bgsurface, 0xCF, 0xDF, 0xCF, 0xFF);
204     bgsurface->DrawString (bgsurface,
205         "Press left mouse button and drag to move the window.",
206         -1, 0, fontheight, DSTF_LEFT | DSTF_TOP);
207
208     bgsurface->SetColor (bgsurface, 0xCF, 0xEF, 0x9F, 0xFF);
209     bgsurface->DrawString (bgsurface,
210         "Press middle mouse button to raise/lower the window.",
211         -1, 0, fontheight * 2, DSTF_LEFT | DSTF_TOP);
212
213     bgsurface->SetColor (bgsurface, 0xCF, 0xFF, 0x6F, 0xFF);
214     bgsurface->DrawString (bgsurface,
215         "Press right mouse button when you are done.", -1,
216         0, fontheight * 3, DSTF_LEFT | DSTF_TOP);
217
218     layer->SetBackgroundImage (layer, bgsurface);
219     layer->SetBackgroundMode (layer, DLBM_IMAGE);
220   }
221
222   {
223     DFBSurfaceDescription sdsc;
224     DFBWindowDescription desc;
225
226     desc.flags = (DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT);
227
228     if (!video_provider) {
229       desc.caps = DWCAPS_ALPHACHANNEL;
230       desc.flags |= DWDESC_CAPS;
231
232       sdsc.width = 300;
233       sdsc.height = 200;
234     } else {
235       video_provider->GetSurfaceDescription (video_provider, &sdsc);
236
237       if (sdsc.flags & DSDESC_CAPS) {
238         desc.flags |= DWDESC_SURFACE_CAPS;
239         desc.surface_caps = sdsc.caps;
240       }
241     }
242
243     desc.posx = 20;
244     desc.posy = 120;
245     desc.width = sdsc.width;
246     desc.height = sdsc.height;
247
248     DFBCHECK (layer->CreateWindow (layer, &desc, &window2));
249     window2->GetSurface (window2, &window_surface2);
250
251     window2->SetOpacity (window2, 0xFF);
252
253     window2->GetID (window2, &id2);
254
255     window2->CreateEventBuffer (window2, &buffer);
256
257     if (video_provider) {
258       video_provider->PlayTo (video_provider, window_surface2,
259           NULL, NULL, NULL);
260     } else {
261       window_surface2->SetColor (window_surface2, 0x00, 0x30, 0x10, 0xc0);
262       window_surface2->DrawRectangle (window_surface2,
263           0, 0, desc.width, desc.height);
264       window_surface2->SetColor (window_surface2, 0x80, 0xa0, 0x00, 0x90);
265       window_surface2->FillRectangle (window_surface2,
266           1, 1, desc.width - 2, desc.height - 2);
267     }
268
269     window_surface2->Flip (window_surface2, NULL, 0);
270   }
271
272   {
273     DFBWindowDescription desc;
274
275     desc.flags = (DWDESC_POSX | DWDESC_POSY |
276         DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS);
277     desc.posx = 200;
278     desc.posy = 200;
279     desc.width = 512;
280     desc.height = 145;
281     desc.caps = DWCAPS_ALPHACHANNEL;
282
283     DFBCHECK (layer->CreateWindow (layer, &desc, &window1));
284     window1->GetSurface (window1, &window_surface1);
285
286     DFBCHECK (dfb->CreateImageProvider (dfb, "dfblogo.png", &provider));
287     provider->RenderTo (provider, window_surface1, NULL);
288
289     window_surface1->SetColor (window_surface1, 0xFF, 0x20, 0x20, 0x90);
290     window_surface1->DrawRectangle (window_surface1,
291         0, 0, desc.width, desc.height);
292
293     window_surface1->Flip (window_surface1, NULL, 0);
294
295     provider->Release (provider);
296
297     window1->AttachEventBuffer (window1, buffer);
298
299     window1->SetOpacity (window1, 0xFF);
300
301     window1->GetID (window1, &id1);
302   }
303
304   {
305     DFBWindowDescription desc;
306     GstElement *src, *decode;
307     GstElement *v_queue, *v_scale, *cs, *v_sink;
308     GstElement *a_queue, *conv, *a_sink;
309     GstPad *v_pad, *a_pad;
310
311     desc.flags = (DWDESC_POSX | DWDESC_POSY |
312         DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS);
313     desc.posx = 10;
314     desc.posy = 10;
315     desc.width = 100;
316     desc.height = 100;
317     desc.caps = DWCAPS_ALPHACHANNEL;
318
319     DFBCHECK (layer->CreateWindow (layer, &desc, &window3));
320     window3->GetSurface (window3, &window_surface3);
321
322     window3->AttachEventBuffer (window3, buffer);
323
324     window3->SetOpacity (window3, 0xFF);
325
326     window3->GetID (window3, &id3);
327
328     pipeline = gst_pipeline_new ("pipeline");
329
330     src = gst_element_factory_make ("gnomevfssrc", "src");
331     g_object_set (src, "location", argv[1], NULL);
332     decode = gst_element_factory_make ("decodebin", "decode");
333
334     v_queue = gst_element_factory_make ("queue", "v_queue");
335     v_scale = gst_element_factory_make ("videoscale", "v_scale");
336     cs = gst_element_factory_make ("ffmpegcolorspace", "cs");
337     v_sink = gst_element_factory_make ("dfbvideosink", "v_sink");
338     g_object_set (v_sink, "surface", window_surface3, NULL);
339
340     a_queue = gst_element_factory_make ("queue", "a_queue");
341     conv = gst_element_factory_make ("audioconvert", "conv");
342     a_sink = gst_element_factory_make ("alsasink", "a_sink");
343
344     gst_bin_add_many (GST_BIN (pipeline), src, decode, NULL);
345     gst_bin_add_many (GST_BIN (pipeline), v_queue, v_scale, cs, v_sink, NULL);
346     gst_bin_add_many (GST_BIN (pipeline), a_queue, conv, a_sink, NULL);
347
348     gst_element_link (src, decode);
349     gst_element_link_many (v_queue, v_scale, cs, v_sink, NULL);
350     gst_element_link_many (a_queue, conv, a_sink, NULL);
351
352     v_pad = gst_element_get_static_pad (v_queue, "sink");
353     a_pad = gst_element_get_static_pad (a_queue, "sink");
354
355     setup_dynamic_link (decode, NULL, v_pad, NULL);
356     setup_dynamic_link (decode, NULL, a_pad, NULL);
357
358     /* We want to know when the size is defined */
359     g_signal_connect (v_pad, "notify::caps", G_CALLBACK (size_changed),
360         window3);
361
362     gst_object_unref (a_pad);
363     gst_object_unref (v_pad);
364
365     gst_element_set_state (pipeline, GST_STATE_PLAYING);
366   }
367
368   window1->RequestFocus (window1);
369   window1->RaiseToTop (window1);
370
371   while (!quit) {
372     static IDirectFBWindow *active = NULL;
373     static int grabbed = 0;
374     static int startx = 0;
375     static int starty = 0;
376     static int endx = 0;
377     static int endy = 0;
378     DFBWindowEvent evt;
379
380     buffer->WaitForEventWithTimeout (buffer, 0, 10);
381
382     while (buffer->GetEvent (buffer, DFB_EVENT (&evt)) == DFB_OK) {
383       IDirectFBWindow *window;
384
385       if (evt.window_id == id1)
386         window = window1;
387       else if (evt.window_id == id3)
388         window = window3;
389       else
390         window = window2;
391
392       if (evt.type == DWET_GOTFOCUS) {
393         active = window;
394       } else if (active) {
395         switch (evt.type) {
396
397           case DWET_BUTTONDOWN:
398             if (!grabbed && evt.button == DIBI_LEFT) {
399               grabbed = 1;
400               startx = evt.cx;
401               starty = evt.cy;
402               window->GrabPointer (window);
403             }
404             break;
405
406           case DWET_BUTTONUP:
407             switch (evt.button) {
408               case DIBI_LEFT:
409                 if (grabbed) {
410                   window->UngrabPointer (window);
411                   grabbed = 0;
412                 }
413                 break;
414               case DIBI_MIDDLE:
415                 active->RaiseToTop (active);
416                 break;
417               case DIBI_RIGHT:
418                 quit = DIKS_DOWN;
419                 break;
420               default:
421                 break;
422             }
423             break;
424
425           case DWET_KEYDOWN:
426             if (grabbed)
427               break;
428             switch (evt.key_id) {
429               case DIKI_RIGHT:
430                 active->Move (active, 1, 0);
431                 break;
432               case DIKI_LEFT:
433                 active->Move (active, -1, 0);
434                 break;
435               case DIKI_UP:
436                 active->Move (active, 0, -1);
437                 break;
438               case DIKI_DOWN:
439                 active->Move (active, 0, 1);
440                 break;
441               default:
442                 break;
443             }
444             break;
445
446           case DWET_LOSTFOCUS:
447             if (!grabbed && active == window)
448               active = NULL;
449             break;
450
451           default:
452             break;
453
454         }
455       }
456
457       switch (evt.type) {
458
459         case DWET_MOTION:
460           endx = evt.cx;
461           endy = evt.cy;
462           break;
463
464         case DWET_KEYDOWN:
465           switch (evt.key_symbol) {
466             case DIKS_ESCAPE:
467             case DIKS_SMALL_Q:
468             case DIKS_CAPITAL_Q:
469             case DIKS_BACK:
470             case DIKS_STOP:
471               quit = 1;
472               break;
473             default:
474               break;
475           }
476           break;
477
478         default:
479           break;
480       }
481     }
482
483     if (video_provider)
484       window_surface2->Flip (window_surface2, NULL, 0);
485
486     if (active) {
487       if (grabbed) {
488         active->Move (active, endx - startx, endy - starty);
489         startx = endx;
490         starty = endy;
491       }
492       active->SetOpacity (active, (sin (myclock () / 300.0) * 85) + 170);
493     }
494   }
495
496   if (video_provider)
497     video_provider->Release (video_provider);
498
499   gst_element_set_state (pipeline, GST_STATE_NULL);
500
501   buffer->Release (buffer);
502   font->Release (font);
503   window_surface2->Release (window_surface2);
504   window_surface1->Release (window_surface1);
505   window_surface3->Release (window_surface3);
506   window2->Release (window2);
507   window1->Release (window1);
508   window3->Release (window3);
509   layer->Release (layer);
510   bgsurface->Release (bgsurface);
511   dfb->Release (dfb);
512
513   return 42;
514 }