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
myclock(void)60 myclock (void)
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
dynamic_link(GstPadTemplate * templ,GstPad * newpad,gpointer data)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
size_changed(GObject * obj,GParamSpec * pspec,IDirectFBWindow * window)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_current_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       gst_caps_unref (caps);
96       return;
97     }
98 
99     window->Resize (window, width, height);
100   }
101   gst_caps_unref (caps);
102 }
103 
104 static void
setup_dynamic_link(GstElement * element,const gchar * padname,GstPad * target,GstElement * bin)105 setup_dynamic_link (GstElement * element, const gchar * padname,
106     GstPad * target, GstElement * bin)
107 {
108   dyn_link *connect;
109 
110   connect = g_new0 (dyn_link, 1);
111   connect->padname = g_strdup (padname);
112   connect->target = target;
113   connect->bin = bin;
114 
115   g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link),
116       connect);
117 }
118 
119 int
main(int argc,char * argv[])120 main (int argc, char *argv[])
121 {
122   IDirectFB *dfb;
123   IDirectFBDisplayLayer *layer;
124 
125   IDirectFBImageProvider *provider;
126   IDirectFBVideoProvider *video_provider;
127 
128   IDirectFBSurface *bgsurface;
129 
130   IDirectFBWindow *window1;
131   IDirectFBWindow *window2;
132   IDirectFBWindow *window3;
133   IDirectFBSurface *window_surface1;
134   IDirectFBSurface *window_surface2;
135   IDirectFBSurface *window_surface3;
136 
137   GstElement *pipeline;
138 
139   IDirectFBEventBuffer *buffer;
140 
141   IDirectFBFont *font;
142 
143   DFBDisplayLayerConfig layer_config;
144   DFBGraphicsDeviceDescription gdesc;
145   DFBWindowID id1;
146   DFBWindowID id2;
147   DFBWindowID id3;
148 
149   int fontheight;
150   int err;
151   int quit = 0;
152 
153 
154   DFBCHECK (DirectFBInit (&argc, &argv));
155   gst_init (&argc, &argv);
156   DFBCHECK (DirectFBCreate (&dfb));
157 
158   dfb->GetDeviceDescription (dfb, &gdesc);
159 
160   DFBCHECK (dfb->GetDisplayLayer (dfb, DLID_PRIMARY, &layer));
161 
162   layer->SetCooperativeLevel (layer, DLSCL_ADMINISTRATIVE);
163 
164   if (!((gdesc.blitting_flags & DSBLIT_BLEND_ALPHACHANNEL) &&
165           (gdesc.blitting_flags & DSBLIT_BLEND_COLORALPHA))) {
166     layer_config.flags = DLCONF_BUFFERMODE;
167     layer_config.buffermode = DLBM_BACKSYSTEM;
168 
169     layer->SetConfiguration (layer, &layer_config);
170   }
171 
172   layer->GetConfiguration (layer, &layer_config);
173   layer->EnableCursor (layer, 1);
174 
175   {
176     DFBFontDescription desc;
177 
178     desc.flags = DFDESC_HEIGHT;
179     desc.height = layer_config.width / 50;
180 
181     DFBCHECK (dfb->CreateFont (dfb, "decker.ttf", &desc, &font));
182     font->GetHeight (font, &fontheight);
183   }
184 
185   if (argc < 2 ||
186       dfb->CreateVideoProvider (dfb, argv[1], &video_provider) != DFB_OK) {
187     video_provider = NULL;
188   }
189 
190   {
191     DFBSurfaceDescription desc;
192 
193     desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT;
194     desc.width = layer_config.width;
195     desc.height = layer_config.height;
196 
197     DFBCHECK (dfb->CreateSurface (dfb, &desc, &bgsurface));
198 
199     DFBCHECK (bgsurface->SetFont (bgsurface, font));
200 
201     bgsurface->SetColor (bgsurface, 0xCF, 0xCF, 0xFF, 0xFF);
202     bgsurface->DrawString (bgsurface,
203         "Move the mouse over a window to activate it.",
204         -1, 0, 0, DSTF_LEFT | DSTF_TOP);
205 
206     bgsurface->SetColor (bgsurface, 0xCF, 0xDF, 0xCF, 0xFF);
207     bgsurface->DrawString (bgsurface,
208         "Press left mouse button and drag to move the window.",
209         -1, 0, fontheight, DSTF_LEFT | DSTF_TOP);
210 
211     bgsurface->SetColor (bgsurface, 0xCF, 0xEF, 0x9F, 0xFF);
212     bgsurface->DrawString (bgsurface,
213         "Press middle mouse button to raise/lower the window.",
214         -1, 0, fontheight * 2, DSTF_LEFT | DSTF_TOP);
215 
216     bgsurface->SetColor (bgsurface, 0xCF, 0xFF, 0x6F, 0xFF);
217     bgsurface->DrawString (bgsurface,
218         "Press right mouse button when you are done.", -1,
219         0, fontheight * 3, DSTF_LEFT | DSTF_TOP);
220 
221     layer->SetBackgroundImage (layer, bgsurface);
222     layer->SetBackgroundMode (layer, DLBM_IMAGE);
223   }
224 
225   {
226     DFBSurfaceDescription sdsc;
227     DFBWindowDescription desc;
228 
229     desc.flags = (DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT);
230 
231     if (!video_provider) {
232       desc.caps = DWCAPS_ALPHACHANNEL;
233       desc.flags |= DWDESC_CAPS;
234 
235       sdsc.width = 300;
236       sdsc.height = 200;
237     } else {
238       video_provider->GetSurfaceDescription (video_provider, &sdsc);
239 
240       if (sdsc.flags & DSDESC_CAPS) {
241         desc.flags |= DWDESC_SURFACE_CAPS;
242         desc.surface_caps = sdsc.caps;
243       }
244     }
245 
246     desc.posx = 20;
247     desc.posy = 120;
248     desc.width = sdsc.width;
249     desc.height = sdsc.height;
250 
251     DFBCHECK (layer->CreateWindow (layer, &desc, &window2));
252     window2->GetSurface (window2, &window_surface2);
253 
254     window2->SetOpacity (window2, 0xFF);
255 
256     window2->GetID (window2, &id2);
257 
258     window2->CreateEventBuffer (window2, &buffer);
259 
260     if (video_provider) {
261       video_provider->PlayTo (video_provider, window_surface2,
262           NULL, NULL, NULL);
263     } else {
264       window_surface2->SetColor (window_surface2, 0x00, 0x30, 0x10, 0xc0);
265       window_surface2->DrawRectangle (window_surface2,
266           0, 0, desc.width, desc.height);
267       window_surface2->SetColor (window_surface2, 0x80, 0xa0, 0x00, 0x90);
268       window_surface2->FillRectangle (window_surface2,
269           1, 1, desc.width - 2, desc.height - 2);
270     }
271 
272     window_surface2->Flip (window_surface2, NULL, 0);
273   }
274 
275   {
276     DFBWindowDescription desc;
277 
278     desc.flags = (DWDESC_POSX | DWDESC_POSY |
279         DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS);
280     desc.posx = 200;
281     desc.posy = 200;
282     desc.width = 512;
283     desc.height = 145;
284     desc.caps = DWCAPS_ALPHACHANNEL;
285 
286     DFBCHECK (layer->CreateWindow (layer, &desc, &window1));
287     window1->GetSurface (window1, &window_surface1);
288 
289     DFBCHECK (dfb->CreateImageProvider (dfb, "dfblogo.png", &provider));
290     provider->RenderTo (provider, window_surface1, NULL);
291 
292     window_surface1->SetColor (window_surface1, 0xFF, 0x20, 0x20, 0x90);
293     window_surface1->DrawRectangle (window_surface1,
294         0, 0, desc.width, desc.height);
295 
296     window_surface1->Flip (window_surface1, NULL, 0);
297 
298     provider->Release (provider);
299 
300     window1->AttachEventBuffer (window1, buffer);
301 
302     window1->SetOpacity (window1, 0xFF);
303 
304     window1->GetID (window1, &id1);
305   }
306 
307   {
308     DFBWindowDescription desc;
309     GstElement *src, *decode;
310     GstElement *v_queue, *v_scale, *cs, *v_sink;
311     GstElement *a_queue, *conv, *a_sink;
312     GstPad *v_pad, *a_pad;
313 
314     desc.flags = (DWDESC_POSX | DWDESC_POSY |
315         DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS);
316     desc.posx = 10;
317     desc.posy = 10;
318     desc.width = 100;
319     desc.height = 100;
320     desc.caps = DWCAPS_ALPHACHANNEL;
321 
322     DFBCHECK (layer->CreateWindow (layer, &desc, &window3));
323     window3->GetSurface (window3, &window_surface3);
324 
325     window3->AttachEventBuffer (window3, buffer);
326 
327     window3->SetOpacity (window3, 0xFF);
328 
329     window3->GetID (window3, &id3);
330 
331     pipeline = gst_pipeline_new ("pipeline");
332 
333     src = gst_element_factory_make ("gnomevfssrc", "src");
334     g_object_set (src, "location", argv[1], NULL);
335     decode = gst_element_factory_make ("decodebin", "decode");
336 
337     v_queue = gst_element_factory_make ("queue", "v_queue");
338     v_scale = gst_element_factory_make ("videoscale", "v_scale");
339     cs = gst_element_factory_make ("videoconvert", "cs");
340     v_sink = gst_element_factory_make ("dfbvideosink", "v_sink");
341     g_object_set (v_sink, "surface", window_surface3, NULL);
342 
343     a_queue = gst_element_factory_make ("queue", "a_queue");
344     conv = gst_element_factory_make ("audioconvert", "conv");
345     a_sink = gst_element_factory_make ("alsasink", "a_sink");
346 
347     gst_bin_add_many (GST_BIN (pipeline), src, decode, NULL);
348     gst_bin_add_many (GST_BIN (pipeline), v_queue, v_scale, cs, v_sink, NULL);
349     gst_bin_add_many (GST_BIN (pipeline), a_queue, conv, a_sink, NULL);
350 
351     gst_element_link (src, decode);
352     gst_element_link_many (v_queue, v_scale, cs, v_sink, NULL);
353     gst_element_link_many (a_queue, conv, a_sink, NULL);
354 
355     v_pad = gst_element_get_static_pad (v_queue, "sink");
356     a_pad = gst_element_get_static_pad (a_queue, "sink");
357 
358     setup_dynamic_link (decode, NULL, v_pad, NULL);
359     setup_dynamic_link (decode, NULL, a_pad, NULL);
360 
361     /* We want to know when the size is defined */
362     g_signal_connect (v_pad, "notify::caps", G_CALLBACK (size_changed),
363         window3);
364 
365     gst_object_unref (a_pad);
366     gst_object_unref (v_pad);
367 
368     gst_element_set_state (pipeline, GST_STATE_PLAYING);
369   }
370 
371   window1->RequestFocus (window1);
372   window1->RaiseToTop (window1);
373 
374   while (!quit) {
375     static IDirectFBWindow *active = NULL;
376     static int grabbed = 0;
377     static int startx = 0;
378     static int starty = 0;
379     static int endx = 0;
380     static int endy = 0;
381     DFBWindowEvent evt;
382 
383     buffer->WaitForEventWithTimeout (buffer, 0, 10);
384 
385     while (buffer->GetEvent (buffer, DFB_EVENT (&evt)) == DFB_OK) {
386       IDirectFBWindow *window;
387 
388       if (evt.window_id == id1)
389         window = window1;
390       else if (evt.window_id == id3)
391         window = window3;
392       else
393         window = window2;
394 
395       if (evt.type == DWET_GOTFOCUS) {
396         active = window;
397       } else if (active) {
398         switch (evt.type) {
399 
400           case DWET_BUTTONDOWN:
401             if (!grabbed && evt.button == DIBI_LEFT) {
402               grabbed = 1;
403               startx = evt.cx;
404               starty = evt.cy;
405               window->GrabPointer (window);
406             }
407             break;
408 
409           case DWET_BUTTONUP:
410             switch (evt.button) {
411               case DIBI_LEFT:
412                 if (grabbed) {
413                   window->UngrabPointer (window);
414                   grabbed = 0;
415                 }
416                 break;
417               case DIBI_MIDDLE:
418                 active->RaiseToTop (active);
419                 break;
420               case DIBI_RIGHT:
421                 quit = DIKS_DOWN;
422                 break;
423               default:
424                 break;
425             }
426             break;
427 
428           case DWET_KEYDOWN:
429             if (grabbed)
430               break;
431             switch (evt.key_id) {
432               case DIKI_RIGHT:
433                 active->Move (active, 1, 0);
434                 break;
435               case DIKI_LEFT:
436                 active->Move (active, -1, 0);
437                 break;
438               case DIKI_UP:
439                 active->Move (active, 0, -1);
440                 break;
441               case DIKI_DOWN:
442                 active->Move (active, 0, 1);
443                 break;
444               default:
445                 break;
446             }
447             break;
448 
449           case DWET_LOSTFOCUS:
450             if (!grabbed && active == window)
451               active = NULL;
452             break;
453 
454           default:
455             break;
456 
457         }
458       }
459 
460       switch (evt.type) {
461 
462         case DWET_MOTION:
463           endx = evt.cx;
464           endy = evt.cy;
465           break;
466 
467         case DWET_KEYDOWN:
468           switch (evt.key_symbol) {
469             case DIKS_ESCAPE:
470             case DIKS_SMALL_Q:
471             case DIKS_CAPITAL_Q:
472             case DIKS_BACK:
473             case DIKS_STOP:
474               quit = 1;
475               break;
476             default:
477               break;
478           }
479           break;
480 
481         default:
482           break;
483       }
484     }
485 
486     if (video_provider)
487       window_surface2->Flip (window_surface2, NULL, 0);
488 
489     if (active) {
490       if (grabbed) {
491         active->Move (active, endx - startx, endy - starty);
492         startx = endx;
493         starty = endy;
494       }
495       active->SetOpacity (active, (sin (myclock () / 300.0) * 85) + 170);
496     }
497   }
498 
499   if (video_provider)
500     video_provider->Release (video_provider);
501 
502   gst_element_set_state (pipeline, GST_STATE_NULL);
503 
504   buffer->Release (buffer);
505   font->Release (font);
506   window_surface2->Release (window_surface2);
507   window_surface1->Release (window_surface1);
508   window_surface3->Release (window_surface3);
509   window2->Release (window2);
510   window1->Release (window1);
511   window3->Release (window3);
512   layer->Release (layer);
513   bgsurface->Release (bgsurface);
514   dfb->Release (dfb);
515 
516   return 42;
517 }
518