| /* |
| (c) Copyright 2000-2002 convergence integrated media GmbH. |
| All rights reserved. |
| |
| Written by Denis Oliver Kropp <dok@directfb.org>, |
| Andreas Hundt <andi@fischlustig.de>, |
| Sven Neumann <neo@directfb.org> and |
| Julien Moutte <julien@moutte.net>. |
| |
| This file is subject to the terms and conditions of the MIT License: |
| |
| Permission is hereby granted, free of charge, to any person |
| obtaining a copy of this software and associated documentation |
| files (the "Software"), to deal in the Software without restriction, |
| including without limitation the rights to use, copy, modify, merge, |
| publish, distribute, sublicense, and/or sell copies of the Software, |
| and to permit persons to whom the Software is furnished to do so, |
| subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <math.h> |
| #include <time.h> |
| |
| #include <directfb.h> |
| #include <gst/gst.h> |
| #include <string.h> |
| |
| /* macro for a safe call to DirectFB functions */ |
| #define DFBCHECK(x...) \ |
| { \ |
| err = x; \ |
| if (err != DFB_OK) { \ |
| fprintf( stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \ |
| DirectFBErrorFatal( #x, err ); \ |
| } \ |
| } |
| |
| typedef struct |
| { |
| const gchar *padname; |
| GstPad *target; |
| GstElement *bin; |
| } dyn_link; |
| |
| static inline long |
| myclock (void) |
| { |
| struct timeval tv; |
| |
| gettimeofday (&tv, NULL); |
| return (tv.tv_sec * 1000 + tv.tv_usec / 1000); |
| } |
| |
| static void |
| dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data) |
| { |
| dyn_link *connect = (dyn_link *) data; |
| |
| if (connect->padname == NULL || |
| !strcmp (gst_pad_get_name (newpad), connect->padname)) { |
| gst_pad_link (newpad, connect->target); |
| } |
| } |
| |
| static void |
| size_changed (GObject * obj, GParamSpec * pspec, IDirectFBWindow * window) |
| { |
| GstPad *pad = GST_PAD (obj); |
| GstStructure *s; |
| GstCaps *caps; |
| |
| if (!(caps = gst_pad_get_current_caps (pad))) |
| return; |
| |
| s = gst_caps_get_structure (caps, 0); |
| if (s) { |
| gint width, height; |
| |
| if (!(gst_structure_get_int (s, "width", &width) && |
| gst_structure_get_int (s, "height", &height))) |
| return; |
| |
| window->Resize (window, width, height); |
| } |
| } |
| |
| static void |
| setup_dynamic_link (GstElement * element, const gchar * padname, |
| GstPad * target, GstElement * bin) |
| { |
| dyn_link *connect; |
| |
| connect = g_new0 (dyn_link, 1); |
| connect->padname = g_strdup (padname); |
| connect->target = target; |
| connect->bin = bin; |
| |
| g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link), |
| connect); |
| } |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| IDirectFB *dfb; |
| IDirectFBDisplayLayer *layer; |
| |
| IDirectFBImageProvider *provider; |
| IDirectFBVideoProvider *video_provider; |
| |
| IDirectFBSurface *bgsurface; |
| |
| IDirectFBWindow *window1; |
| IDirectFBWindow *window2; |
| IDirectFBWindow *window3; |
| IDirectFBSurface *window_surface1; |
| IDirectFBSurface *window_surface2; |
| IDirectFBSurface *window_surface3; |
| |
| GstElement *pipeline; |
| |
| IDirectFBEventBuffer *buffer; |
| |
| IDirectFBFont *font; |
| |
| DFBDisplayLayerConfig layer_config; |
| DFBGraphicsDeviceDescription gdesc; |
| DFBWindowID id1; |
| DFBWindowID id2; |
| DFBWindowID id3; |
| |
| int fontheight; |
| int err; |
| int quit = 0; |
| |
| |
| DFBCHECK (DirectFBInit (&argc, &argv)); |
| gst_init (&argc, &argv); |
| DFBCHECK (DirectFBCreate (&dfb)); |
| |
| dfb->GetDeviceDescription (dfb, &gdesc); |
| |
| DFBCHECK (dfb->GetDisplayLayer (dfb, DLID_PRIMARY, &layer)); |
| |
| layer->SetCooperativeLevel (layer, DLSCL_ADMINISTRATIVE); |
| |
| if (!((gdesc.blitting_flags & DSBLIT_BLEND_ALPHACHANNEL) && |
| (gdesc.blitting_flags & DSBLIT_BLEND_COLORALPHA))) { |
| layer_config.flags = DLCONF_BUFFERMODE; |
| layer_config.buffermode = DLBM_BACKSYSTEM; |
| |
| layer->SetConfiguration (layer, &layer_config); |
| } |
| |
| layer->GetConfiguration (layer, &layer_config); |
| layer->EnableCursor (layer, 1); |
| |
| { |
| DFBFontDescription desc; |
| |
| desc.flags = DFDESC_HEIGHT; |
| desc.height = layer_config.width / 50; |
| |
| DFBCHECK (dfb->CreateFont (dfb, "decker.ttf", &desc, &font)); |
| font->GetHeight (font, &fontheight); |
| } |
| |
| if (argc < 2 || |
| dfb->CreateVideoProvider (dfb, argv[1], &video_provider) != DFB_OK) { |
| video_provider = NULL; |
| } |
| |
| { |
| DFBSurfaceDescription desc; |
| |
| desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT; |
| desc.width = layer_config.width; |
| desc.height = layer_config.height; |
| |
| DFBCHECK (dfb->CreateSurface (dfb, &desc, &bgsurface)); |
| |
| DFBCHECK (bgsurface->SetFont (bgsurface, font)); |
| |
| bgsurface->SetColor (bgsurface, 0xCF, 0xCF, 0xFF, 0xFF); |
| bgsurface->DrawString (bgsurface, |
| "Move the mouse over a window to activate it.", |
| -1, 0, 0, DSTF_LEFT | DSTF_TOP); |
| |
| bgsurface->SetColor (bgsurface, 0xCF, 0xDF, 0xCF, 0xFF); |
| bgsurface->DrawString (bgsurface, |
| "Press left mouse button and drag to move the window.", |
| -1, 0, fontheight, DSTF_LEFT | DSTF_TOP); |
| |
| bgsurface->SetColor (bgsurface, 0xCF, 0xEF, 0x9F, 0xFF); |
| bgsurface->DrawString (bgsurface, |
| "Press middle mouse button to raise/lower the window.", |
| -1, 0, fontheight * 2, DSTF_LEFT | DSTF_TOP); |
| |
| bgsurface->SetColor (bgsurface, 0xCF, 0xFF, 0x6F, 0xFF); |
| bgsurface->DrawString (bgsurface, |
| "Press right mouse button when you are done.", -1, |
| 0, fontheight * 3, DSTF_LEFT | DSTF_TOP); |
| |
| layer->SetBackgroundImage (layer, bgsurface); |
| layer->SetBackgroundMode (layer, DLBM_IMAGE); |
| } |
| |
| { |
| DFBSurfaceDescription sdsc; |
| DFBWindowDescription desc; |
| |
| desc.flags = (DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT); |
| |
| if (!video_provider) { |
| desc.caps = DWCAPS_ALPHACHANNEL; |
| desc.flags |= DWDESC_CAPS; |
| |
| sdsc.width = 300; |
| sdsc.height = 200; |
| } else { |
| video_provider->GetSurfaceDescription (video_provider, &sdsc); |
| |
| if (sdsc.flags & DSDESC_CAPS) { |
| desc.flags |= DWDESC_SURFACE_CAPS; |
| desc.surface_caps = sdsc.caps; |
| } |
| } |
| |
| desc.posx = 20; |
| desc.posy = 120; |
| desc.width = sdsc.width; |
| desc.height = sdsc.height; |
| |
| DFBCHECK (layer->CreateWindow (layer, &desc, &window2)); |
| window2->GetSurface (window2, &window_surface2); |
| |
| window2->SetOpacity (window2, 0xFF); |
| |
| window2->GetID (window2, &id2); |
| |
| window2->CreateEventBuffer (window2, &buffer); |
| |
| if (video_provider) { |
| video_provider->PlayTo (video_provider, window_surface2, |
| NULL, NULL, NULL); |
| } else { |
| window_surface2->SetColor (window_surface2, 0x00, 0x30, 0x10, 0xc0); |
| window_surface2->DrawRectangle (window_surface2, |
| 0, 0, desc.width, desc.height); |
| window_surface2->SetColor (window_surface2, 0x80, 0xa0, 0x00, 0x90); |
| window_surface2->FillRectangle (window_surface2, |
| 1, 1, desc.width - 2, desc.height - 2); |
| } |
| |
| window_surface2->Flip (window_surface2, NULL, 0); |
| } |
| |
| { |
| DFBWindowDescription desc; |
| |
| desc.flags = (DWDESC_POSX | DWDESC_POSY | |
| DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS); |
| desc.posx = 200; |
| desc.posy = 200; |
| desc.width = 512; |
| desc.height = 145; |
| desc.caps = DWCAPS_ALPHACHANNEL; |
| |
| DFBCHECK (layer->CreateWindow (layer, &desc, &window1)); |
| window1->GetSurface (window1, &window_surface1); |
| |
| DFBCHECK (dfb->CreateImageProvider (dfb, "dfblogo.png", &provider)); |
| provider->RenderTo (provider, window_surface1, NULL); |
| |
| window_surface1->SetColor (window_surface1, 0xFF, 0x20, 0x20, 0x90); |
| window_surface1->DrawRectangle (window_surface1, |
| 0, 0, desc.width, desc.height); |
| |
| window_surface1->Flip (window_surface1, NULL, 0); |
| |
| provider->Release (provider); |
| |
| window1->AttachEventBuffer (window1, buffer); |
| |
| window1->SetOpacity (window1, 0xFF); |
| |
| window1->GetID (window1, &id1); |
| } |
| |
| { |
| DFBWindowDescription desc; |
| GstElement *src, *decode; |
| GstElement *v_queue, *v_scale, *cs, *v_sink; |
| GstElement *a_queue, *conv, *a_sink; |
| GstPad *v_pad, *a_pad; |
| |
| desc.flags = (DWDESC_POSX | DWDESC_POSY | |
| DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS); |
| desc.posx = 10; |
| desc.posy = 10; |
| desc.width = 100; |
| desc.height = 100; |
| desc.caps = DWCAPS_ALPHACHANNEL; |
| |
| DFBCHECK (layer->CreateWindow (layer, &desc, &window3)); |
| window3->GetSurface (window3, &window_surface3); |
| |
| window3->AttachEventBuffer (window3, buffer); |
| |
| window3->SetOpacity (window3, 0xFF); |
| |
| window3->GetID (window3, &id3); |
| |
| pipeline = gst_pipeline_new ("pipeline"); |
| |
| src = gst_element_factory_make ("gnomevfssrc", "src"); |
| g_object_set (src, "location", argv[1], NULL); |
| decode = gst_element_factory_make ("decodebin", "decode"); |
| |
| v_queue = gst_element_factory_make ("queue", "v_queue"); |
| v_scale = gst_element_factory_make ("videoscale", "v_scale"); |
| cs = gst_element_factory_make ("videoconvert", "cs"); |
| v_sink = gst_element_factory_make ("dfbvideosink", "v_sink"); |
| g_object_set (v_sink, "surface", window_surface3, NULL); |
| |
| a_queue = gst_element_factory_make ("queue", "a_queue"); |
| conv = gst_element_factory_make ("audioconvert", "conv"); |
| a_sink = gst_element_factory_make ("alsasink", "a_sink"); |
| |
| gst_bin_add_many (GST_BIN (pipeline), src, decode, NULL); |
| gst_bin_add_many (GST_BIN (pipeline), v_queue, v_scale, cs, v_sink, NULL); |
| gst_bin_add_many (GST_BIN (pipeline), a_queue, conv, a_sink, NULL); |
| |
| gst_element_link (src, decode); |
| gst_element_link_many (v_queue, v_scale, cs, v_sink, NULL); |
| gst_element_link_many (a_queue, conv, a_sink, NULL); |
| |
| v_pad = gst_element_get_static_pad (v_queue, "sink"); |
| a_pad = gst_element_get_static_pad (a_queue, "sink"); |
| |
| setup_dynamic_link (decode, NULL, v_pad, NULL); |
| setup_dynamic_link (decode, NULL, a_pad, NULL); |
| |
| /* We want to know when the size is defined */ |
| g_signal_connect (v_pad, "notify::caps", G_CALLBACK (size_changed), |
| window3); |
| |
| gst_object_unref (a_pad); |
| gst_object_unref (v_pad); |
| |
| gst_element_set_state (pipeline, GST_STATE_PLAYING); |
| } |
| |
| window1->RequestFocus (window1); |
| window1->RaiseToTop (window1); |
| |
| while (!quit) { |
| static IDirectFBWindow *active = NULL; |
| static int grabbed = 0; |
| static int startx = 0; |
| static int starty = 0; |
| static int endx = 0; |
| static int endy = 0; |
| DFBWindowEvent evt; |
| |
| buffer->WaitForEventWithTimeout (buffer, 0, 10); |
| |
| while (buffer->GetEvent (buffer, DFB_EVENT (&evt)) == DFB_OK) { |
| IDirectFBWindow *window; |
| |
| if (evt.window_id == id1) |
| window = window1; |
| else if (evt.window_id == id3) |
| window = window3; |
| else |
| window = window2; |
| |
| if (evt.type == DWET_GOTFOCUS) { |
| active = window; |
| } else if (active) { |
| switch (evt.type) { |
| |
| case DWET_BUTTONDOWN: |
| if (!grabbed && evt.button == DIBI_LEFT) { |
| grabbed = 1; |
| startx = evt.cx; |
| starty = evt.cy; |
| window->GrabPointer (window); |
| } |
| break; |
| |
| case DWET_BUTTONUP: |
| switch (evt.button) { |
| case DIBI_LEFT: |
| if (grabbed) { |
| window->UngrabPointer (window); |
| grabbed = 0; |
| } |
| break; |
| case DIBI_MIDDLE: |
| active->RaiseToTop (active); |
| break; |
| case DIBI_RIGHT: |
| quit = DIKS_DOWN; |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case DWET_KEYDOWN: |
| if (grabbed) |
| break; |
| switch (evt.key_id) { |
| case DIKI_RIGHT: |
| active->Move (active, 1, 0); |
| break; |
| case DIKI_LEFT: |
| active->Move (active, -1, 0); |
| break; |
| case DIKI_UP: |
| active->Move (active, 0, -1); |
| break; |
| case DIKI_DOWN: |
| active->Move (active, 0, 1); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case DWET_LOSTFOCUS: |
| if (!grabbed && active == window) |
| active = NULL; |
| break; |
| |
| default: |
| break; |
| |
| } |
| } |
| |
| switch (evt.type) { |
| |
| case DWET_MOTION: |
| endx = evt.cx; |
| endy = evt.cy; |
| break; |
| |
| case DWET_KEYDOWN: |
| switch (evt.key_symbol) { |
| case DIKS_ESCAPE: |
| case DIKS_SMALL_Q: |
| case DIKS_CAPITAL_Q: |
| case DIKS_BACK: |
| case DIKS_STOP: |
| quit = 1; |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| if (video_provider) |
| window_surface2->Flip (window_surface2, NULL, 0); |
| |
| if (active) { |
| if (grabbed) { |
| active->Move (active, endx - startx, endy - starty); |
| startx = endx; |
| starty = endy; |
| } |
| active->SetOpacity (active, (sin (myclock () / 300.0) * 85) + 170); |
| } |
| } |
| |
| if (video_provider) |
| video_provider->Release (video_provider); |
| |
| gst_element_set_state (pipeline, GST_STATE_NULL); |
| |
| buffer->Release (buffer); |
| font->Release (font); |
| window_surface2->Release (window_surface2); |
| window_surface1->Release (window_surface1); |
| window_surface3->Release (window_surface3); |
| window2->Release (window2); |
| window1->Release (window1); |
| window3->Release (window3); |
| layer->Release (layer); |
| bgsurface->Release (bgsurface); |
| dfb->Release (dfb); |
| |
| return 42; |
| } |