1 /* GStreamer DirectFB plugin
2 * Copyright (C) 2005 Julien MOUTTE <julien@moutte.net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:element-dfbvideosink
25 * DfbVideoSink renders video frames using the
26 * <ulink url="http://www.directfb.org/">DirectFB</ulink> library.
27 * Rendering can happen in two different modes :
31 * Standalone: this mode will take complete control of the monitor forcing
32 * <ulink url="http://www.directfb.org/">DirectFB</ulink> to fullscreen layout.
33 * This is convenient to test using the gst-launch command line tool or
34 * other simple applications. It is possible to interrupt playback while
35 * being in this mode by pressing the Escape key.
38 * This mode handles navigation events for every input device supported by
39 * the <ulink url="http://www.directfb.org/">DirectFB</ulink> library, it will
40 * look for available video modes in the fb.modes file and try to switch
41 * the framebuffer video mode to the most suitable one. Depending on
42 * hardware acceleration capabilities the element will handle scaling or not.
43 * If no acceleration is available it will do clipping or centering of the
44 * video frames respecting the original aspect ratio.
49 * Embedded: this mode will render video frames in a
50 * <link linkend="GstDfbVideoSink--surface">surface</link> provided by the
51 * application developer. This is a more advanced usage of the element and
52 * it is required to integrate video playback in existing
53 * <ulink url="http://www.directfb.org/">DirectFB</ulink> applications.
56 * When using this mode the element just renders to the
57 * <link linkend="GstDfbVideoSink--surface">surface</link> provided by the
58 * application, that means it won't handle navigation events and won't resize
59 * the <link linkend="GstDfbVideoSink--surface">surface</link> to fit video
60 * frames geometry. Application has to implement the necessary code to grab
61 * informations about the negotiated geometry and resize there
62 * <link linkend="GstDfbVideoSink--surface">surface</link> accordingly.
66 * For both modes the element implements a buffer pool allocation system to
67 * optimize memory allocation time and handle reverse negotiation. Indeed if
68 * you insert an element like videoscale in the pipeline the video sink will
69 * negotiate with it to try get a scaled video for either the fullscreen layout
70 * or the application provided external
71 * <link linkend="GstDfbVideoSink--surface">surface</link>.
73 * <title>Example application</title>
75 * <include xmlns="http://www.w3.org/2003/XInclude" href="element-dfb-example.xml" />
77 * <title>Example pipelines</title>
79 * Here is a test pipeline to test the colorbalance interface :
81 * gst-launch -v videotestsrc ! dfbvideosink hue=20000 saturation=40000 brightness=25000
92 #include <gst/interfaces/navigation.h>
93 #include <gst/interfaces/colorbalance.h>
96 #include "dfbvideosink.h"
100 /* Debugging category */
101 GST_DEBUG_CATEGORY_STATIC (dfbvideosink_debug);
102 #define GST_CAT_DEFAULT dfbvideosink_debug
104 /* ElementFactory information */
105 static const GstElementDetails gst_dfbvideosink_details =
106 GST_ELEMENT_DETAILS ("DirectFB video sink",
108 "A DirectFB based videosink",
109 "Julien Moutte <julien@moutte.net>");
111 /* Default template */
112 static GstStaticPadTemplate gst_dfbvideosink_sink_template_factory =
113 GST_STATIC_PAD_TEMPLATE ("sink",
116 GST_STATIC_CAPS ("video/x-raw-rgb, "
117 "framerate = (fraction) [ 0, MAX ], "
118 "width = (int) [ 1, MAX ], "
119 "height = (int) [ 1, MAX ]; "
121 "framerate = (fraction) [ 0, MAX ], "
122 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
125 /* Signals and args */
134 ARG_PIXEL_ASPECT_RATIO,
138 static void gst_dfbvideosink_bufferpool_clear (GstDfbVideoSink * dfbvideosink);
139 static DFBSurfacePixelFormat gst_dfbvideosink_get_format_from_caps (GstCaps *
141 static void gst_dfbvideosink_update_colorbalance (GstDfbVideoSink *
143 static void gst_dfbvideosink_surface_destroy (GstDfbVideoSink * dfbvideosink,
144 GstDfbSurface * surface);
146 static GstVideoSinkClass *parent_class = NULL;
147 static GstBufferClass *surface_parent_class = NULL;
150 gst_dfbvideosink_get_format_name (DFBSurfacePixelFormat format)
198 /* Creates miniobject and our internal surface */
199 static GstDfbSurface *
200 gst_dfbvideosink_surface_create (GstDfbVideoSink * dfbvideosink, GstCaps * caps,
203 GstDfbSurface *surface = NULL;
204 GstStructure *structure = NULL;
206 DFBSurfaceDescription s_dsc;
209 gboolean succeeded = FALSE;
211 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink), NULL);
213 surface = (GstDfbSurface *) gst_mini_object_new (GST_TYPE_DFBSURFACE);
215 /* Keep a ref to our sink */
216 surface->dfbvideosink = gst_object_ref (dfbvideosink);
217 /* Surface is not locked yet */
218 surface->locked = FALSE;
220 structure = gst_caps_get_structure (caps, 0);
222 if (!gst_structure_get_int (structure, "width", &surface->width) ||
223 !gst_structure_get_int (structure, "height", &surface->height)) {
224 GST_WARNING_OBJECT (dfbvideosink, "failed getting geometry from caps %"
225 GST_PTR_FORMAT, caps);
229 /* Pixel format from caps */
230 surface->pixel_format = gst_dfbvideosink_get_format_from_caps (caps);
231 if (surface->pixel_format == DSPF_UNKNOWN) {
235 if (!dfbvideosink->dfb) {
236 GST_DEBUG_OBJECT (dfbvideosink, "no DirectFB context to create a surface");
240 /* Creating an internal surface which will be used as GstBuffer, we used
241 the detected pixel format and video dimensions */
244 DSDESC_PIXELFORMAT | DSDESC_WIDTH | DSDESC_HEIGHT /*| DSDESC_CAPS */ ;
246 s_dsc.pixelformat = surface->pixel_format;
247 s_dsc.width = surface->width;
248 s_dsc.height = surface->height;
249 /*s_dsc.caps = DSCAPS_VIDEOONLY; */
251 ret = dfbvideosink->dfb->CreateSurface (dfbvideosink->dfb, &s_dsc,
254 GST_WARNING_OBJECT (dfbvideosink, "failed creating a DirectFB surface");
255 surface->surface = NULL;
259 /* Clearing surface */
260 surface->surface->Clear (surface->surface, 0x00, 0x00, 0x00, 0xFF);
262 /* Locking the surface to acquire the memory pointer */
263 surface->surface->Lock (surface->surface, DSLF_WRITE, &data, &pitch);
264 surface->locked = TRUE;
265 GST_BUFFER_DATA (surface) = data;
266 GST_BUFFER_SIZE (surface) = pitch * surface->height;
268 /* Be carefull here. If size is different from the surface size
269 (pitch * height), we can't use that surface through buffer alloc system
270 or we are going to run into serious stride issues */
271 if (GST_BUFFER_SIZE (surface) != size) {
272 GST_WARNING_OBJECT (dfbvideosink, "DirectFB surface size (%dx%d=%d) "
273 "differs from GStreamer requested size %d", pitch, surface->height,
274 GST_BUFFER_SIZE (surface), size);
278 GST_DEBUG_OBJECT (dfbvideosink, "creating a %dx%d surface (%p) with %s "
279 "pixel format, line pitch %d", surface->width, surface->height, surface,
280 gst_dfbvideosink_get_format_name (surface->pixel_format), pitch);
288 /* We allocate a standard buffer ourselves to store it in our buffer pool,
289 this is an optimisation for memory allocation */
290 GST_BUFFER (surface)->malloc_data = g_malloc (size);
291 GST_BUFFER_DATA (surface) = GST_BUFFER (surface)->malloc_data;
292 GST_BUFFER_SIZE (surface) = size;
293 if (surface->surface) {
294 if (surface->locked) {
295 surface->surface->Unlock (surface->surface);
296 surface->locked = FALSE;
298 surface->surface->Release (surface->surface);
299 surface->surface = NULL;
301 GST_DEBUG_OBJECT (dfbvideosink, "allocating a buffer (%p) of %d bytes",
308 gst_dfbvideosink_surface_destroy (dfbvideosink, surface);
314 /* We are called from the finalize method of miniobject, the object will be
315 * destroyed so we just have to clean our internal stuff */
317 gst_dfbvideosink_surface_destroy (GstDfbVideoSink * dfbvideosink,
318 GstDfbSurface * surface)
320 g_return_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink));
322 /* Release our internal surface */
323 if (surface->surface) {
324 if (surface->locked) {
325 surface->surface->Unlock (surface->surface);
326 surface->locked = FALSE;
328 surface->surface->Release (surface->surface);
329 surface->surface = NULL;
332 if (surface->dfbvideosink) {
333 /* Release the ref to our sink */
334 surface->dfbvideosink = NULL;
335 gst_object_unref (dfbvideosink);
338 GST_MINI_OBJECT_CLASS (surface_parent_class)->
339 finalize (GST_MINI_OBJECT (surface));
343 gst_dfbvideosink_event_thread (GstDfbVideoSink * dfbvideosink)
347 while (dfbvideosink->running) {
348 /* Wait for an event with a 50 ms timeout */
349 dfbvideosink->event_buffer->WaitForEventWithTimeout (dfbvideosink->
350 event_buffer, 0, 50);
352 /* Do we have an event ? */
353 ret = dfbvideosink->event_buffer->HasEvent (dfbvideosink->event_buffer);
358 GST_DEBUG_OBJECT (dfbvideosink, "we have an event");
360 ret = dfbvideosink->event_buffer->GetEvent (dfbvideosink->event_buffer,
362 if (ret != DFB_OK) { /* Error */
363 GST_WARNING_OBJECT (dfbvideosink, "failed when getting event from "
365 } else { /* Handle event */
366 if (event.input.type == DIET_KEYPRESS) {
367 switch (event.input.key_symbol) {
370 GST_ELEMENT_ERROR (dfbvideosink, RESOURCE, OPEN_WRITE,
371 ("Video output device is gone."),
372 ("We were running fullscreen and user "
373 "pressed the ESC key, stopping playback."));
376 GST_DEBUG_OBJECT (dfbvideosink, "key press event %c !",
377 event.input.key_symbol);
378 gst_navigation_send_key_event (GST_NAVIGATION (dfbvideosink),
379 "key-press", "prout");
381 } else if (event.input.type == DIET_BUTTONPRESS) {
384 dfbvideosink->layer->GetCursorPosition (dfbvideosink->layer, &x, &y);
386 GST_DEBUG_OBJECT (dfbvideosink, "button %d pressed at %dx%d",
387 event.input.button, x, y);
389 gst_navigation_send_mouse_event (GST_NAVIGATION (dfbvideosink),
390 "mouse-button-press", event.input.button, x, y);
391 } else if (event.input.type == DIET_BUTTONRELEASE) {
394 dfbvideosink->layer->GetCursorPosition (dfbvideosink->layer, &x, &y);
396 GST_DEBUG_OBJECT (dfbvideosink, "button %d released at %dx%d",
397 event.input.button, x, y);
399 gst_navigation_send_mouse_event (GST_NAVIGATION (dfbvideosink),
400 "mouse-button-release", event.input.button, x, y);
401 } else if (event.input.type == DIET_AXISMOTION) {
404 dfbvideosink->layer->GetCursorPosition (dfbvideosink->layer, &x, &y);
405 gst_navigation_send_mouse_event (GST_NAVIGATION (dfbvideosink),
406 "mouse-move", 0, x, y);
408 GST_WARNING_OBJECT (dfbvideosink, "unhandled event type %d",
417 static DFBEnumerationResult
418 gst_dfbvideosink_enum_layers (DFBDisplayLayerID id,
419 DFBDisplayLayerDescription desc, void *data)
421 GstDfbVideoSink *dfbvideosink = NULL;
422 IDirectFBDisplayLayer *layer = NULL;
423 DFBDisplayLayerConfig dlc;
425 gboolean backbuffer = FALSE;
427 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (data), DFENUM_CANCEL);
429 dfbvideosink = GST_DFBVIDEOSINK (data);
431 GST_DEBUG_OBJECT (dfbvideosink, "inspecting display layer %d with name: %s",
434 if ((desc.type & DLTF_VIDEO) && (desc.caps & DLCAPS_SURFACE)) {
435 GST_DEBUG_OBJECT (dfbvideosink,
436 "this layer can handle live video and has a surface");
438 if (desc.caps & DLCAPS_SURFACE) {
439 GST_DEBUG_OBJECT (dfbvideosink,
440 "this layer can not handle live video but has a surface");
442 GST_DEBUG_OBJECT (dfbvideosink, "no we can't use that layer, really...");
447 ret = dfbvideosink->dfb->GetDisplayLayer (dfbvideosink->dfb, id, &layer);
449 GST_WARNING_OBJECT (dfbvideosink, "failed getting display layer %s",
454 ret = layer->GetConfiguration (layer, &dlc);
456 GST_WARNING_OBJECT (dfbvideosink,
457 "failed getting display layer configuration");
461 if ((dlc.flags & DLCONF_BUFFERMODE) && (dlc.buffermode & DLBM_FRONTONLY)) {
462 GST_DEBUG_OBJECT (dfbvideosink, "no backbuffer");
464 if ((dlc.flags & DLCONF_BUFFERMODE) && (dlc.buffermode & DLBM_BACKVIDEO)) {
465 GST_DEBUG_OBJECT (dfbvideosink, "backbuffer is in video memory");
468 if ((dlc.flags & DLCONF_BUFFERMODE) && (dlc.buffermode & DLBM_BACKSYSTEM)) {
469 GST_DEBUG_OBJECT (dfbvideosink, "backbuffer is in system memory");
472 if ((dlc.flags & DLCONF_BUFFERMODE) && (dlc.buffermode & DLBM_TRIPLE)) {
473 GST_DEBUG_OBJECT (dfbvideosink, "triple buffering");
477 /* If the primary is suitable we prefer using it */
478 if (dfbvideosink->layer_id != DLID_PRIMARY) {
479 GST_DEBUG_OBJECT (dfbvideosink, "selecting layer named %s", desc.name);
480 dfbvideosink->layer_id = id;
481 dfbvideosink->backbuffer = backbuffer;
483 GST_DEBUG_OBJECT (dfbvideosink, "layer %s is suitable but the primary "
484 "is currently selected and we prefer that one", desc.name);
489 layer->Release (layer);
494 static DFBEnumerationResult
495 gst_dfbvideosink_enum_vmodes (gint width, gint height, gint bpp, void *data)
497 GstDfbVideoSink *dfbvideosink = NULL;
498 GstDfbVMode *vmode = NULL;
500 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (data), DFENUM_CANCEL);
502 dfbvideosink = GST_DFBVIDEOSINK (data);
504 GST_DEBUG_OBJECT (dfbvideosink, "adding video mode %dx%d at %d bpp", width,
506 vmode = g_new0 (GstDfbVMode, 1);
507 vmode->width = width;
508 vmode->height = height;
511 /* We need to know the maximum video geometry we can accept for the caps */
512 if (width > dfbvideosink->out_width) {
513 dfbvideosink->out_width = width;
515 if (height > dfbvideosink->out_height) {
516 dfbvideosink->out_height = height;
519 dfbvideosink->vmodes = g_slist_append (dfbvideosink->vmodes, vmode);
524 static DFBEnumerationResult
525 gst_dfbvideosink_enum_devices (DFBInputDeviceID id,
526 DFBInputDeviceDescription desc, void *data)
528 GstDfbVideoSink *dfbvideosink = NULL;
529 IDirectFBInputDevice *device = NULL;
532 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (data), DFENUM_CANCEL);
534 dfbvideosink = GST_DFBVIDEOSINK (data);
536 GST_DEBUG_OBJECT (dfbvideosink, "detected input device %s from vendor %s",
537 desc.name, desc.vendor);
539 /* Get that input device */
540 ret = dfbvideosink->dfb->GetInputDevice (dfbvideosink->dfb, id, &device);
542 GST_WARNING_OBJECT (dfbvideosink, "failed when getting input device id %d",
547 ret = device->AttachEventBuffer (device, dfbvideosink->event_buffer);
549 GST_WARNING_OBJECT (dfbvideosink, "failed when attaching input device "
550 "%d to our event buffer", id);
555 device->Release (device);
561 gst_dfbvideosink_setup (GstDfbVideoSink * dfbvideosink)
565 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink), FALSE);
567 dfbvideosink->video_width = 0;
568 dfbvideosink->video_height = 0;
569 dfbvideosink->out_width = 0;
570 dfbvideosink->out_height = 0;
571 dfbvideosink->fps_d = 0;
572 dfbvideosink->fps_n = 0;
573 dfbvideosink->hw_scaling = FALSE;
574 dfbvideosink->backbuffer = FALSE;
575 dfbvideosink->pixel_format = DSPF_UNKNOWN;
577 /* If we do it all by ourself we create the DirectFB context, get the
578 primary layer and use a fullscreen configuration */
579 if (!dfbvideosink->ext_surface) {
580 GST_DEBUG_OBJECT (dfbvideosink, "no external surface, taking over "
581 "DirectFB fullscreen");
582 if (!dfbvideosink->dfb) {
583 DFBGraphicsDeviceDescription hw_caps;
584 char *argv[] = { "-", "--dfb:quiet", NULL };
588 GST_DEBUG_OBJECT (dfbvideosink, "initializing DirectFB");
591 ret = DirectFBInit (&argc, &args);
594 GST_WARNING_OBJECT (dfbvideosink, "DirectFB initialization failed");
598 ret = DirectFBCreate (&(dfbvideosink->dfb));
601 GST_WARNING_OBJECT (dfbvideosink, "failed creating the DirectFB "
606 /* Get Hardware capabilities */
607 ret = dfbvideosink->dfb->GetDeviceDescription (dfbvideosink->dfb,
611 GST_WARNING_OBJECT (dfbvideosink, "failed grabbing the hardware "
616 GST_DEBUG_OBJECT (dfbvideosink, "video card %s from vendor %s detected "
617 "with %d bytes of video memory", hw_caps.name, hw_caps.vendor,
618 hw_caps.video_memory);
620 if (hw_caps.acceleration_mask & DFXL_BLIT) {
621 GST_DEBUG_OBJECT (dfbvideosink, "Blit is accelerated");
623 if (hw_caps.acceleration_mask & DFXL_STRETCHBLIT) {
624 GST_DEBUG_OBJECT (dfbvideosink, "StretchBlit is accelerated");
625 dfbvideosink->hw_scaling = TRUE;
627 GST_DEBUG_OBJECT (dfbvideosink, "StretchBlit is not accelerated");
628 dfbvideosink->hw_scaling = FALSE;
631 dfbvideosink->layer_id = -1;
633 /* Inspect all the Display layers */
634 dfbvideosink->dfb->EnumDisplayLayers (dfbvideosink->dfb,
635 gst_dfbvideosink_enum_layers, dfbvideosink);
636 /* Inspect all Video modes */
637 dfbvideosink->dfb->EnumVideoModes (dfbvideosink->dfb,
638 gst_dfbvideosink_enum_vmodes, dfbvideosink);
640 /* Create an event buffer for input */
641 dfbvideosink->dfb->CreateEventBuffer (dfbvideosink->dfb,
642 &dfbvideosink->event_buffer);
644 /* Inspect all Input devices */
645 dfbvideosink->dfb->EnumInputDevices (dfbvideosink->dfb,
646 gst_dfbvideosink_enum_devices, dfbvideosink);
647 /* Create a thread to handle those events */
648 dfbvideosink->event_thread = g_thread_create (
649 (GThreadFunc) gst_dfbvideosink_event_thread,
650 dfbvideosink, TRUE, NULL);
652 if (!dfbvideosink->layer) {
653 GList *channels_list = NULL;
654 DFBDisplayLayerDescription dl_desc;
656 /* Get the best Display Layer */
657 ret = dfbvideosink->dfb->GetDisplayLayer (dfbvideosink->dfb,
658 dfbvideosink->layer_id, &dfbvideosink->layer);
660 GST_WARNING_OBJECT (dfbvideosink, "failed getting display layer");
664 ret = dfbvideosink->layer->SetCooperativeLevel (dfbvideosink->layer,
668 GST_WARNING_OBJECT (dfbvideosink, "failed setting display layer to "
673 dfbvideosink->layer->GetDescription (dfbvideosink->layer, &dl_desc);
675 /* Check that this layer is able to do colorbalance settings */
676 if (dl_desc.caps & DLCAPS_BRIGHTNESS) {
677 channels_list = g_list_append (channels_list, "BRIGHTNESS");
679 if (dl_desc.caps & DLCAPS_CONTRAST) {
680 channels_list = g_list_append (channels_list, "CONTRAST");
682 if (dl_desc.caps & DLCAPS_HUE) {
683 channels_list = g_list_append (channels_list, "HUE");
685 if (dl_desc.caps & DLCAPS_SATURATION) {
686 channels_list = g_list_append (channels_list, "SATURATION");
690 GList *walk = channels_list;
692 /* Generate Color balance channel list */
694 GstColorBalanceChannel *channel = NULL;
696 GST_DEBUG_OBJECT (dfbvideosink, "adding %s as a colorbalance channel",
699 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
700 channel->label = g_strdup (walk->data);
701 channel->min_value = 0x0000;
702 channel->max_value = 0xFFFF;
704 dfbvideosink->cb_channels = g_list_append (dfbvideosink->cb_channels,
707 walk = g_list_next (walk);
710 /* If the colorbalance settings have not been touched we get current
711 values as defaults and update our internal variables */
712 if (!dfbvideosink->cb_changed) {
713 DFBColorAdjustment cb_adjust;
715 ret = dfbvideosink->layer->GetColorAdjustment (dfbvideosink->layer,
719 GST_WARNING_OBJECT (dfbvideosink, "failed when getting color "
720 "adjustment from layer");
723 if (cb_adjust.flags & DCAF_BRIGHTNESS) {
724 dfbvideosink->brightness = cb_adjust.brightness;
726 dfbvideosink->brightness = 0x8000;
728 if (cb_adjust.flags & DCAF_CONTRAST) {
729 dfbvideosink->contrast = cb_adjust.contrast;
731 dfbvideosink->contrast = 0x8000;
733 if (cb_adjust.flags & DCAF_HUE) {
734 dfbvideosink->hue = cb_adjust.hue;
736 dfbvideosink->hue = 0x8000;
738 if (cb_adjust.flags & DCAF_SATURATION) {
739 dfbvideosink->saturation = cb_adjust.saturation;
741 dfbvideosink->saturation = 0x8000;
743 GST_DEBUG_OBJECT (dfbvideosink, "brightness %d, contrast %d, "
744 "hue %d, saturation %d", dfbvideosink->brightness,
745 dfbvideosink->contrast, dfbvideosink->hue,
746 dfbvideosink->saturation);
749 g_list_free (channels_list);
751 gst_dfbvideosink_update_colorbalance (dfbvideosink);
754 dfbvideosink->layer->SetBackgroundColor (dfbvideosink->layer,
755 0x00, 0x00, 0x00, 0xFF);
757 dfbvideosink->layer->EnableCursor (dfbvideosink->layer, TRUE);
759 GST_DEBUG_OBJECT (dfbvideosink, "getting primary surface");
760 dfbvideosink->layer->GetSurface (dfbvideosink->layer,
761 &dfbvideosink->primary);
763 dfbvideosink->primary->SetBlittingFlags (dfbvideosink->primary,
767 dfbvideosink->primary->GetPixelFormat (dfbvideosink->primary,
768 &dfbvideosink->pixel_format);
770 DFBSurfaceCapabilities s_caps;
772 GST_DEBUG_OBJECT (dfbvideosink, "getting pixel format from foreign "
773 "surface %p", dfbvideosink->ext_surface);
774 dfbvideosink->ext_surface->GetPixelFormat (dfbvideosink->ext_surface,
775 &dfbvideosink->pixel_format);
776 dfbvideosink->ext_surface->GetSize (dfbvideosink->ext_surface,
777 &dfbvideosink->out_width, &dfbvideosink->out_height);
778 dfbvideosink->ext_surface->GetCapabilities (dfbvideosink->ext_surface,
780 if ((s_caps & DSCAPS_DOUBLE) || (s_caps & DSCAPS_TRIPLE)) {
781 dfbvideosink->backbuffer = TRUE;
783 dfbvideosink->backbuffer = FALSE;
785 GST_DEBUG_OBJECT (dfbvideosink, "external surface is %dx%d and uses %s "
786 "pixel format", dfbvideosink->out_width, dfbvideosink->out_height,
787 gst_dfbvideosink_get_format_name (dfbvideosink->pixel_format));
790 dfbvideosink->setup = TRUE;
793 return dfbvideosink->setup;
797 gst_dfbvideosink_cleanup (GstDfbVideoSink * dfbvideosink)
799 g_return_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink));
801 GST_DEBUG_OBJECT (dfbvideosink, "cleaning up DirectFB environment");
803 /* Wait for our event thread */
804 if (dfbvideosink->event_thread) {
805 g_thread_join (dfbvideosink->event_thread);
806 dfbvideosink->event_thread = NULL;
809 if (dfbvideosink->event_buffer) {
810 dfbvideosink->event_buffer->Release (dfbvideosink->event_buffer);
811 dfbvideosink->event_buffer = NULL;
814 if (dfbvideosink->vmodes) {
815 GSList *walk = dfbvideosink->vmodes;
819 walk = g_slist_next (walk);
821 g_slist_free (dfbvideosink->vmodes);
822 dfbvideosink->vmodes = NULL;
825 if (dfbvideosink->cb_channels) {
826 GList *walk = dfbvideosink->cb_channels;
829 GstColorBalanceChannel *channel = walk->data;
831 g_object_unref (channel);
832 walk = g_list_next (walk);
834 g_list_free (dfbvideosink->cb_channels);
835 dfbvideosink->cb_channels = NULL;
838 if (dfbvideosink->buffer_pool) {
839 gst_dfbvideosink_bufferpool_clear (dfbvideosink);
842 if (dfbvideosink->primary) {
843 dfbvideosink->primary->Release (dfbvideosink->primary);
844 dfbvideosink->primary = NULL;
847 if (dfbvideosink->layer) {
848 dfbvideosink->layer->EnableCursor (dfbvideosink->layer, FALSE);
849 dfbvideosink->layer->Release (dfbvideosink->layer);
850 dfbvideosink->layer = NULL;
853 if (dfbvideosink->dfb) {
854 dfbvideosink->dfb->Release (dfbvideosink->dfb);
855 dfbvideosink->dfb = NULL;
858 dfbvideosink->setup = FALSE;
861 static DFBSurfacePixelFormat
862 gst_dfbvideosink_get_format_from_caps (GstCaps * caps)
864 GstStructure *structure;
866 DFBSurfacePixelFormat pixel_format = DSPF_UNKNOWN;
868 g_return_val_if_fail (GST_IS_CAPS (caps), DSPF_UNKNOWN);
870 structure = gst_caps_get_structure (caps, 0);
872 if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
875 ret = gst_structure_get_int (structure, "bpp", &bpp);
876 ret &= gst_structure_get_int (structure, "depth", &depth);
884 pixel_format = DSPF_RGB16;
887 pixel_format = DSPF_RGB24;
891 pixel_format = DSPF_RGB32;
892 } else if (depth == 32) {
893 pixel_format = DSPF_ARGB;
899 GST_WARNING ("unhandled RGB format, bpp %d, depth %d", bpp, depth);
902 } else if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
905 ret = gst_structure_get_fourcc (structure, "format", &fourcc);
908 GST_WARNING ("failed grabbing fourcc from caps %" GST_PTR_FORMAT, caps);
913 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
914 pixel_format = DSPF_I420;
916 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
917 pixel_format = DSPF_YV12;
919 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
920 pixel_format = DSPF_YUY2;
922 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
923 pixel_format = DSPF_UYVY;
926 GST_WARNING ("unhandled YUV format %" GST_FOURCC_FORMAT,
927 GST_FOURCC_ARGS (fourcc));
931 GST_WARNING ("unknown caps name received %" GST_PTR_FORMAT, caps);
940 gst_dfbvideosink_get_caps_from_format (DFBSurfacePixelFormat format)
942 GstCaps *caps = NULL;
943 gboolean is_rgb = FALSE, is_yuv = FALSE;
947 g_return_val_if_fail (format != DSPF_UNKNOWN, NULL);
972 fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
976 fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
980 fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
984 fourcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
987 GST_WARNING ("unknown pixel format %s",
988 gst_dfbvideosink_get_format_name (format));
993 caps = gst_caps_new_simple ("video/x-raw-rgb",
994 "bpp", G_TYPE_INT, bpp, "depth", G_TYPE_INT, depth, NULL);
996 caps = gst_caps_new_simple ("video/x-raw-yuv",
997 "format", GST_TYPE_FOURCC, fourcc, NULL);
999 GST_WARNING ("neither rgb nor yuv, something strange here");
1007 gst_dfbvideosink_can_blit_from_format (GstDfbVideoSink * dfbvideosink,
1008 DFBSurfacePixelFormat format)
1010 gboolean res = FALSE;
1012 IDirectFBSurface *surface = NULL;
1013 DFBSurfaceDescription s_dsc;
1014 DFBAccelerationMask mask;
1015 DFBDisplayLayerConfig dlc, prev_dlc;
1017 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink), FALSE);
1019 /* Create a surface of desired format */
1020 s_dsc.flags = DSDESC_PIXELFORMAT | DSDESC_WIDTH | DSDESC_HEIGHT;
1021 s_dsc.pixelformat = format;
1025 ret = dfbvideosink->dfb->CreateSurface (dfbvideosink->dfb, &s_dsc, &surface);
1026 if (ret != DFB_OK) {
1027 GST_WARNING_OBJECT (dfbvideosink, "failed creating surface with format %s",
1028 gst_dfbvideosink_get_format_name (format));
1032 /* Backup layer configuration */
1033 ret = dfbvideosink->layer->GetConfiguration (dfbvideosink->layer, &prev_dlc);
1034 if (ret != DFB_OK) {
1035 GST_WARNING_OBJECT (dfbvideosink, "failed when getting current layer "
1040 /* Test configuration of the layer to this pixel format */
1041 dlc.flags = DLCONF_PIXELFORMAT;
1042 dlc.pixelformat = format;
1044 ret = dfbvideosink->layer->TestConfiguration (dfbvideosink->layer, &dlc,
1046 if (ret != DFB_OK) {
1047 GST_DEBUG_OBJECT (dfbvideosink, "our layer refuses to operate in pixel "
1048 "format %s", gst_dfbvideosink_get_format_name (format));
1052 ret = dfbvideosink->layer->SetConfiguration (dfbvideosink->layer, &dlc);
1053 if (ret != DFB_OK) {
1054 GST_WARNING_OBJECT (dfbvideosink, "our layer refuses to operate in pixel "
1055 "format, though this format was successfully tested earlied %s",
1056 gst_dfbvideosink_get_format_name (format));
1060 ret = dfbvideosink->primary->GetAccelerationMask (dfbvideosink->primary,
1062 if (ret != DFB_OK) {
1063 GST_WARNING_OBJECT (dfbvideosink, "failed getting acceleration mask");
1067 /* Blitting from this format to our primary is accelerated */
1068 if (mask & DFXL_BLIT) {
1069 GST_DEBUG_OBJECT (dfbvideosink, "blitting from format %s to our primary "
1070 "is accelerated", gst_dfbvideosink_get_format_name (format));
1073 GST_DEBUG_OBJECT (dfbvideosink, "blitting from format %s to our primary "
1074 "is not accelerated", gst_dfbvideosink_get_format_name (format));
1078 /* Restore original layer configuration */
1079 ret = dfbvideosink->layer->SetConfiguration (dfbvideosink->layer, &prev_dlc);
1080 if (ret != DFB_OK) {
1081 GST_WARNING_OBJECT (dfbvideosink, "failed when restoring layer "
1088 surface->Release (surface);
1094 gst_dfbvideosink_get_best_vmode (GstDfbVideoSink * dfbvideosink, gint v_width,
1095 gint v_height, GstDfbVMode * best_vmode)
1097 GSList *walk = NULL;
1098 gboolean ret = FALSE;
1099 gint width, height, bpp;
1100 GstDfbVMode *vmode = NULL;
1102 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink), FALSE);
1104 if (!dfbvideosink->vmodes) {
1108 walk = dfbvideosink->vmodes;
1110 vmode = (GstDfbVMode *) walk->data;
1113 width = vmode->width;
1114 height = vmode->height;
1118 gint wgap, hgap, best_wgap, best_hgap;
1120 vmode = (GstDfbVMode *) walk->data;
1122 /* What are the gaps */
1123 wgap = abs (vmode->width - v_width);
1124 hgap = abs (vmode->height - v_height);
1125 best_wgap = abs (width - v_width);
1126 best_hgap = abs (height - v_height);
1128 /* If this mode is better we ll use that */
1129 if (wgap + hgap < best_wgap + best_hgap) {
1130 width = vmode->width;
1131 height = vmode->height;
1135 walk = g_slist_next (walk);
1138 GST_DEBUG_OBJECT (dfbvideosink, "found video mode %dx%d for input at %dx%d",
1139 width, height, v_width, v_height);
1141 best_vmode->width = width;
1142 best_vmode->height = height;
1143 best_vmode->bpp = bpp;
1152 gst_dfbvideosink_getcaps (GstBaseSink * bsink)
1154 GstDfbVideoSink *dfbvideosink;
1155 GstCaps *caps = NULL;
1158 dfbvideosink = GST_DFBVIDEOSINK (bsink);
1160 if (!dfbvideosink->setup) {
1161 caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
1163 GST_DEBUG_OBJECT (dfbvideosink, "getcaps called and we are not setup yet, "
1164 "returning template %" GST_PTR_FORMAT, caps);
1167 GST_DEBUG_OBJECT (dfbvideosink, "getcaps called, checking our internal "
1169 if (dfbvideosink->ext_surface) {
1170 /* We are not rendering to our own surface, returning this surface's
1172 caps = gst_dfbvideosink_get_caps_from_format (dfbvideosink->pixel_format);
1174 /* Try some formats */
1175 caps = gst_caps_new_empty ();
1177 if (gst_dfbvideosink_can_blit_from_format (dfbvideosink, DSPF_RGB16)) {
1178 gst_caps_append (caps,
1179 gst_dfbvideosink_get_caps_from_format (DSPF_RGB16));
1181 if (gst_dfbvideosink_can_blit_from_format (dfbvideosink, DSPF_RGB24)) {
1182 gst_caps_append (caps,
1183 gst_dfbvideosink_get_caps_from_format (DSPF_RGB24));
1185 /* There's something wrong with RGB32, ffmpegcolorspace ?
1186 if (gst_dfbvideosink_can_blit_from_format (dfbvideosink, DSPF_RGB32)) {
1187 gst_caps_append (caps,
1188 gst_dfbvideosink_get_caps_from_format (DSPF_RGB32));
1190 if (gst_dfbvideosink_can_blit_from_format (dfbvideosink, DSPF_ARGB)) {
1191 gst_caps_append (caps,
1192 gst_dfbvideosink_get_caps_from_format (DSPF_ARGB));
1194 if (gst_dfbvideosink_can_blit_from_format (dfbvideosink, DSPF_YUY2)) {
1195 gst_caps_append (caps,
1196 gst_dfbvideosink_get_caps_from_format (DSPF_YUY2));
1198 if (gst_dfbvideosink_can_blit_from_format (dfbvideosink, DSPF_UYVY)) {
1199 gst_caps_append (caps,
1200 gst_dfbvideosink_get_caps_from_format (DSPF_UYVY));
1202 if (gst_dfbvideosink_can_blit_from_format (dfbvideosink, DSPF_I420)) {
1203 gst_caps_append (caps,
1204 gst_dfbvideosink_get_caps_from_format (DSPF_I420));
1206 if (gst_dfbvideosink_can_blit_from_format (dfbvideosink, DSPF_YV12)) {
1207 gst_caps_append (caps,
1208 gst_dfbvideosink_get_caps_from_format (DSPF_YV12));
1213 for (i = 0; i < gst_caps_get_size (caps); i++) {
1214 GstStructure *structure = gst_caps_get_structure (caps, i);
1216 gst_structure_set (structure,
1217 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1218 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1219 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1221 if (!dfbvideosink->hw_scaling && dfbvideosink->par) {
1224 nom = gst_value_get_fraction_numerator (dfbvideosink->par);
1225 den = gst_value_get_fraction_denominator (dfbvideosink->par);
1226 gst_structure_set (structure, "pixel-aspect-ratio",
1227 GST_TYPE_FRACTION, nom, den, NULL);
1231 GST_DEBUG_OBJECT (dfbvideosink, "returning our caps %" GST_PTR_FORMAT, caps);
1238 gst_dfbvideosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
1240 GstDfbVideoSink *dfbvideosink;
1241 GstStructure *structure;
1242 gboolean res, result = FALSE;
1243 gint video_width, video_height;
1244 const GValue *framerate;
1245 DFBSurfacePixelFormat pixel_format = DSPF_UNKNOWN;
1247 dfbvideosink = GST_DFBVIDEOSINK (bsink);
1249 structure = gst_caps_get_structure (caps, 0);
1250 res = gst_structure_get_int (structure, "width", &video_width);
1251 res &= gst_structure_get_int (structure, "height", &video_height);
1252 framerate = gst_structure_get_value (structure, "framerate");
1253 res &= (framerate != NULL);
1258 dfbvideosink->fps_n = gst_value_get_fraction_numerator (framerate);
1259 dfbvideosink->fps_d = gst_value_get_fraction_denominator (framerate);
1261 pixel_format = gst_dfbvideosink_get_format_from_caps (caps);
1263 GST_DEBUG_OBJECT (dfbvideosink, "setcaps called with %" GST_PTR_FORMAT, caps);
1264 GST_DEBUG_OBJECT (dfbvideosink, "our format is: %dx%d %s video at %d/%d fps",
1265 video_width, video_height,
1266 gst_dfbvideosink_get_format_name (pixel_format), dfbvideosink->fps_n,
1267 dfbvideosink->fps_d);
1269 if (dfbvideosink->hw_scaling && dfbvideosink->par) {
1270 gint video_par_n, video_par_d; /* video's PAR */
1271 gint display_par_n, display_par_d; /* display's PAR */
1273 GValue display_ratio = { 0, }; /* display w/h ratio */
1274 const GValue *caps_par;
1276 /* get aspect ratio from caps if it's present, and
1277 * convert video width and height to a display width and height
1278 * using wd / hd = wv / hv * PARv / PARd
1279 * the ratio wd / hd will be stored in display_ratio */
1280 g_value_init (&display_ratio, GST_TYPE_FRACTION);
1282 /* get video's PAR */
1283 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
1285 video_par_n = gst_value_get_fraction_numerator (caps_par);
1286 video_par_d = gst_value_get_fraction_denominator (caps_par);
1291 /* get display's PAR */
1292 if (dfbvideosink->par) {
1293 display_par_n = gst_value_get_fraction_numerator (dfbvideosink->par);
1294 display_par_d = gst_value_get_fraction_denominator (dfbvideosink->par);
1300 gst_value_set_fraction (&display_ratio,
1301 video_width * video_par_n * display_par_d,
1302 video_height * video_par_d * display_par_n);
1304 num = gst_value_get_fraction_numerator (&display_ratio);
1305 den = gst_value_get_fraction_denominator (&display_ratio);
1306 GST_DEBUG_OBJECT (dfbvideosink,
1307 "video width/height: %dx%d, calculated display ratio: %d/%d",
1308 video_width, video_height, num, den);
1310 /* now find a width x height that respects this display ratio.
1311 * prefer those that have one of w/h the same as the incoming video
1312 * using wd / hd = num / den */
1314 /* start with same height, because of interlaced video */
1315 /* check hd / den is an integer scale factor, and scale wd with the PAR */
1316 if (video_height % den == 0) {
1317 GST_DEBUG_OBJECT (dfbvideosink, "keeping video height");
1318 GST_VIDEO_SINK_WIDTH (dfbvideosink) = video_height * num / den;
1319 GST_VIDEO_SINK_HEIGHT (dfbvideosink) = video_height;
1320 } else if (video_width % num == 0) {
1321 GST_DEBUG_OBJECT (dfbvideosink, "keeping video width");
1322 GST_VIDEO_SINK_WIDTH (dfbvideosink) = video_width;
1323 GST_VIDEO_SINK_HEIGHT (dfbvideosink) = video_width * den / num;
1325 GST_DEBUG_OBJECT (dfbvideosink, "approximating while keeping height");
1326 GST_VIDEO_SINK_WIDTH (dfbvideosink) = video_height * num / den;
1327 GST_VIDEO_SINK_HEIGHT (dfbvideosink) = video_height;
1329 GST_DEBUG_OBJECT (dfbvideosink, "scaling to %dx%d",
1330 GST_VIDEO_SINK_WIDTH (dfbvideosink),
1331 GST_VIDEO_SINK_HEIGHT (dfbvideosink));
1333 if (dfbvideosink->par) {
1336 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
1338 if (gst_value_compare (par, dfbvideosink->par) != GST_VALUE_EQUAL) {
1343 GST_VIDEO_SINK_WIDTH (dfbvideosink) = video_width;
1344 GST_VIDEO_SINK_HEIGHT (dfbvideosink) = video_height;
1347 /* Try to adapt the video mode to the video geometry */
1348 if (dfbvideosink->dfb) {
1352 GST_DEBUG_OBJECT (dfbvideosink, "trying to adapt the video mode to video "
1355 /* Set video mode and layer configuration appropriately */
1356 if (gst_dfbvideosink_get_best_vmode (dfbvideosink,
1357 GST_VIDEO_SINK_WIDTH (dfbvideosink),
1358 GST_VIDEO_SINK_HEIGHT (dfbvideosink), &vmode)) {
1359 DFBDisplayLayerConfig lc;
1360 gint width, height, bpp;
1362 width = vmode.width;
1363 height = vmode.height;
1366 GST_DEBUG_OBJECT (dfbvideosink, "setting video mode to %dx%d at %d bpp",
1367 width, height, bpp);
1369 ret = dfbvideosink->dfb->SetVideoMode (dfbvideosink->dfb, width,
1371 if (ret != DFB_OK) {
1372 GST_WARNING_OBJECT (dfbvideosink, "failed setting video mode %dx%d "
1373 "at %d bpp", width, height, bpp);
1376 lc.flags = DLCONF_PIXELFORMAT;
1377 lc.pixelformat = pixel_format;
1379 ret = dfbvideosink->layer->SetConfiguration (dfbvideosink->layer, &lc);
1380 if (ret != DFB_OK) {
1381 GST_WARNING_OBJECT (dfbvideosink, "failed setting layer pixelformat "
1382 "to %s", gst_dfbvideosink_get_format_name (pixel_format));
1384 dfbvideosink->layer->GetConfiguration (dfbvideosink->layer, &lc);
1385 dfbvideosink->out_width = lc.width;
1386 dfbvideosink->out_height = lc.height;
1387 dfbvideosink->pixel_format = lc.pixelformat;
1388 GST_DEBUG_OBJECT (dfbvideosink, "layer %d now configured to %dx%d %s",
1389 dfbvideosink->layer_id, lc.width, lc.height,
1390 gst_dfbvideosink_get_format_name (lc.pixelformat));
1395 if (pixel_format != dfbvideosink->pixel_format) {
1396 GST_WARNING_OBJECT (dfbvideosink, "setcaps sent us a different pixel "
1397 "format %s", gst_dfbvideosink_get_format_name (pixel_format));
1401 dfbvideosink->video_width = video_width;
1402 dfbvideosink->video_height = video_height;
1412 GST_INFO_OBJECT (dfbvideosink, "pixel aspect ratio does not match");
1417 static GstStateChangeReturn
1418 gst_dfbvideosink_change_state (GstElement * element, GstStateChange transition)
1420 GstDfbVideoSink *dfbvideosink;
1421 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1423 dfbvideosink = GST_DFBVIDEOSINK (element);
1425 switch (transition) {
1426 case GST_STATE_CHANGE_NULL_TO_READY:
1427 dfbvideosink->running = TRUE;
1428 if (!dfbvideosink->setup) {
1429 if (!gst_dfbvideosink_setup (dfbvideosink)) {
1430 GST_DEBUG_OBJECT (dfbvideosink, "setup failed when changing state "
1431 "from NULL to READY");
1432 GST_ELEMENT_ERROR (dfbvideosink, RESOURCE, OPEN_WRITE,
1433 (NULL), ("Failed initializing DirectFB system"));
1434 return GST_STATE_CHANGE_FAILURE;
1438 case GST_STATE_CHANGE_READY_TO_PAUSED:
1439 /* Blank surface if we have one */
1440 if (dfbvideosink->ext_surface) {
1441 dfbvideosink->ext_surface->Clear (dfbvideosink->ext_surface,
1442 0x00, 0x00, 0x00, 0xFF);
1444 if (dfbvideosink->primary) {
1445 dfbvideosink->primary->Clear (dfbvideosink->primary, 0x00, 0x00,
1449 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1455 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1456 if (ret == GST_STATE_CHANGE_FAILURE)
1459 switch (transition) {
1460 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1462 case GST_STATE_CHANGE_PAUSED_TO_READY:
1463 dfbvideosink->fps_d = 0;
1464 dfbvideosink->fps_n = 0;
1465 dfbvideosink->video_width = 0;
1466 dfbvideosink->video_height = 0;
1468 if (dfbvideosink->buffer_pool) {
1469 gst_dfbvideosink_bufferpool_clear (dfbvideosink);
1472 case GST_STATE_CHANGE_READY_TO_NULL:
1473 dfbvideosink->running = FALSE;
1474 if (dfbvideosink->setup) {
1475 gst_dfbvideosink_cleanup (dfbvideosink);
1486 gst_dfbvideosink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1487 GstClockTime * start, GstClockTime * end)
1489 GstDfbVideoSink *dfbvideosink;
1491 dfbvideosink = GST_DFBVIDEOSINK (bsink);
1493 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1494 *start = GST_BUFFER_TIMESTAMP (buf);
1495 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1496 *end = *start + GST_BUFFER_DURATION (buf);
1498 if (dfbvideosink->fps_n > 0) {
1500 *start + (GST_SECOND * dfbvideosink->fps_d) / dfbvideosink->fps_n;
1506 static GstFlowReturn
1507 gst_dfbvideosink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
1509 GstDfbVideoSink *dfbvideosink = NULL;
1511 GstVideoRectangle dst, src, result;
1512 GstFlowReturn ret = GST_FLOW_OK;
1513 gboolean mem_cpy = TRUE;
1515 dfbvideosink = GST_DFBVIDEOSINK (bsink);
1517 if (!dfbvideosink->setup) {
1518 ret = GST_FLOW_UNEXPECTED;
1522 /* Is that a buffer we allocated ourselves ? */
1523 if (GST_IS_DFBSURFACE (buf)) {
1524 GstDfbSurface *tmp_surface = GST_DFBSURFACE (buf);
1526 /* Does it have a surface ? */
1527 if (tmp_surface->surface) {
1529 GST_DEBUG_OBJECT (dfbvideosink, "we have a buffer (%p) we allocated "
1530 "ourselves and it has a surface, no memcpy then", buf);
1532 /* No surface, that's a malloc */
1533 GST_DEBUG_OBJECT (dfbvideosink, "we have a buffer (%p) we allocated "
1534 "ourselves but it does not hold a surface", buf);
1538 GST_DEBUG_OBJECT (dfbvideosink, "we have a buffer (%p) we did not allocate",
1543 IDirectFBSurface *dest = NULL, *surface = NULL;
1545 gint dest_pitch, src_pitch, line;
1546 GstStructure *structure;
1548 /* As we are not blitting no acceleration is possible. If the surface is
1549 * too small we do clipping, if it's too big we center. Theoretically as
1550 * we are using buffer_alloc, there's a chance that we have been able to
1551 * do reverse caps negotiation */
1553 if (dfbvideosink->ext_surface) {
1554 surface = dfbvideosink->ext_surface;
1555 GST_DEBUG_OBJECT (dfbvideosink, "memcpy to an external surface "
1556 "subsurface (vsync %d)", dfbvideosink->vsync);
1558 surface = dfbvideosink->primary;
1559 GST_DEBUG_OBJECT (dfbvideosink, "memcpy to a primary subsurface "
1560 "(vsync %d)", dfbvideosink->vsync);
1563 /* Get the video frame geometry from the buffer caps */
1564 structure = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
1566 gst_structure_get_int (structure, "width", &src.w);
1567 gst_structure_get_int (structure, "height", &src.h);
1569 src.w = dfbvideosink->video_width;
1570 src.h = dfbvideosink->video_height;
1572 res = surface->GetSize (surface, &dst.w, &dst.h);
1575 gst_video_sink_center_rect (src, dst, &result, FALSE);
1578 surface->GetSubSurface (surface, (DFBRectangle *) (void *) &result,
1580 if (res != DFB_OK) {
1581 GST_WARNING_OBJECT (dfbvideosink, "failed when getting a sub surface");
1582 ret = GST_FLOW_UNEXPECTED;
1586 /* If we are not using Flip we wait for VSYNC before blit */
1587 if (!dfbvideosink->backbuffer && dfbvideosink->vsync) {
1588 dfbvideosink->layer->WaitForSync (dfbvideosink->layer);
1591 res = dest->Lock (dest, DSLF_WRITE, &data, &dest_pitch);
1592 if (res != DFB_OK) {
1593 GST_WARNING_OBJECT (dfbvideosink, "failed locking the external "
1594 "subsurface for writing");
1595 ret = GST_FLOW_ERROR;
1599 /* Source video rowbytes */
1600 src_pitch = GST_BUFFER_SIZE (buf) / src.h;
1602 /* Write each line respecting subsurface pitch */
1603 for (line = 0; line < result.h; line++) {
1604 /* We do clipping */
1605 memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch),
1606 MIN (src_pitch, dest_pitch));
1610 res = dest->Unlock (dest);
1612 res = dest->Release (dest);
1614 if (dfbvideosink->backbuffer) {
1615 if (dfbvideosink->vsync) {
1616 res = surface->Flip (surface, NULL, DSFLIP_ONSYNC);
1618 res = surface->Flip (surface, NULL, DSFLIP_NONE);
1622 /* Else we will [Stretch]Blit to our primary */
1623 GstDfbSurface *surface = GST_DFBSURFACE (buf);
1625 GST_DEBUG_OBJECT (dfbvideosink, "blitting to a primary surface (vsync %d)",
1626 dfbvideosink->vsync);
1628 src.w = GST_VIDEO_SINK_WIDTH (dfbvideosink);
1629 src.h = GST_VIDEO_SINK_HEIGHT (dfbvideosink);
1631 dfbvideosink->primary->GetSize (dfbvideosink->primary, &dst.w, &dst.h);
1633 /* Unlocking surface before blit */
1634 if (surface->locked) {
1635 surface->surface->Unlock (surface->surface);
1636 surface->locked = FALSE;
1639 gst_video_sink_center_rect (src, dst, &result, dfbvideosink->hw_scaling);
1641 /* If we are not using Flip we wait for VSYNC before blit */
1642 if (!dfbvideosink->backbuffer && dfbvideosink->vsync) {
1643 dfbvideosink->layer->WaitForSync (dfbvideosink->layer);
1646 if (dfbvideosink->hw_scaling) {
1647 dfbvideosink->primary->StretchBlit (dfbvideosink->primary,
1648 surface->surface, NULL, (DFBRectangle *) (void *) &result);
1652 clip.x = clip.y = 0;
1655 dfbvideosink->primary->Blit (dfbvideosink->primary, surface->surface,
1656 &clip, result.x, result.y);
1659 if (dfbvideosink->backbuffer) {
1660 if (dfbvideosink->vsync) {
1661 dfbvideosink->primary->Flip (dfbvideosink->primary, NULL,
1664 dfbvideosink->primary->Flip (dfbvideosink->primary, NULL, DSFLIP_NONE);
1674 gst_dfbvideosink_bufferpool_clear (GstDfbVideoSink * dfbvideosink)
1676 g_mutex_lock (dfbvideosink->pool_lock);
1677 while (dfbvideosink->buffer_pool) {
1678 GstDfbSurface *surface = dfbvideosink->buffer_pool->data;
1680 dfbvideosink->buffer_pool = g_slist_delete_link (dfbvideosink->buffer_pool,
1681 dfbvideosink->buffer_pool);
1682 gst_dfbvideosink_surface_destroy (dfbvideosink, surface);
1684 g_mutex_unlock (dfbvideosink->pool_lock);
1687 /* For every buffer request we create a custom buffer containing and
1688 * IDirectFBSurface or allocate a previously created one that's not used
1690 static GstFlowReturn
1691 gst_dfbvideosink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
1692 GstCaps * caps, GstBuffer ** buf)
1694 GstDfbVideoSink *dfbvideosink;
1695 GstDfbSurface *surface = NULL;
1696 GstFlowReturn ret = GST_FLOW_OK;
1698 gboolean rev_nego = FALSE;
1701 GstCaps *desired_caps = NULL;
1702 GstStructure *structure = NULL;
1704 dfbvideosink = GST_DFBVIDEOSINK (bsink);
1706 GST_DEBUG_OBJECT (dfbvideosink, "a buffer of %d bytes was requested "
1707 "with caps %" GST_PTR_FORMAT " and offset %llu", size, caps, offset);
1709 if (G_UNLIKELY (!dfbvideosink->setup)) {
1710 GST_DEBUG_OBJECT (dfbvideosink, "we are not setup yet, can't allocate!");
1715 desired_caps = gst_caps_copy (caps);
1717 structure = gst_caps_get_structure (desired_caps, 0);
1719 if (gst_structure_get_int (structure, "width", &width) &&
1720 gst_structure_get_int (structure, "height", &height)) {
1721 GstVideoRectangle dst, src, result;
1724 /* If we can do hardware scaling we don't do reverse negotiation */
1725 if (dfbvideosink->hw_scaling) {
1729 /* Our desired geometry respects aspect ratio */
1732 /* We should adapt the destination to the most suitable video mode */
1733 if (gst_dfbvideosink_get_best_vmode (dfbvideosink, width, height, &vmode)) {
1734 dst.w = vmode.width;
1735 dst.h = vmode.height;
1737 if (dfbvideosink->ext_surface) {
1738 dfbvideosink->ext_surface->GetSize (dfbvideosink->ext_surface, &dst.w,
1741 dfbvideosink->primary->GetSize (dfbvideosink->primary, &dst.w, &dst.h);
1743 dfbvideosink->out_width = dst.w;
1744 dfbvideosink->out_height = dst.h;
1747 gst_video_sink_center_rect (src, dst, &result, TRUE);
1749 if (width != result.w || height != result.h) {
1750 GstPad *peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (dfbvideosink));
1752 if (!GST_IS_PAD (peer)) {
1753 /* Is this situation possible ? */
1757 GST_DEBUG_OBJECT (dfbvideosink, "we would love to receive a %dx%d video",
1758 result.w, result.h);
1759 gst_structure_set (structure, "width", G_TYPE_INT, result.w, NULL);
1760 gst_structure_set (structure, "height", G_TYPE_INT, result.h, NULL);
1762 /* PAR property overrides the X calculated one */
1763 if (dfbvideosink->par) {
1766 nom = gst_value_get_fraction_numerator (dfbvideosink->par);
1767 den = gst_value_get_fraction_denominator (dfbvideosink->par);
1768 gst_structure_set (structure, "pixel-aspect-ratio",
1769 GST_TYPE_FRACTION, nom, den, NULL);
1772 if (gst_pad_accept_caps (peer, desired_caps)) {
1775 bpp = size / height / width;
1779 size = bpp * width * height;
1780 GST_DEBUG_OBJECT (dfbvideosink, "peed pad accepts our desired caps %"
1781 GST_PTR_FORMAT " buffer size is now %d bytes", desired_caps, size);
1783 GST_DEBUG_OBJECT (dfbvideosink, "peer pad does not accept our "
1784 "desired caps %" GST_PTR_FORMAT, desired_caps);
1786 width = dfbvideosink->video_width;
1787 height = dfbvideosink->video_height;
1789 gst_object_unref (peer);
1794 /* Inspect our buffer pool */
1795 g_mutex_lock (dfbvideosink->pool_lock);
1796 while (dfbvideosink->buffer_pool) {
1797 surface = (GstDfbSurface *) dfbvideosink->buffer_pool->data;
1800 /* Removing from the pool */
1801 dfbvideosink->buffer_pool =
1802 g_slist_delete_link (dfbvideosink->buffer_pool,
1803 dfbvideosink->buffer_pool);
1805 /* If the surface is invalid for our need, destroy */
1806 if ((surface->width != width) ||
1807 (surface->height != height) ||
1808 (surface->pixel_format != dfbvideosink->pixel_format)) {
1809 gst_dfbvideosink_surface_destroy (dfbvideosink, surface);
1812 /* We found a suitable surface */
1817 g_mutex_unlock (dfbvideosink->pool_lock);
1819 /* We haven't found anything, creating a new one */
1822 surface = gst_dfbvideosink_surface_create (dfbvideosink, desired_caps,
1825 surface = gst_dfbvideosink_surface_create (dfbvideosink, caps, size);
1828 /* Now we should have a surface, set appropriate caps on it */
1831 gst_buffer_set_caps (GST_BUFFER (surface), desired_caps);
1833 gst_buffer_set_caps (GST_BUFFER (surface), caps);
1837 *buf = GST_BUFFER (surface);
1839 gst_caps_unref (desired_caps);
1844 /* Our subclass of GstBuffer */
1847 gst_dfbsurface_finalize (GstDfbSurface * surface)
1849 GstDfbVideoSink *dfbvideosink = NULL;
1851 g_return_if_fail (surface != NULL);
1853 dfbvideosink = surface->dfbvideosink;
1854 if (!dfbvideosink) {
1855 GST_WARNING_OBJECT (surface, "no sink found");
1859 /* If our geometry changed we can't reuse that image. */
1860 if ((surface->width != dfbvideosink->video_width) ||
1861 (surface->height != dfbvideosink->video_height) ||
1862 (surface->pixel_format != dfbvideosink->pixel_format)) {
1863 GST_DEBUG_OBJECT (dfbvideosink, "destroy surface %p as its size changed "
1864 "%dx%d vs current %dx%d", surface, surface->width, surface->height,
1865 dfbvideosink->video_width, dfbvideosink->video_height);
1866 gst_dfbvideosink_surface_destroy (dfbvideosink, surface);
1868 /* In that case we can reuse the image and add it to our image pool. */
1869 GST_DEBUG_OBJECT (dfbvideosink, "recycling surface %p in pool", surface);
1870 /* need to increment the refcount again to recycle */
1871 gst_buffer_ref (GST_BUFFER (surface));
1872 g_mutex_lock (dfbvideosink->pool_lock);
1873 dfbvideosink->buffer_pool = g_slist_prepend (dfbvideosink->buffer_pool,
1875 g_mutex_unlock (dfbvideosink->pool_lock);
1883 gst_dfbsurface_init (GstDfbSurface * surface, gpointer g_class)
1885 surface->surface = NULL;
1887 surface->height = 0;
1888 surface->pixel_format = DSPF_UNKNOWN;
1889 surface->dfbvideosink = NULL;
1893 gst_dfbsurface_class_init (gpointer g_class, gpointer class_data)
1895 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
1897 surface_parent_class = g_type_class_peek_parent (g_class);
1899 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
1900 gst_dfbsurface_finalize;
1904 gst_dfbsurface_get_type (void)
1906 static GType _gst_dfbsurface_type;
1908 if (G_UNLIKELY (_gst_dfbsurface_type == 0)) {
1909 static const GTypeInfo dfbsurface_info = {
1910 sizeof (GstBufferClass),
1913 gst_dfbsurface_class_init,
1916 sizeof (GstDfbSurface),
1918 (GInstanceInitFunc) gst_dfbsurface_init,
1921 _gst_dfbsurface_type = g_type_register_static (GST_TYPE_BUFFER,
1922 "GstDfbSurface", &dfbsurface_info, 0);
1924 return _gst_dfbsurface_type;
1927 /* Interfaces stuff */
1930 gst_dfbvideosink_interface_supported (GstImplementsInterface * iface,
1933 g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE);
1938 gst_dfbvideosink_interface_init (GstImplementsInterfaceClass * klass)
1940 klass->supported = gst_dfbvideosink_interface_supported;
1944 gst_dfbvideosink_navigation_send_event (GstNavigation * navigation,
1945 GstStructure * structure)
1947 GstDfbVideoSink *dfbvideosink = GST_DFBVIDEOSINK (navigation);
1949 GstVideoRectangle src, dst, result;
1953 src.w = GST_VIDEO_SINK_WIDTH (dfbvideosink);
1954 src.h = GST_VIDEO_SINK_HEIGHT (dfbvideosink);
1955 dst.w = dfbvideosink->out_width;
1956 dst.h = dfbvideosink->out_height;
1957 gst_video_sink_center_rect (src, dst, &result, dfbvideosink->hw_scaling);
1959 event = gst_event_new_navigation (structure);
1961 /* Our coordinates can be wrong here if we centered the video */
1963 /* Converting pointer coordinates to the non scaled geometry */
1964 if (gst_structure_get_double (structure, "pointer_x", &x)) {
1967 if (x >= result.x && x <= (result.x + result.w)) {
1969 x *= dfbvideosink->video_width;
1974 GST_DEBUG_OBJECT (dfbvideosink, "translated navigation event x "
1975 "coordinate from %f to %f", old_x, x);
1976 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL);
1978 if (gst_structure_get_double (structure, "pointer_y", &y)) {
1981 if (y >= result.y && y <= (result.y + result.h)) {
1983 y *= dfbvideosink->video_height;
1988 GST_DEBUG_OBJECT (dfbvideosink, "translated navigation event y "
1989 "coordinate from %fd to %fd", old_y, y);
1990 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL);
1993 pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (dfbvideosink));
1995 if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
1996 gst_pad_send_event (pad, event);
1998 gst_object_unref (pad);
2003 gst_dfbvideosink_navigation_init (GstNavigationInterface * iface)
2005 iface->send_event = gst_dfbvideosink_navigation_send_event;
2009 gst_dfbvideosink_update_colorbalance (GstDfbVideoSink * dfbvideosink)
2011 g_return_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink));
2013 if (dfbvideosink->layer) {
2014 DFBColorAdjustment cb_adjust;
2016 cb_adjust.flags = DCAF_NONE;
2018 if (dfbvideosink->brightness >= 0) {
2019 cb_adjust.flags |= DCAF_BRIGHTNESS;
2021 if (dfbvideosink->contrast >= 0) {
2022 cb_adjust.flags |= DCAF_CONTRAST;
2024 if (dfbvideosink->hue >= 0) {
2025 cb_adjust.flags |= DCAF_HUE;
2027 if (dfbvideosink->saturation >= 0) {
2028 cb_adjust.flags |= DCAF_SATURATION;
2031 cb_adjust.brightness = dfbvideosink->brightness;
2032 cb_adjust.contrast = dfbvideosink->contrast;
2033 cb_adjust.hue = dfbvideosink->hue;
2034 cb_adjust.saturation = dfbvideosink->saturation;
2036 GST_DEBUG_OBJECT (dfbvideosink, "updating colorbalance: flags %d "
2037 "brightness %d contrast %d hue %d saturation %d", cb_adjust.flags,
2038 cb_adjust.brightness, cb_adjust.contrast, cb_adjust.hue,
2039 cb_adjust.saturation);
2040 dfbvideosink->layer->SetColorAdjustment (dfbvideosink->layer, &cb_adjust);
2044 static const GList *
2045 gst_dfbvideosink_colorbalance_list_channels (GstColorBalance * balance)
2047 GstDfbVideoSink *dfbvideosink = GST_DFBVIDEOSINK (balance);
2049 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink), NULL);
2051 return dfbvideosink->cb_channels;
2055 gst_dfbvideosink_colorbalance_set_value (GstColorBalance * balance,
2056 GstColorBalanceChannel * channel, gint value)
2058 GstDfbVideoSink *dfbvideosink = GST_DFBVIDEOSINK (balance);
2060 g_return_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink));
2061 g_return_if_fail (channel->label != NULL);
2063 dfbvideosink->cb_changed = TRUE;
2065 if (g_ascii_strcasecmp (channel->label, "HUE") == 0) {
2066 dfbvideosink->hue = value;
2067 } else if (g_ascii_strcasecmp (channel->label, "SATURATION") == 0) {
2068 dfbvideosink->saturation = value;
2069 } else if (g_ascii_strcasecmp (channel->label, "CONTRAST") == 0) {
2070 dfbvideosink->contrast = value;
2071 } else if (g_ascii_strcasecmp (channel->label, "BRIGHTNESS") == 0) {
2072 dfbvideosink->brightness = value;
2074 GST_WARNING_OBJECT (dfbvideosink, "got an unknown channel %s",
2079 gst_dfbvideosink_update_colorbalance (dfbvideosink);
2083 gst_dfbvideosink_colorbalance_get_value (GstColorBalance * balance,
2084 GstColorBalanceChannel * channel)
2086 GstDfbVideoSink *dfbvideosink = GST_DFBVIDEOSINK (balance);
2089 g_return_val_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink), 0);
2090 g_return_val_if_fail (channel->label != NULL, 0);
2092 if (g_ascii_strcasecmp (channel->label, "HUE") == 0) {
2093 value = dfbvideosink->hue;
2094 } else if (g_ascii_strcasecmp (channel->label, "SATURATION") == 0) {
2095 value = dfbvideosink->saturation;
2096 } else if (g_ascii_strcasecmp (channel->label, "CONTRAST") == 0) {
2097 value = dfbvideosink->contrast;
2098 } else if (g_ascii_strcasecmp (channel->label, "BRIGHTNESS") == 0) {
2099 value = dfbvideosink->brightness;
2101 GST_WARNING_OBJECT (dfbvideosink, "got an unknown channel %s",
2109 gst_dfbvideosink_colorbalance_init (GstColorBalanceClass * iface)
2111 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
2112 iface->list_channels = gst_dfbvideosink_colorbalance_list_channels;
2113 iface->set_value = gst_dfbvideosink_colorbalance_set_value;
2114 iface->get_value = gst_dfbvideosink_colorbalance_get_value;
2120 gst_dfbvideosink_set_property (GObject * object, guint prop_id,
2121 const GValue * value, GParamSpec * pspec)
2123 GstDfbVideoSink *dfbvideosink;
2125 g_return_if_fail (GST_IS_DFBVIDEOSINK (object));
2126 dfbvideosink = GST_DFBVIDEOSINK (object);
2130 dfbvideosink->ext_surface = g_value_get_pointer (value);
2133 dfbvideosink->hue = g_value_get_int (value);
2134 dfbvideosink->cb_changed = TRUE;
2135 gst_dfbvideosink_update_colorbalance (dfbvideosink);
2138 dfbvideosink->contrast = g_value_get_int (value);
2139 dfbvideosink->cb_changed = TRUE;
2140 gst_dfbvideosink_update_colorbalance (dfbvideosink);
2142 case ARG_BRIGHTNESS:
2143 dfbvideosink->brightness = g_value_get_int (value);
2144 dfbvideosink->cb_changed = TRUE;
2145 gst_dfbvideosink_update_colorbalance (dfbvideosink);
2147 case ARG_SATURATION:
2148 dfbvideosink->saturation = g_value_get_int (value);
2149 dfbvideosink->cb_changed = TRUE;
2150 gst_dfbvideosink_update_colorbalance (dfbvideosink);
2152 case ARG_PIXEL_ASPECT_RATIO:
2153 g_free (dfbvideosink->par);
2154 dfbvideosink->par = g_new0 (GValue, 1);
2155 g_value_init (dfbvideosink->par, GST_TYPE_FRACTION);
2156 if (!g_value_transform (value, dfbvideosink->par)) {
2157 GST_WARNING_OBJECT (dfbvideosink, "Could not transform string to "
2159 gst_value_set_fraction (dfbvideosink->par, 1, 1);
2161 GST_DEBUG_OBJECT (dfbvideosink, "set PAR to %d/%d",
2162 gst_value_get_fraction_numerator (dfbvideosink->par),
2163 gst_value_get_fraction_denominator (dfbvideosink->par));
2166 dfbvideosink->vsync = g_value_get_boolean (value);
2169 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2175 gst_dfbvideosink_get_property (GObject * object, guint prop_id,
2176 GValue * value, GParamSpec * pspec)
2178 GstDfbVideoSink *dfbvideosink;
2180 g_return_if_fail (GST_IS_DFBVIDEOSINK (object));
2181 dfbvideosink = GST_DFBVIDEOSINK (object);
2185 g_value_set_int (value, dfbvideosink->hue);
2188 g_value_set_int (value, dfbvideosink->contrast);
2190 case ARG_BRIGHTNESS:
2191 g_value_set_int (value, dfbvideosink->brightness);
2193 case ARG_SATURATION:
2194 g_value_set_int (value, dfbvideosink->saturation);
2196 case ARG_PIXEL_ASPECT_RATIO:
2197 if (dfbvideosink->par)
2198 g_value_transform (dfbvideosink->par, value);
2201 g_value_set_boolean (value, dfbvideosink->vsync);
2204 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2209 /* =========================================== */
2211 /* Init & Class init */
2213 /* =========================================== */
2215 gst_dfbvideosink_finalize (GObject * object)
2217 GstDfbVideoSink *dfbvideosink;
2219 dfbvideosink = GST_DFBVIDEOSINK (object);
2221 if (dfbvideosink->par) {
2222 g_free (dfbvideosink->par);
2223 dfbvideosink->par = NULL;
2225 if (dfbvideosink->pool_lock) {
2226 g_mutex_free (dfbvideosink->pool_lock);
2227 dfbvideosink->pool_lock = NULL;
2229 if (dfbvideosink->setup) {
2230 gst_dfbvideosink_cleanup (dfbvideosink);
2233 G_OBJECT_CLASS (parent_class)->finalize (object);
2237 gst_dfbvideosink_init (GstDfbVideoSink * dfbvideosink)
2239 dfbvideosink->pool_lock = g_mutex_new ();
2240 dfbvideosink->buffer_pool = NULL;
2241 dfbvideosink->video_height = dfbvideosink->out_width = 0;
2242 dfbvideosink->video_width = dfbvideosink->out_height = 0;
2243 dfbvideosink->fps_d = 0;
2244 dfbvideosink->fps_n = 0;
2246 dfbvideosink->dfb = NULL;
2247 dfbvideosink->vmodes = NULL;
2248 dfbvideosink->layer_id = -1;
2249 dfbvideosink->layer = NULL;
2250 dfbvideosink->primary = NULL;
2251 dfbvideosink->event_buffer = NULL;
2252 dfbvideosink->event_thread = NULL;
2254 dfbvideosink->ext_surface = NULL;
2256 dfbvideosink->pixel_format = DSPF_UNKNOWN;
2258 dfbvideosink->hw_scaling = FALSE;
2259 dfbvideosink->backbuffer = FALSE;
2260 dfbvideosink->vsync = TRUE;
2261 dfbvideosink->setup = FALSE;
2262 dfbvideosink->running = FALSE;
2264 dfbvideosink->cb_channels = NULL;
2265 dfbvideosink->brightness = -1;
2266 dfbvideosink->contrast = -1;
2267 dfbvideosink->hue = -1;
2268 dfbvideosink->saturation = -1;
2270 dfbvideosink->par = NULL;
2274 gst_dfbvideosink_base_init (gpointer g_class)
2276 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
2278 gst_element_class_set_details (element_class, &gst_dfbvideosink_details);
2280 gst_element_class_add_pad_template (element_class,
2281 gst_static_pad_template_get (&gst_dfbvideosink_sink_template_factory));
2285 gst_dfbvideosink_class_init (GstDfbVideoSinkClass * klass)
2287 GObjectClass *gobject_class;
2288 GstElementClass *gstelement_class;
2289 GstBaseSinkClass *gstbasesink_class;
2291 gobject_class = (GObjectClass *) klass;
2292 gstelement_class = (GstElementClass *) klass;
2293 gstbasesink_class = (GstBaseSinkClass *) klass;
2295 parent_class = g_type_class_peek_parent (klass);
2297 gobject_class->finalize = gst_dfbvideosink_finalize;
2298 gobject_class->set_property = gst_dfbvideosink_set_property;
2299 gobject_class->get_property = gst_dfbvideosink_get_property;
2301 g_object_class_install_property (gobject_class, ARG_SURFACE,
2302 g_param_spec_pointer ("surface", "Surface",
2303 "The target surface for video", G_PARAM_WRITABLE));
2304 g_object_class_install_property (gobject_class, ARG_CONTRAST,
2305 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
2306 0x0000, 0xFFFF, 0x8000, G_PARAM_READWRITE));
2307 g_object_class_install_property (gobject_class, ARG_BRIGHTNESS,
2308 g_param_spec_int ("brightness", "Brightness",
2309 "The brightness of the video", 0x0000, 0xFFFF, 0x8000,
2310 G_PARAM_READWRITE));
2311 g_object_class_install_property (gobject_class, ARG_HUE,
2312 g_param_spec_int ("hue", "Hue", "The hue of the video", 0x0000, 0xFFFF,
2313 0x8000, G_PARAM_READWRITE));
2314 g_object_class_install_property (gobject_class, ARG_SATURATION,
2315 g_param_spec_int ("saturation", "Saturation",
2316 "The saturation of the video", 0x0000, 0xFFFF, 0x8000,
2317 G_PARAM_READWRITE));
2318 g_object_class_install_property (gobject_class, ARG_PIXEL_ASPECT_RATIO,
2319 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
2320 "The pixel aspect ratio of the device", "1/1", G_PARAM_READWRITE));
2321 g_object_class_install_property (gobject_class, ARG_VSYNC,
2322 g_param_spec_boolean ("vsync", "Vertical synchronisation",
2323 "Wait for next vertical sync to draw frames", TRUE,
2324 G_PARAM_READWRITE));
2326 gstelement_class->change_state = gst_dfbvideosink_change_state;
2328 gstbasesink_class->get_caps = gst_dfbvideosink_getcaps;
2329 gstbasesink_class->set_caps = gst_dfbvideosink_setcaps;
2330 gstbasesink_class->buffer_alloc = gst_dfbvideosink_buffer_alloc;
2331 gstbasesink_class->get_times = gst_dfbvideosink_get_times;
2332 gstbasesink_class->preroll = gst_dfbvideosink_show_frame;
2333 gstbasesink_class->render = gst_dfbvideosink_show_frame;
2336 /* ============================================================= */
2338 /* Public Methods */
2340 /* ============================================================= */
2342 /* =========================================== */
2344 /* Object typing & Creation */
2346 /* =========================================== */
2349 gst_dfbvideosink_get_type (void)
2351 static GType dfbvideosink_type = 0;
2353 if (!dfbvideosink_type) {
2354 static const GTypeInfo dfbvideosink_info = {
2355 sizeof (GstDfbVideoSinkClass),
2356 gst_dfbvideosink_base_init,
2358 (GClassInitFunc) gst_dfbvideosink_class_init,
2361 sizeof (GstDfbVideoSink),
2363 (GInstanceInitFunc) gst_dfbvideosink_init,
2365 static const GInterfaceInfo iface_info = {
2366 (GInterfaceInitFunc) gst_dfbvideosink_interface_init,
2370 static const GInterfaceInfo navigation_info = {
2371 (GInterfaceInitFunc) gst_dfbvideosink_navigation_init,
2375 static const GInterfaceInfo colorbalance_info = {
2376 (GInterfaceInitFunc) gst_dfbvideosink_colorbalance_init,
2381 dfbvideosink_type = g_type_register_static (GST_TYPE_VIDEO_SINK,
2382 "GstDfbVideoSink", &dfbvideosink_info, 0);
2384 g_type_add_interface_static (dfbvideosink_type,
2385 GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
2386 g_type_add_interface_static (dfbvideosink_type, GST_TYPE_NAVIGATION,
2388 g_type_add_interface_static (dfbvideosink_type, GST_TYPE_COLOR_BALANCE,
2389 &colorbalance_info);
2392 return dfbvideosink_type;
2396 plugin_init (GstPlugin * plugin)
2398 if (!gst_element_register (plugin, "dfbvideosink", GST_RANK_MARGINAL,
2399 GST_TYPE_DFBVIDEOSINK))
2402 GST_DEBUG_CATEGORY_INIT (dfbvideosink_debug, "dfbvideosink", 0,
2403 "DirectFB video sink element");
2408 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2411 "DirectFB video output plugin",
2412 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)