diff options
Diffstat (limited to 'examples/directfb/gstdfb.c')
-rw-r--r-- | examples/directfb/gstdfb.c | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/examples/directfb/gstdfb.c b/examples/directfb/gstdfb.c new file mode 100644 index 00000000..58114204 --- /dev/null +++ b/examples/directfb/gstdfb.c @@ -0,0 +1,514 @@ +/* + (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 () +{ + 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_negotiated_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 ("ffmpegcolorspace", "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_pad (v_queue, "sink"); + a_pad = gst_element_get_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; +} |