Added TI patches, generated from commit 04f9d72 of the following tree:
[ubuntu-omap:gst-plugins-bad1-0.git] / debian / patches / 0001-01-30-WIP-start-adding-dri2videosink.patch
1 From a359feb1cc2732e36523e1189d1cbffa3a150a0b Mon Sep 17 00:00:00 2001
2 From: Rob Clark <rob@ti.com>
3 Date: Thu, 14 Jun 2012 10:37:06 -0500
4 Subject: [PATCH 001/100] [01/30] WIP: start adding dri2videosink
5
6 ---
7  sys/dri2/Makefile.am         |   23 +
8  sys/dri2/gstdri2.c           |   57 +++
9  sys/dri2/gstdri2bufferpool.c |  113 +++++
10  sys/dri2/gstdri2bufferpool.h |   94 ++++
11  sys/dri2/gstdri2util.c       |  627 ++++++++++++++++++++++++
12  sys/dri2/gstdri2util.h       |  122 +++++
13  sys/dri2/gstdri2videosink.c  | 1117 ++++++++++++++++++++++++++++++++++++++++++
14  sys/dri2/gstdri2videosink.h  |  101 ++++
15  8 files changed, 2254 insertions(+)
16  create mode 100644 sys/dri2/Makefile.am
17  create mode 100644 sys/dri2/gstdri2.c
18  create mode 100644 sys/dri2/gstdri2bufferpool.c
19  create mode 100644 sys/dri2/gstdri2bufferpool.h
20  create mode 100644 sys/dri2/gstdri2util.c
21  create mode 100644 sys/dri2/gstdri2util.h
22  create mode 100644 sys/dri2/gstdri2videosink.c
23  create mode 100644 sys/dri2/gstdri2videosink.h
24
25 diff --git a/sys/dri2/Makefile.am b/sys/dri2/Makefile.am
26 new file mode 100644
27 index 0000000..5da9931
28 --- /dev/null
29 +++ b/sys/dri2/Makefile.am
30 @@ -0,0 +1,23 @@
31 +plugin_LTLIBRARIES = libgstdri2.la
32 +
33 +libgstdri2_la_SOURCES = \
34 +       gstdri2.c \
35 +       gstdri2videosink.c \
36 +       gstdri2bufferpool.c \
37 +       gstdri2util.c
38 +
39 +libgstdri2_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(DRI2_CFLAGS)
40 +
41 +libgstdri2_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) \
42 +       $(GST_PLUGINS_BASE_LIBS) $(GST_PLUGINS_BAD_LIBS) $(X11_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
43 +       -lgstinterfaces-$(GST_MAJORMINOR) -lgstdmabuf-$(GST_MAJORMINOR) -lgstdrm-$(GST_MAJORMINOR) \
44 +       $(DRI2_LIBS) \
45 +       $(LIBM)
46 +
47 +libgstdri2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
48 +libgstdri2_la_LIBTOOLFLAGS = --tag=disable-static
49 +
50 +noinst_HEADERS = \
51 +       gstdri2videosink.h \
52 +       gstdri2bufferpool.h \
53 +       gstdri2util.h
54 diff --git a/sys/dri2/gstdri2.c b/sys/dri2/gstdri2.c
55 new file mode 100644
56 index 0000000..85367f2
57 --- /dev/null
58 +++ b/sys/dri2/gstdri2.c
59 @@ -0,0 +1,57 @@
60 +/*
61 + * GStreamer
62 + *
63 + * Copyright (C) 2012 Texas Instruments
64 + * Copyright (C) 2012 Collabora Ltd
65 + *
66 + * Authors:
67 + *  Alessandro Decina <alessandro.decina@collabora.co.uk>
68 + *  Rob Clark <rob.clark@linaro.org>
69 + *
70 + * This library is free software; you can redistribute it and/or
71 + * modify it under the terms of the GNU Lesser General Public
72 + * License as published by the Free Software Foundation
73 + * version 2.1 of the License.
74 + *
75 + * This library is distributed in the hope that it will be useful,
76 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
77 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
78 + * Lesser General Public License for more details.
79 + *
80 + * You should have received a copy of the GNU Lesser General Public
81 + * License along with this library; if not, write to the Free Software
82 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
83 + */
84 +
85 +#ifdef HAVE_CONFIG_H
86 +#  include <config.h>
87 +#endif
88 +
89 +#include "gstdri2videosink.h"
90 +
91 +GST_DEBUG_CATEGORY (gst_debug_dri2);
92 +
93 +static gboolean
94 +plugin_init (GstPlugin * plugin)
95 +{
96 +  GST_DEBUG_CATEGORY_INIT (gst_debug_dri2, "dri2videosink", 0,
97 +      "dri2videosink");
98 +
99 +  return gst_element_register (plugin, "dri2videosink", GST_RANK_SECONDARY,
100 +      GST_TYPE_DRI2VIDEOSINK);
101 +}
102 +
103 +/* PACKAGE: this is usually set by autotools depending on some _INIT macro
104 + * in configure.ac and then written into and defined in config.h, but we can
105 + * just set it ourselves here in case someone doesn't use autotools to
106 + * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined.
107 + */
108 +#ifndef PACKAGE
109 +#  define PACKAGE "dri2"
110 +#endif
111 +
112 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
113 +    GST_VERSION_MINOR,
114 +    "dri2",
115 +    "DRI2 based plugin",
116 +    plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
117 diff --git a/sys/dri2/gstdri2bufferpool.c b/sys/dri2/gstdri2bufferpool.c
118 new file mode 100644
119 index 0000000..76faad7
120 --- /dev/null
121 +++ b/sys/dri2/gstdri2bufferpool.c
122 @@ -0,0 +1,113 @@
123 +/*
124 + * GStreamer
125 + *
126 + * Copyright (C) 2012 Texas Instruments
127 + * Copyright (C) 2012 Collabora Ltd
128 + *
129 + * Authors:
130 + *  Alessandro Decina <alessandro.decina@collabora.co.uk>
131 + *  Rob Clark <rob.clark@linaro.org>
132 + *
133 + * This library is free software; you can redistribute it and/or
134 + * modify it under the terms of the GNU Lesser General Public
135 + * License as published by the Free Software Foundation
136 + * version 2.1 of the License.
137 + *
138 + * This library is distributed in the hope that it will be useful,
139 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
140 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
141 + * Lesser General Public License for more details.
142 + *
143 + * You should have received a copy of the GNU Lesser General Public
144 + * License along with this library; if not, write to the Free Software
145 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
146 + */
147 +
148 +#ifdef HAVE_CONFIG_H
149 +#include "config.h"
150 +#endif
151 +
152 +#include "gstdri2bufferpool.h"
153 +
154 +/*
155 + * GstDRI2BufferPool:
156 + */
157 +
158 +G_DEFINE_TYPE (GstDRI2BufferPool, gst_dri2_buffer_pool,
159 +    GST_TYPE_DRM_BUFFER_POOL);
160 +
161 +GstDRI2BufferPool *
162 +gst_dri2_buffer_pool_new (GstDRI2Window * xwindow,
163 +    int fd, GstCaps * caps, guint size)
164 +{
165 +  GstDRI2BufferPool *self = (GstDRI2BufferPool *)
166 +      gst_mini_object_new (GST_TYPE_DRI2_BUFFER_POOL);
167 +
168 +  gst_drm_buffer_pool_initialize (GST_DRM_BUFFER_POOL (self),
169 +      xwindow->dcontext->elem, fd, caps, size);
170 +
171 +  self->xwindow = xwindow;
172 +
173 +  return self;
174 +}
175 +
176 +static GstDRMBuffer *
177 +gst_dri2_buffer_alloc (GstDRMBufferPool * pool)
178 +{
179 +  GstDRI2BufferPool *dri2pool = GST_DRI2_BUFFER_POOL (pool);
180 +  GstDRI2Buffer *self = (GstDRI2Buffer *)
181 +      gst_mini_object_new (GST_TYPE_DRI2_BUFFER);
182 +  struct omap_bo *bo;
183 +
184 +  self->dri2buf = gst_dri2window_get_dri2buffer (dri2pool->xwindow,
185 +      pool->width, pool->height, pool->fourcc);
186 +
187 +  /* we can't really properly support multi-planar w/ separate buffers
188 +   * in gst0.10..  we need a way to indicate this to the server!
189 +   */
190 +  g_warn_if_fail (self->dri2buf->names[1] == 0);
191 +
192 +  bo = omap_bo_from_name (pool->dev, self->dri2buf->names[0]);
193 +  gst_drm_buffer_initialize (GST_DRM_BUFFER (self), pool, bo);
194 +
195 +  return GST_DRM_BUFFER (self);
196 +}
197 +
198 +static void
199 +gst_dri2_buffer_cleanup (GstDRMBufferPool * pool, GstDRMBuffer * buf)
200 +{
201 +  gst_dri2window_free_dri2buffer (
202 +      GST_DRI2_BUFFER_POOL (pool)->xwindow,
203 +      GST_DRI2_BUFFER (buf)->dri2buf);
204 +}
205 +
206 +static void
207 +gst_dri2_buffer_pool_class_init (GstDRI2BufferPoolClass * klass)
208 +{
209 +  GST_DRM_BUFFER_POOL_CLASS (klass)->buffer_alloc =
210 +      GST_DEBUG_FUNCPTR (gst_dri2_buffer_alloc);
211 +  GST_DRM_BUFFER_POOL_CLASS (klass)->buffer_cleanup =
212 +      GST_DEBUG_FUNCPTR (gst_dri2_buffer_cleanup);
213 +}
214 +
215 +static void
216 +gst_dri2_buffer_pool_init (GstDRI2BufferPool * self)
217 +{
218 +}
219 +
220 +/*
221 + * GstDRI2Buffer:
222 + */
223 +
224 +
225 +G_DEFINE_TYPE (GstDRI2Buffer, gst_dri2_buffer, GST_TYPE_DRM_BUFFER);
226 +
227 +static void
228 +gst_dri2_buffer_class_init (GstDRI2BufferClass * klass)
229 +{
230 +}
231 +
232 +static void
233 +gst_dri2_buffer_init (GstDRI2Buffer * buffer)
234 +{
235 +}
236 diff --git a/sys/dri2/gstdri2bufferpool.h b/sys/dri2/gstdri2bufferpool.h
237 new file mode 100644
238 index 0000000..2a86aff
239 --- /dev/null
240 +++ b/sys/dri2/gstdri2bufferpool.h
241 @@ -0,0 +1,94 @@
242 +/*
243 + * GStreamer
244 + *
245 + * Copyright (C) 2012 Texas Instruments
246 + * Copyright (C) 2012 Collabora Ltd
247 + *
248 + * Authors:
249 + *  Alessandro Decina <alessandro.decina@collabora.co.uk>
250 + *  Rob Clark <rob.clark@linaro.org>
251 + *
252 + * This library is free software; you can redistribute it and/or
253 + * modify it under the terms of the GNU Lesser General Public
254 + * License as published by the Free Software Foundation
255 + * version 2.1 of the License.
256 + *
257 + * This library is distributed in the hope that it will be useful,
258 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
259 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
260 + * Lesser General Public License for more details.
261 + *
262 + * You should have received a copy of the GNU Lesser General Public
263 + * License along with this library; if not, write to the Free Software
264 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
265 + */
266 +
267 +#ifndef __GSTDRI2BUFFERPOOL_H__
268 +#define __GSTDRI2BUFFERPOOL_H__
269 +
270 +#include <gst/gst.h>
271 +
272 +#include "gstdri2util.h"
273 +
274 +G_BEGIN_DECLS
275 +
276 +/*
277 + * GstDRI2BufferPool:
278 + */
279 +
280 +#define GST_TYPE_DRI2_BUFFER_POOL (gst_dri2_buffer_pool_get_type())
281 +#define GST_IS_DRI2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DRI2_BUFFER_POOL))
282 +#define GST_DRI2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DRI2_BUFFER_POOL, GstDRI2BufferPool))
283 +#define GST_DRI2_BUFFER_POOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DRI2_BUFFER_POOL, GstDRI2BufferPoolClass))
284 +#define GST_DRI2_BUFFER_POOL_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DRI2_BUFFER_POOL, GstDRI2BufferPoolClass))
285 +
286 +#define GST_DRI2_BUFFER_POOL_LOCK(self)     g_mutex_lock ((self)->lock)
287 +#define GST_DRI2_BUFFER_POOL_UNLOCK(self)   g_mutex_unlock ((self)->lock)
288 +
289 +typedef struct _GstDRI2BufferPool GstDRI2BufferPool;
290 +typedef struct _GstDRI2BufferPoolClass GstDRI2BufferPoolClass;
291 +
292 +struct _GstDRI2BufferPool {
293 +  GstDRMBufferPool parent;
294 +  GstDRI2Window *xwindow;
295 +};
296 +
297 +struct _GstDRI2BufferPoolClass {
298 +  GstDRMBufferPoolClass klass;
299 +};
300 +
301 +GType gst_dri2_buffer_pool_get_type (void);
302 +
303 +GstDRI2BufferPool * gst_dri2_buffer_pool_new (GstDRI2Window * xwindow,
304 +    int fd, GstCaps * caps, guint size);
305 +void gst_dri2_buffer_pool_destroy (GstDRI2BufferPool * self);
306 +
307 +/*
308 + * GstDRI2Buffer:
309 + */
310 +
311 +#define GST_TYPE_DRI2_BUFFER (gst_dri2_buffer_get_type())
312 +#define GST_IS_DRI2_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DRI2_BUFFER))
313 +#define GST_DRI2_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DRI2_BUFFER, GstDRI2Buffer))
314 +
315 +typedef struct _GstDRI2Buffer GstDRI2Buffer;
316 +typedef struct _GstDRI2BufferClass GstDRI2BufferClass;
317 +
318 +struct _GstDRI2Buffer {
319 +  GstDRMBuffer parent;
320 +
321 +  DRI2Buffer *dri2buf;
322 +};
323 +
324 +struct _GstDRI2BufferClass {
325 +  GstDRMBufferClass klass;
326 +
327 +  guint width, height;
328 +  guint32 format;
329 +};
330 +
331 +GType gst_dri2_buffer_get_type (void);
332 +
333 +G_END_DECLS
334 +
335 +#endif /* __GSTDRI2BUFFERPOOL_H__ */
336 diff --git a/sys/dri2/gstdri2util.c b/sys/dri2/gstdri2util.c
337 new file mode 100644
338 index 0000000..7e54c85
339 --- /dev/null
340 +++ b/sys/dri2/gstdri2util.c
341 @@ -0,0 +1,627 @@
342 +/*
343 + * GStreamer
344 + *
345 + * Copyright (C) 2012 Texas Instruments
346 + *
347 + * Authors:
348 + *  Rob Clark <rob.clark@linaro.org>
349 + *
350 + * This library is free software; you can redistribute it and/or
351 + * modify it under the terms of the GNU Lesser General Public
352 + * License as published by the Free Software Foundation
353 + * version 2.1 of the License.
354 + *
355 + * This library is distributed in the hope that it will be useful,
356 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
357 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
358 + * Lesser General Public License for more details.
359 + *
360 + * You should have received a copy of the GNU Lesser General Public
361 + * License along with this library; if not, write to the Free Software
362 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
363 + */
364 +
365 +#ifdef HAVE_CONFIG_H
366 +#include "config.h"
367 +#endif
368 +
369 +#include <ctype.h>
370 +
371 +#include <gst/video/video-crop.h>
372 +
373 +#include "gstdri2util.h"
374 +#include "gstdri2bufferpool.h"
375 +
376 +static Bool WireToEvent (Display * dpy, XExtDisplayInfo * info,
377 +    XEvent * event, xEvent * wire)
378 +{
379 +  switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
380 +
381 +  case DRI2_BufferSwapComplete: {
382 +    //    xDRI2BufferSwapComplete *awire = (xDRI2BufferSwapComplete *)wire;
383 +    // TODO use this to know when the previous buffer is no longer visible..
384 +    GST_LOG ("BufferSwapComplete");
385 +    return True;
386 +  }
387 +  case DRI2_InvalidateBuffers: {
388 +    //    xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire;
389 +    GST_LOG ("InvalidateBuffers");
390 +    //    dri2InvalidateBuffers(dpy, awire->drawable);
391 +    return False;
392 +  }
393 +  default:
394 +    /* client doesn't support server event */
395 +    break;
396 +  }
397 +
398 +  return False;
399 +}
400 +
401 +static Status EventToWire (Display * dpy, XExtDisplayInfo * info,
402 +    XEvent * event, xEvent * wire)
403 +{
404 +  switch (event->type) {
405 +  default:
406 +    /* client doesn't support server event */
407 +    break;
408 +  }
409 +
410 +  return Success;
411 +}
412 +
413 +static const DRI2EventOps ops = {
414 +    .WireToEvent = WireToEvent,
415 +    .EventToWire = EventToWire,
416 +};
417 +
418 +static DRI2Buffer * get_buffer (GstDRI2Window * xwindow, guint attach,
419 +    gint width, gint height, guint32 format);
420 +
421 +static Bool is_fourcc(unsigned int val)
422 +{
423 +  char *str = (char *)&val;
424 +  return isalnum(str[0]) && isalnum(str[1]) &&
425 +      isalnum(str[2]) && isalnum(str[3]);
426 +}
427 +
428 +/*
429 + * GstDRI2DrawContext
430 + */
431 +
432 +/* This function calculates the pixel aspect ratio based on the properties
433 + * in the xcontext structure and stores it there.
434 + */
435 +static void
436 +gst_dri2context_calculate_pixel_aspect_ratio (GstDRI2Context * dcontext)
437 +{
438 +  static const gint par[][2] = {
439 +    {1, 1},                     /* regular screen */
440 +    {16, 15},                   /* PAL TV */
441 +    {11, 10},                   /* 525 line Rec.601 video */
442 +    {54, 59},                   /* 625 line Rec.601 video */
443 +    {64, 45},                   /* 1280x1024 on 16:9 display */
444 +    {5, 3},                     /* 1280x1024 on 4:3 display */
445 +    {4, 3}                      /* 800x600 on 16:9 display */
446 +  };
447 +  gint i;
448 +  gint index;
449 +  gdouble ratio;
450 +  gdouble delta;
451 +
452 +#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
453 +
454 +  /* first calculate the "real" ratio; which is the "physical" w/h divided
455 +   * by the w/h in pixels of the display
456 +   *
457 +   * TODO:
458 +  ratio = (gdouble) (dcontext->physical_width * dcontext->display_height)
459 +      / (dcontext->physical_height * dcontext->display_width);
460 +   */
461 +
462 +  /* XXX */
463 +  ratio = 1;
464 +
465 +  GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
466 +  /* now find the one from par[][2] with the lowest delta to the real one */
467 +  delta = DELTA (0);
468 +  index = 0;
469 +
470 +  for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
471 +    gdouble this_delta = DELTA (i);
472 +
473 +    if (this_delta < delta) {
474 +      index = i;
475 +      delta = this_delta;
476 +    }
477 +  }
478 +
479 +  GST_DEBUG ("Decided on index %d (%d/%d)", index,
480 +      par[index][0], par[index][1]);
481 +
482 +  g_free (dcontext->par);
483 +  dcontext->par = g_new0 (GValue, 1);
484 +  g_value_init (dcontext->par, GST_TYPE_FRACTION);
485 +  gst_value_set_fraction (dcontext->par, par[index][0], par[index][1]);
486 +  GST_DEBUG ("set dcontext PAR to %d/%d",
487 +      gst_value_get_fraction_numerator (dcontext->par),
488 +      gst_value_get_fraction_denominator (dcontext->par));
489 +}
490 +
491 +GstDRI2Context *
492 +gst_dri2context_new (GstElement * elem)
493 +{
494 +  GstDRI2Context *dcontext;
495 +  Window root;
496 +  drm_magic_t magic;
497 +  int eventBase, errorBase, major, minor;
498 +  char *driver, *device;
499 +  unsigned int i, nformats, *formats;
500 +  int fd;
501 +
502 +  dcontext = g_new0 (GstDRI2Context, 1);
503 +  dcontext->elem = elem;
504 +  dcontext->x_lock = g_mutex_new ();
505 +
506 +  dcontext->x_display = XOpenDisplay (NULL);
507 +  if (!DRI2InitDisplay(dcontext->x_display, &ops)) {
508 +    GST_ERROR_OBJECT (elem, "DRI2InitDisplay failed");
509 +    goto fail;
510 +  }
511 +
512 +  if (!DRI2QueryExtension (dcontext->x_display, &eventBase, &errorBase)) {
513 +    GST_ERROR_OBJECT (elem, "DRI2QueryExtension failed");
514 +    goto fail;
515 +  }
516 +
517 +  GST_DEBUG_OBJECT (elem, "DRI2QueryExtension: "
518 +      "eventBase=%d, errorBase=%d", eventBase, errorBase);
519 +
520 +  if (!DRI2QueryVersion (dcontext->x_display, &major, &minor)) {
521 +    GST_ERROR_OBJECT (elem, "DRI2QueryVersion failed");
522 +    goto fail;
523 +  }
524 +
525 +  GST_DEBUG_OBJECT (elem, "DRI2QueryVersion: major=%d, minor=%d",
526 +      major, minor);
527 +
528 +  root = RootWindow (dcontext->x_display,
529 +      DefaultScreen (dcontext->x_display));
530 +
531 +  if (!DRI2Connect (dcontext->x_display, root,
532 +      DRI2DriverXV, &driver, &device)) {
533 +    GST_ERROR_OBJECT (elem, "DRI2Connect failed");
534 +    goto fail;
535 +  }
536 +
537 +  GST_DEBUG_OBJECT (elem, "DRI2Connect: driver=%s, device=%s",
538 +      driver, device);
539 +
540 +  fd = open (device, O_RDWR);
541 +  if (fd < 0) {
542 +    GST_ERROR_OBJECT (elem, "open failed");
543 +    goto fail;
544 +  }
545 +
546 +  if (drmGetMagic (fd, &magic)) {
547 +    GST_ERROR_OBJECT (elem, "drmGetMagic failed");
548 +    goto fail;
549 +  }
550 +
551 +  if (!DRI2Authenticate (dcontext->x_display, root, magic)) {
552 +    GST_ERROR_OBJECT (elem, "DRI2Authenticate failed");
553 +    goto fail;
554 +  }
555 +
556 +  dcontext->drm_fd = fd;
557 +  dcontext->dev = omap_device_new (fd);
558 +
559 +  if (!DRI2GetFormats (dcontext->x_display, root, &nformats, &formats)) {
560 +    GST_ERROR_OBJECT (elem, "DRI2GetFormats failed");
561 +    goto fail;
562 +  }
563 +
564 +  if (nformats == 0) {
565 +    GST_ERROR_OBJECT (elem, "no formats!");
566 +    goto fail;
567 +  }
568 +
569 +  /* print out supported formats */
570 +  GST_DEBUG_OBJECT (elem, "Found %d supported formats:", nformats);
571 +  for (i = 0; i < nformats; i++) {
572 +    if (is_fourcc(formats[i])) {
573 +      GST_DEBUG_OBJECT (elem, "  %d: %08x (\"%.4s\")", i, formats[i],
574 +          (char *)&formats[i]);
575 +    } else {
576 +      GST_DEBUG_OBJECT (elem, "  %d: %08x (device dependent)", i, formats[i]);
577 +    }
578 +  }
579 +
580 +  free(formats);
581 +
582 +  gst_dri2context_calculate_pixel_aspect_ratio (dcontext);
583 +
584 +  dcontext->black = XBlackPixel (dcontext->x_display, dcontext->screen_num);
585 +
586 +  return dcontext;
587 +
588 +fail:
589 +  /* XXX: release resources */
590 +  return NULL;
591 +}
592 +
593 +void
594 +gst_dri2context_delete (GstDRI2Context *dcontext)
595 +{
596 +  g_free (dcontext->par);
597 +
598 +  g_mutex_lock (dcontext->x_lock);
599 +  XCloseDisplay (dcontext->x_display);
600 +  g_mutex_unlock (dcontext->x_lock);
601 +  g_mutex_free (dcontext->x_lock);
602 +
603 +  omap_device_del (dcontext->dev);
604 +  drmClose (dcontext->drm_fd);
605 +
606 +  g_free (dcontext);
607 +}
608 +
609 +/*
610 + * GstDRI2Window
611 + */
612 +
613 +/* NOTES:
614 + * at startup (or on first buffer allocation?) request front buffer..
615 + * otherwise I think we can do GetBuffers 1 at a time, w/ different
616 + * attachment points.. use width==0, height==0 to destroy the buffer
617 + * Keep the table of attachment->buffer globally, to handle resolution
618 + * changes.. the old bufferpool is torn down, but still goes via the
619 + * per video-sink table of attachments, because during the transition
620 + * period we could have some not-yet-displayed buffers at the previous
621 + * dimensions/format..
622 + */
623 +
624 +GstDRI2Window *
625 +gst_dri2window_new_from_handle (GstDRI2Context *dcontext, XID xwindow_id)
626 +{
627 +  GstDRI2Window *xwindow;
628 +  XWindowAttributes attr;
629 +
630 +  xwindow = g_new0 (GstDRI2Window, 1);
631 +  xwindow->dcontext = dcontext;
632 +  xwindow->window = xwindow_id;
633 +  xwindow->pool_lock = g_mutex_new ();
634 +  xwindow->buffer_pool = NULL;
635 +  xwindow->pool_valid = FALSE;
636 +
637 +  /* Set the event we want to receive and create a GC */
638 +  g_mutex_lock (dcontext->x_lock);
639 +
640 +  XGetWindowAttributes (dcontext->x_display, xwindow->window,
641 +      &attr);
642 +
643 +  xwindow->width = attr.width;
644 +  xwindow->height = attr.height;
645 +
646 +  /* We have to do that to prevent X from redrawing the background on
647 +   * ConfigureNotify. This takes away flickering of video when resizing. */
648 +  XSetWindowBackgroundPixmap (dcontext->x_display,
649 +      xwindow->window, None);
650 +
651 +  XMapWindow (dcontext->x_display, xwindow->window);
652 +
653 +  xwindow->gc = XCreateGC (dcontext->x_display,
654 +      xwindow->window, 0, NULL);
655 +  g_mutex_unlock (dcontext->x_lock);
656 +
657 +  DRI2CreateDrawable (dcontext->x_display, xwindow->window);
658 +
659 +  /* request the front buffer.. we don't need to keep it, just to
660 +   * request it.. otherwise DRI2 core on xserver side gets miffed:
661 +   *   [DRI2] swap_buffers: drawable has no back or front?
662 +   */
663 +  free (get_buffer (xwindow, DRI2BufferFrontLeft,
664 +      xwindow->width, xwindow->height, 32));
665 +
666 +  return xwindow;
667 +}
668 +
669 +GstDRI2Window *
670 +gst_dri2window_new (GstDRI2Context * dcontext, gint width, gint height)
671 +{
672 +  GstDRI2Window *xwindow;
673 +  Window root;
674 +  Atom wm_delete;
675 +  XID xwindow_id;
676 +
677 +  g_mutex_lock (dcontext->x_lock);
678 +
679 +  GST_DEBUG_OBJECT (dcontext->elem, "creating window: %dx%d", width, height);
680 +
681 +  root = DefaultRootWindow (dcontext->x_display);
682 +  xwindow_id = XCreateSimpleWindow (dcontext->x_display, root, 0, 0,
683 +      width, height, 2, 2, dcontext->black);
684 +
685 +
686 +  /* Tell the window manager we'd like delete client messages instead of
687 +   * being killed */
688 +  wm_delete = XInternAtom (dcontext->x_display, "WM_DELETE_WINDOW", True);
689 +  if (wm_delete != None) {
690 +    (void) XSetWMProtocols (dcontext->x_display, xwindow_id,
691 +        &wm_delete, 1);
692 +  }
693 +
694 +  g_mutex_unlock (dcontext->x_lock);
695 +
696 +  xwindow = gst_dri2window_new_from_handle (dcontext, xwindow_id);
697 +  xwindow->internal = TRUE;
698 +
699 +  return xwindow;
700 +}
701 +
702 +void
703 +gst_dri2window_delete (GstDRI2Window * xwindow)
704 +{
705 +  GstDRI2Context *dcontext = xwindow->dcontext;
706 +
707 +  g_mutex_lock (xwindow->pool_lock);
708 +  xwindow->pool_valid = FALSE;
709 +  if (xwindow->buffer_pool) {
710 +    gst_drm_buffer_pool_destroy (xwindow->buffer_pool);
711 +    xwindow->buffer_pool = NULL;
712 +  }
713 +  g_mutex_unlock (xwindow->pool_lock);
714 +
715 +  g_mutex_free (xwindow->pool_lock);
716 +
717 +  g_mutex_lock (dcontext->x_lock);
718 +
719 +  DRI2DestroyDrawable (dcontext->x_display, xwindow->window);
720 +
721 +  /* If we did not create the window we just free the GC and let it live */
722 +  if (xwindow->internal)
723 +    XDestroyWindow (dcontext->x_display, xwindow->window);
724 +  else
725 +    XSelectInput (dcontext->x_display, xwindow->window, 0);
726 +
727 +  XFreeGC (dcontext->x_display, xwindow->gc);
728 +
729 +  XSync (dcontext->x_display, FALSE);
730 +
731 +  // XXX free xwindow->dri2bufs
732 +  // TODO we probably want xwindow to be a refcnt'd miniobj so we don't end w/
733 +  // dri2buffer's referencing deleted xwindow's..
734 +
735 +  g_mutex_unlock (dcontext->x_lock);
736 +
737 +  g_free (xwindow);
738 +}
739 +
740 +/* call with x_lock held */
741 +void
742 +gst_dri2window_update_geometry (GstDRI2Window * xwindow)
743 +{
744 +  XWindowAttributes attr;
745 +
746 +  XGetWindowAttributes (xwindow->dcontext->x_display,
747 +      xwindow->window, &attr);
748 +
749 +  xwindow->width  = attr.width;
750 +  xwindow->height = attr.height;
751 +}
752 +
753 +void
754 +gst_dri2window_set_pool_valid (GstDRI2Window * xwindow, gboolean valid)
755 +{
756 +  g_mutex_lock (xwindow->pool_lock);
757 +  xwindow->pool_valid = valid;
758 +  g_mutex_unlock (xwindow->pool_lock);
759 +}
760 +
761 +void
762 +gst_dri2window_check_caps (GstDRI2Window * xwindow, GstCaps * caps)
763 +{
764 +  g_mutex_lock (xwindow->pool_lock);
765 +  if (xwindow->buffer_pool) {
766 +    if (gst_drm_buffer_pool_check_caps (xwindow->buffer_pool, caps)) {
767 +      GST_INFO_OBJECT (xwindow->dcontext->elem, "caps change");
768 +      gst_drm_buffer_pool_destroy (xwindow->buffer_pool);
769 +      xwindow->buffer_pool = NULL;
770 +    }
771 +  }
772 +  g_mutex_unlock (xwindow->pool_lock);
773 +}
774 +
775 +static inline gboolean
776 +ok_buffer (GstDRI2Window * xwindow, GstBuffer * buf)
777 +{
778 +  return GST_IS_DRI2_BUFFER (buf) &&
779 +      (GST_DRI2_BUFFER_POOL (GST_DRM_BUFFER (buf)->pool)->xwindow == xwindow);
780 +
781 +}
782 +
783 +GstFlowReturn
784 +gst_dri2window_buffer_show (GstDRI2Window * xwindow, GstBuffer * buf)
785 +{
786 +  GstDRI2Context *dcontext = xwindow->dcontext;
787 +  GstDRI2Buffer *dri2buf;
788 +  GstVideoCrop *crop;
789 +  CARD64 count;
790 +  BoxRec b;
791 +
792 +  if (! ok_buffer (xwindow, buf)) {
793 +    GST_WARNING_OBJECT (dcontext->elem, "unexpected buffer: %p", buf);
794 +    return GST_FLOW_UNEXPECTED;
795 +  }
796 +
797 +  dri2buf = GST_DRI2_BUFFER (buf);
798 +
799 +  crop = gst_buffer_get_video_crop (buf);
800 +  if (crop) {
801 +    b.x1 = gst_video_crop_left (crop);
802 +    b.y1 = gst_video_crop_top (crop);
803 +    b.x2 = b.x1 + gst_video_crop_width (crop) - 1;
804 +    b.y2 = b.y1 + gst_video_crop_height (crop) - 1;
805 +  } else {
806 +    b.x1 = 0;
807 +    b.y1 = 0;
808 +    b.x2 = GST_DRM_BUFFER (dri2buf)->pool->width - 1;
809 +    b.y2 = GST_DRM_BUFFER (dri2buf)->pool->height - 1;
810 +  }
811 +
812 +  g_mutex_lock (dcontext->x_lock);
813 +  DRI2SwapBuffersVid (dcontext->x_display, xwindow->window, 0, 0, 0,
814 +      &count, dri2buf->dri2buf->attachment, &b);
815 +  /* TODO: probably should wait for DRI2_BufferSwapComplete instead..
816 +   * although that probably depends on someone making an x11 call to
817 +   * dispatch the events
818 +   */
819 +  DRI2WaitSBC (dcontext->x_display, xwindow->window, count,
820 +      /* just re-use count as a valid ptr.. we don't need ust/msc/sbc: */
821 +      &count, &count, &count);
822 +  g_mutex_unlock (dcontext->x_lock);
823 +
824 +  return GST_FLOW_OK;
825 +}
826 +
827 +GstBuffer *
828 +gst_dri2window_buffer_prepare (GstDRI2Window * xwindow, GstBuffer * buf)
829 +{
830 +  GstBuffer *newbuf = NULL;
831 +
832 +  if (! ok_buffer (xwindow, buf)) {
833 +
834 +    gst_dri2window_buffer_alloc (xwindow, GST_BUFFER_SIZE (buf),
835 +        GST_BUFFER_CAPS (buf), &newbuf);
836 +
837 +    if (newbuf) {
838 +      GST_DEBUG_OBJECT (xwindow->dcontext->elem,
839 +          "slow-path.. I got a %s so I need to memcpy",
840 +          g_type_name (G_OBJECT_TYPE (buf)));
841 +#if 0 // XXX
842 +      memcpy (GST_BUFFER_DATA (newbuf),
843 +          GST_BUFFER_DATA (buf),
844 +          MIN (GST_BUFFER_SIZE (newbuf), GST_BUFFER_SIZE (buf)));
845 +#else
846 +      GST_DEBUG_OBJECT (xwindow->dcontext->elem,
847 +          "stubbed: memcpy(%p, %p, %d)",
848 +          GST_BUFFER_DATA (newbuf),
849 +          GST_BUFFER_DATA (buf),
850 +          MIN (GST_BUFFER_SIZE (newbuf), GST_BUFFER_SIZE (buf)));
851 +#endif
852 +    }
853 +  }
854 +
855 +  return newbuf;
856 +}
857 +
858 +GstFlowReturn
859 +gst_dri2window_buffer_alloc (GstDRI2Window * xwindow, guint size,
860 +    GstCaps * caps, GstBuffer ** buf)
861 +{
862 +  GstDRI2Context *dcontext = xwindow->dcontext;
863 +  GstFlowReturn ret = GST_FLOW_ERROR;
864 +
865 +  *buf = NULL;
866 +
867 +  g_mutex_lock (xwindow->pool_lock);
868 +#if 0
869 +  /* double check if we need this.. if we do, we probably need to
870 +   * move pool_valid back to dri2videosink itself, because the
871 +   * window can be created after the PAUSED->READY state transition
872 +   */
873 +  if (G_UNLIKELY (! xwindow->pool_valid)) {
874 +    GST_DEBUG_OBJECT (dcontext->elem, "the pool is flushing");
875 +    ret = GST_FLOW_WRONG_STATE;
876 +    g_mutex_unlock (xwindow->pool_lock);
877 +    goto beach;
878 +  }
879 +#endif
880 +
881 +  /* initialize the buffer pool if not initialized yet */
882 +  if (G_UNLIKELY (!xwindow->buffer_pool ||
883 +      gst_drm_buffer_pool_size (xwindow->buffer_pool) != size)) {
884 +
885 +    if (xwindow->buffer_pool) {
886 +      GST_INFO_OBJECT (dcontext->elem, "size change");
887 +      gst_drm_buffer_pool_destroy (xwindow->buffer_pool);
888 +    }
889 +
890 +    GST_LOG_OBJECT (dcontext->elem, "Creating buffer pool");
891 +    xwindow->buffer_pool = GST_DRM_BUFFER_POOL (gst_dri2_buffer_pool_new (
892 +        xwindow, dcontext->drm_fd, caps, size));
893 +    if (!xwindow->buffer_pool) {
894 +      goto beach;
895 +    }
896 +  }
897 +
898 +  *buf = GST_BUFFER (gst_drm_buffer_pool_get (xwindow->buffer_pool, FALSE));
899 +
900 +  if (*buf)
901 +    ret = GST_FLOW_OK;
902 +
903 +beach:
904 +  g_mutex_unlock (xwindow->pool_lock);
905 +  return ret;
906 +}
907 +
908 +/*
909 + * These are used by the bufferpool to allocate buffers.. the bufferpool
910 + * needs to go thru the GstDRI2Window, because we need one place to track
911 + * which attachment points are in use and which are not to hande cases of
912 + * switching between resolutions, where the bufferpool is replaced but
913 + * with a transition period of having both buffers of the old and new size
914 + * floating around
915 + */
916 +
917 +static DRI2Buffer *
918 +get_buffer (GstDRI2Window * xwindow, guint attach, gint width, gint height,
919 +    guint32 format)
920 +{
921 +  GstDRI2Context *dcontext = xwindow->dcontext;
922 +  int nbufs = 1;
923 +  unsigned attachments[] = { attach, format };
924 +  DRI2Buffer *dri2buf;
925 +  g_mutex_lock (dcontext->x_lock);
926 +  dri2buf = DRI2GetBuffersVid(dcontext->x_display, xwindow->window,
927 +      width, height, attachments, nbufs, &nbufs);
928 +  g_mutex_unlock (dcontext->x_lock);
929 +  GST_DEBUG_OBJECT (dcontext->elem, "got %d buffer(s)", nbufs);
930 +  if (nbufs != 1) {
931 +    free (dri2buf);
932 +    return NULL;
933 +  }
934 +  return dri2buf;
935 +}
936 +
937 +DRI2Buffer *
938 +gst_dri2window_get_dri2buffer (GstDRI2Window * xwindow, gint width, gint height,
939 +    guint32 format)
940 +{
941 +  GstDRI2Context *dcontext = xwindow->dcontext;
942 +  int idx;
943 +
944 +  /* find an empty slot, note first slot is the (fake) front buffer,
945 +   * attached when the GstDRI2Window is constructed:
946 +   */
947 +  for (idx = 0; idx < G_N_ELEMENTS (xwindow->dri2bufs); idx++) {
948 +    if (!xwindow->dri2bufs[idx]) {
949 +      xwindow->dri2bufs[idx] = get_buffer (xwindow, idx + 1,
950 +          width, height, format);
951 +      g_warn_if_fail ((xwindow->dri2bufs[idx]->attachment - 1) == idx);
952 +      return xwindow->dri2bufs[idx];
953 +    }
954 +  }
955 +
956 +  GST_ERROR_OBJECT (dcontext->elem, "out of buffer slots");
957 +
958 +  return NULL;
959 +}
960 +
961 +void
962 +gst_dri2window_free_dri2buffer (GstDRI2Window * xwindow, DRI2Buffer * dri2buf)
963 +{
964 +  int idx = dri2buf->attachment - 1;
965 +  get_buffer (xwindow, dri2buf->attachment, 0, 0, 0);
966 +  free (xwindow->dri2bufs[idx]);
967 +  xwindow->dri2bufs[idx] = NULL;
968 +}
969 diff --git a/sys/dri2/gstdri2util.h b/sys/dri2/gstdri2util.h
970 new file mode 100644
971 index 0000000..c7d96fb
972 --- /dev/null
973 +++ b/sys/dri2/gstdri2util.h
974 @@ -0,0 +1,122 @@
975 +/*
976 + * GStreamer
977 + *
978 + * Copyright (C) 2012 Texas Instruments
979 + *
980 + * Authors:
981 + *  Rob Clark <rob.clark@linaro.org>
982 + *
983 + * This library is free software; you can redistribute it and/or
984 + * modify it under the terms of the GNU Lesser General Public
985 + * License as published by the Free Software Foundation
986 + * version 2.1 of the License.
987 + *
988 + * This library is distributed in the hope that it will be useful,
989 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
990 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
991 + * Lesser General Public License for more details.
992 + *
993 + * You should have received a copy of the GNU Lesser General Public
994 + * License along with this library; if not, write to the Free Software
995 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
996 + */
997 +
998 +#ifndef __GSTDRI2UTIL_H__
999 +#define __GSTDRI2UTIL_H__
1000 +
1001 +#include <gst/gst.h>
1002 +#include <gst/video/video.h>
1003 +#include <gst/drm/gstdrmbufferpool.h>
1004 +
1005 +#include <string.h>
1006 +#include <math.h>
1007 +#include <fcntl.h>
1008 +#include <omap_drm.h>
1009 +#include <omap_drmif.h>
1010 +#include <xf86drmMode.h>
1011 +#include <xf86drm.h>
1012 +#include <drm.h>
1013 +#include <X11/Xlib.h>
1014 +#include <X11/Xmd.h>
1015 +#include <X11/Xutil.h>
1016 +#include <X11/extensions/dri2proto.h>
1017 +#include <X11/extensions/dri2.h>
1018 +
1019 +
1020 +GST_DEBUG_CATEGORY_EXTERN (gst_debug_dri2);
1021 +#define GST_CAT_DEFAULT gst_debug_dri2
1022 +
1023 +
1024 +typedef struct _GstDRI2Context GstDRI2Context;
1025 +typedef struct _GstDRI2Window GstDRI2Window;
1026 +
1027 +
1028 +/*
1029 + * GstDRI2DrawContext
1030 + */
1031 +
1032 +struct _GstDRI2Context
1033 +{
1034 +  GstElement *elem;
1035 +
1036 +  /* TODO: to handle par properly, we need a way to get physical
1037 +   * dimensions from display.. and way to post a buffer specifying
1038 +   * dst coords as well as src coords..
1039 +   */
1040 +  GValue *par;
1041 +
1042 +  GMutex *x_lock;
1043 +  Display *x_display;
1044 +  gint screen_num;
1045 +  gulong black;
1046 +
1047 +  int drm_fd;
1048 +  struct omap_device *dev;
1049 +};
1050 +
1051 +
1052 +GstDRI2Context * gst_dri2context_new (GstElement * elem);
1053 +void gst_dri2context_delete (GstDRI2Context *dcontext);
1054 +
1055 +/*
1056 + * GstDRI2Window
1057 + */
1058 +
1059 +struct _GstDRI2Window
1060 +{
1061 +  GstDRI2Context *dcontext;
1062 +
1063 +  Window window;
1064 +  gint width, height;
1065 +  gboolean internal;
1066 +  GC gc;
1067 +
1068 +  /* The bufferpool is associated to the drawable because the
1069 +   * attachment points are associated with the drawable.. if
1070 +   * the app changes the drawable, we need to re-allocate the
1071 +   * buffers:
1072 +   */
1073 +  GMutex *pool_lock;
1074 +  GstDRMBufferPool *buffer_pool;
1075 +  gboolean pool_valid;
1076 +
1077 +  /* we could be a bit more clever and dynamically size the table:
1078 +   */
1079 +  DRI2Buffer *dri2bufs[50];
1080 +};
1081 +
1082 +GstDRI2Window * gst_dri2window_new_from_handle (GstDRI2Context *dcontext, XID xwindow_id);
1083 +GstDRI2Window * gst_dri2window_new (GstDRI2Context *dcontext, gint width, gint height);
1084 +void gst_dri2window_delete (GstDRI2Window * xwindow);
1085 +void gst_dri2window_update_geometry (GstDRI2Window * xwindow);
1086 +void gst_dri2window_set_pool_valid (GstDRI2Window * xwindow, gboolean valid);
1087 +void gst_dri2window_check_caps (GstDRI2Window * xwindow, GstCaps * caps);
1088 +GstFlowReturn gst_dri2window_buffer_show (GstDRI2Window * xwindow, GstBuffer * buf);
1089 +GstBuffer * gst_dri2window_buffer_prepare (GstDRI2Window * xwindow, GstBuffer * buf);
1090 +GstFlowReturn gst_dri2window_buffer_alloc (GstDRI2Window * xwindow, guint size, GstCaps * caps, GstBuffer ** buf);
1091 +
1092 +/* used by GstDRI2BufferPool: */
1093 +DRI2Buffer * gst_dri2window_get_dri2buffer (GstDRI2Window * xwindow, gint width, gint height, guint32 format);
1094 +void gst_dri2window_free_dri2buffer (GstDRI2Window * xwindow, DRI2Buffer * dri2buf);
1095 +
1096 +#endif /* __GSTDRI2UTIL_H__ */
1097 diff --git a/sys/dri2/gstdri2videosink.c b/sys/dri2/gstdri2videosink.c
1098 new file mode 100644
1099 index 0000000..7974fd3
1100 --- /dev/null
1101 +++ b/sys/dri2/gstdri2videosink.c
1102 @@ -0,0 +1,1117 @@
1103 +/*
1104 + * GStreamer
1105 + *
1106 + * Copyright (C) 2012 Texas Instruments
1107 + * Copyright (C) 2012 Collabora Ltd
1108 + *
1109 + * Authors:
1110 + *  Alessandro Decina <alessandro.decina@collabora.co.uk>
1111 + *  Rob Clark <rob.clark@linaro.org>
1112 + *
1113 + * This library is free software; you can redistribute it and/or
1114 + * modify it under the terms of the GNU Lesser General Public
1115 + * License as published by the Free Software Foundation
1116 + * version 2.1 of the License.
1117 + *
1118 + * This library is distributed in the hope that it will be useful,
1119 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1120 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1121 + * Lesser General Public License for more details.
1122 + *
1123 + * You should have received a copy of the GNU Lesser General Public
1124 + * License along with this library; if not, write to the Free Software
1125 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
1126 + */
1127 +
1128 +#ifdef HAVE_CONFIG_H
1129 +#include "config.h"
1130 +#endif
1131 +
1132 +#include <gst/video/gstvideosink.h>
1133 +#include <gst/interfaces/xoverlay.h>
1134 +#include <gst/interfaces/navigation.h>
1135 +
1136 +#include <gst/gstinfo.h>
1137 +
1138 +#include "gstdri2videosink.h"
1139 +#include "gstdri2bufferpool.h"
1140 +
1141 +static void gst_dri2videosink_reset (GstDRI2VideoSink * self);
1142 +static GstFlowReturn gst_dri2videosink_buffer_alloc (GstBaseSink * bsink,
1143 +    guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
1144 +static void gst_dri2videosink_expose (GstXOverlay * overlay);
1145 +static void gst_dri2videosink_set_event_handling (GstXOverlay * overlay,
1146 +    gboolean handle_events);
1147 +
1148 +/* TODO we can get supported color formats from xserver */
1149 +static GstStaticPadTemplate gst_dri2videosink_sink_template_factory =
1150 +    GST_STATIC_PAD_TEMPLATE ("sink",
1151 +    GST_PAD_SINK,
1152 +    GST_PAD_ALWAYS,
1153 +    GST_STATIC_CAPS ("video/x-raw-yuv, "
1154 +        "format = (fourcc){NV12, I420, YUY2, UYVY}, "
1155 +        "width = " GST_VIDEO_SIZE_RANGE ", "
1156 +        "height = " GST_VIDEO_SIZE_RANGE ", "
1157 +        "framerate = " GST_VIDEO_FPS_RANGE));
1158 +
1159 +enum
1160 +{
1161 +  PROP_0,
1162 +  PROP_FORCE_ASPECT_RATIO,
1163 +  PROP_WINDOW_WIDTH,
1164 +  PROP_WINDOW_HEIGHT
1165 +};
1166 +
1167 +
1168 +static GstVideoSinkClass *parent_class = NULL;
1169 +
1170 +/* call w/ x_lock held */
1171 +static void
1172 +gst_dri2videosink_xwindow_update_geometry (GstDRI2VideoSink * self)
1173 +{
1174 +  /* Update the window geometry */
1175 +  if (G_UNLIKELY (self->xwindow == NULL)) {
1176 +    return;
1177 +  }
1178 +
1179 +  gst_dri2window_update_geometry (self->xwindow);
1180 +
1181 +  if (!self->have_render_rect) {
1182 +    self->render_rect.x = self->render_rect.y = 0;
1183 +    self->render_rect.w = self->xwindow->width;
1184 +    self->render_rect.h = self->xwindow->height;
1185 +  }
1186 +
1187 +  g_mutex_unlock (self->dcontext->x_lock);
1188 +}
1189 +
1190 +/* This function handles XEvents that might be in the queue. It generates
1191 +   GstEvent that will be sent upstream in the pipeline to handle interactivity
1192 +   and navigation. It will also listen for configure events on the window to
1193 +   trigger caps renegotiation so on the fly software scaling can work. */
1194 +static void
1195 +gst_dri2videosink_handle_xevents (GstDRI2VideoSink * self)
1196 +{
1197 +  Display *dpy = self->dcontext->x_display;
1198 +  Window win = self->xwindow->window;
1199 +  XEvent e;
1200 +  gboolean exposed = FALSE;
1201 +  gboolean configured = FALSE;
1202 +  guint pointer_x = 0, pointer_y = 0;
1203 +  gboolean pointer_moved = FALSE;
1204 +
1205 +  g_mutex_lock (self->flow_lock);
1206 +  g_mutex_lock (self->dcontext->x_lock);
1207 +
1208 +  /* First get all pointer motion events, only the last position is
1209 +   * interesting so throw out the earlier ones:
1210 +   */
1211 +  while (XCheckWindowEvent (dpy, win, PointerMotionMask, &e)) {
1212 +    switch (e.type) {
1213 +      case MotionNotify:
1214 +        pointer_x = e.xmotion.x;
1215 +        pointer_y = e.xmotion.y;
1216 +        pointer_moved = TRUE;
1217 +        break;
1218 +      default:
1219 +        break;
1220 +    }
1221 +  }
1222 +
1223 +  if (pointer_moved) {
1224 +    GST_DEBUG_OBJECT (self,
1225 +        "pointer moved over window at %d,%d", pointer_x, pointer_y);
1226 +    g_mutex_unlock (self->dcontext->x_lock);
1227 +    gst_navigation_send_mouse_event (GST_NAVIGATION (self),
1228 +        "mouse-move", 0, e.xbutton.x, e.xbutton.y);
1229 +    g_mutex_lock (self->dcontext->x_lock);
1230 +  }
1231 +
1232 +  /* Then handle all the other events: */
1233 +  while (XCheckWindowEvent (self->dcontext->x_display,
1234 +          self->xwindow->window,
1235 +          ExposureMask | StructureNotifyMask |
1236 +          KeyPressMask | KeyReleaseMask |
1237 +          ButtonPressMask | ButtonReleaseMask, &e)) {
1238 +    KeySym keysym;
1239 +    const char *key_str = NULL;
1240 +
1241 +    g_mutex_unlock (self->dcontext->x_lock);
1242 +
1243 +    switch (e.type) {
1244 +      case Expose:
1245 +        exposed = TRUE;
1246 +        break;
1247 +      case ConfigureNotify:
1248 +        g_mutex_lock (self->dcontext->x_lock);
1249 +        gst_dri2videosink_xwindow_update_geometry (self);
1250 +        g_mutex_unlock (self->dcontext->x_lock);
1251 +        configured = TRUE;
1252 +        break;
1253 +      case ButtonPress:
1254 +        GST_DEBUG_OBJECT (self,
1255 +            "button %d pressed over window at %d,%d",
1256 +            e.xbutton.button, e.xbutton.x, e.xbutton.y);
1257 +        gst_navigation_send_mouse_event (GST_NAVIGATION (self),
1258 +            "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1259 +        break;
1260 +      case ButtonRelease:
1261 +        GST_DEBUG_OBJECT (self,
1262 +            "button %d released over window at %d,%d", e.xbutton.button,
1263 +            e.xbutton.x, e.xbutton.y);
1264 +        gst_navigation_send_mouse_event (GST_NAVIGATION (self),
1265 +            "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1266 +        break;
1267 +      case KeyPress:
1268 +      case KeyRelease:
1269 +        g_mutex_lock (self->dcontext->x_lock);
1270 +        keysym = XKeycodeToKeysym (dpy, e.xkey.keycode, 0);
1271 +        if (keysym != NoSymbol) {
1272 +          key_str = XKeysymToString (keysym);
1273 +        } else {
1274 +          key_str = "unknown";
1275 +        }
1276 +        g_mutex_unlock (self->dcontext->x_lock);
1277 +        GST_DEBUG_OBJECT (self,
1278 +            "key %d pressed over window at %d,%d (%s)",
1279 +            e.xkey.keycode, e.xkey.x, e.xkey.y, key_str);
1280 +        gst_navigation_send_key_event (GST_NAVIGATION (self),
1281 +            e.type == KeyPress ? "key-press" : "key-release", key_str);
1282 +        break;
1283 +      default:
1284 +        GST_DEBUG_OBJECT (self, "unhandled X event (%d)", e.type);
1285 +        break;
1286 +    }
1287 +
1288 +    g_mutex_lock (self->dcontext->x_lock);
1289 +  }
1290 +
1291 +  if (exposed || configured) {
1292 +    g_mutex_unlock (self->dcontext->x_lock);
1293 +    g_mutex_unlock (self->flow_lock);
1294 +
1295 +    gst_dri2videosink_expose (GST_X_OVERLAY (self));
1296 +
1297 +    g_mutex_lock (self->flow_lock);
1298 +    g_mutex_lock (self->dcontext->x_lock);
1299 +  }
1300 +
1301 +  /* Handle Display events */
1302 +  while (XPending (self->dcontext->x_display)) {
1303 +    XNextEvent (self->dcontext->x_display, &e);
1304 +
1305 +    switch (e.type) {
1306 +      case ClientMessage:{
1307 +        Atom wm_delete;
1308 +
1309 +        wm_delete = XInternAtom (self->dcontext->x_display,
1310 +            "WM_DELETE_WINDOW", True);
1311 +        if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
1312 +          /* Handle window deletion by posting an error on the bus */
1313 +          GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
1314 +              ("Output window was closed"), (NULL));
1315 +
1316 +          g_mutex_unlock (self->dcontext->x_lock);
1317 +          gst_dri2window_delete (self->xwindow);
1318 +          self->xwindow = NULL;
1319 +          g_mutex_lock (self->dcontext->x_lock);
1320 +        }
1321 +        break;
1322 +      }
1323 +      default:
1324 +        break;
1325 +    }
1326 +  }
1327 +
1328 +  g_mutex_unlock (self->dcontext->x_lock);
1329 +  g_mutex_unlock (self->flow_lock);
1330 +}
1331 +
1332 +static gpointer
1333 +gst_dri2videosink_event_thread (GstDRI2VideoSink * self)
1334 +{
1335 +  GST_OBJECT_LOCK (self);
1336 +  while (self->running) {
1337 +    GST_OBJECT_UNLOCK (self);
1338 +
1339 +    if (self->xwindow) {
1340 +      gst_dri2videosink_handle_xevents (self);
1341 +    }
1342 +    g_usleep (G_USEC_PER_SEC / 20);
1343 +
1344 +    GST_OBJECT_LOCK (self);
1345 +  }
1346 +  GST_OBJECT_UNLOCK (self);
1347 +
1348 +  return NULL;
1349 +}
1350 +
1351 +static void
1352 +gst_dri2videosink_manage_event_thread (GstDRI2VideoSink * self)
1353 +{
1354 +  GThread *thread = NULL;
1355 +
1356 +  /* don't start the thread too early */
1357 +  if (self->dcontext == NULL) {
1358 +    return;
1359 +  }
1360 +
1361 +  GST_OBJECT_LOCK (self);
1362 +  if (!self->event_thread) {
1363 +    /* Setup our event listening thread */
1364 +    GST_DEBUG_OBJECT (self, "run xevent thread");
1365 +    self->running = TRUE;
1366 +    self->event_thread = g_thread_create (
1367 +        (GThreadFunc) gst_dri2videosink_event_thread, self, TRUE, NULL);
1368 +  }
1369 +  GST_OBJECT_UNLOCK (self);
1370 +
1371 +  /* Wait for our event thread to finish */
1372 +  if (thread)
1373 +    g_thread_join (thread);
1374 +}
1375 +
1376 +static void
1377 +gst_dri2videosink_xwindow_set_title (GstDRI2VideoSink * self,
1378 +    GstDRI2Window * xwindow, const gchar * media_title)
1379 +{
1380 +  if (media_title) {
1381 +    g_free (self->media_title);
1382 +    self->media_title = g_strdup (media_title);
1383 +  }
1384 +  if (xwindow) {
1385 +    /* we have a window */
1386 +    if (xwindow->internal) {
1387 +      XTextProperty xproperty;
1388 +      const gchar *app_name;
1389 +      const gchar *title = NULL;
1390 +      gchar *title_mem = NULL;
1391 +
1392 +      /* set application name as a title */
1393 +      app_name = g_get_application_name ();
1394 +
1395 +      if (app_name && self->media_title) {
1396 +        title = title_mem = g_strconcat (self->media_title, " : ",
1397 +            app_name, NULL);
1398 +      } else if (app_name) {
1399 +        title = app_name;
1400 +      } else if (self->media_title) {
1401 +        title = self->media_title;
1402 +      }
1403 +
1404 +      if (title) {
1405 +        if ((XStringListToTextProperty (((char **) &title), 1,
1406 +                    &xproperty)) != 0) {
1407 +          XSetWMName (self->dcontext->x_display, xwindow->window,
1408 +              &xproperty);
1409 +          XFree (xproperty.value);
1410 +        }
1411 +
1412 +        g_free (title_mem);
1413 +      }
1414 +    }
1415 +  }
1416 +}
1417 +
1418 +static GstDRI2Window *
1419 +gst_dri2videosink_create_window (GstDRI2VideoSink * self, gint width,
1420 +    gint height)
1421 +{
1422 +  GstDRI2Window *xwindow;
1423 +
1424 +  GST_DEBUG_OBJECT (self, "begin");
1425 +
1426 +  xwindow = gst_dri2window_new (self->dcontext, width, height);
1427 +
1428 +  g_mutex_lock (self->dcontext->x_lock);
1429 +  gst_dri2videosink_xwindow_set_title (self, xwindow, NULL);
1430 +  gst_dri2videosink_xwindow_update_geometry (self);
1431 +  g_mutex_unlock (self->dcontext->x_lock);
1432 +
1433 +  GST_DEBUG_OBJECT (self, "end");
1434 +
1435 +  return xwindow;
1436 +}
1437 +
1438 +static GstDRI2Window *
1439 +gst_dri2videosink_get_window (GstDRI2VideoSink * self)
1440 +{
1441 +  if (!self->xwindow) {
1442 +    self->xwindow = gst_dri2videosink_create_window (self,
1443 +        GST_VIDEO_SINK_WIDTH (self),
1444 +        GST_VIDEO_SINK_HEIGHT (self));
1445 +  }
1446 +  return self->xwindow;
1447 +}
1448 +
1449 +/* Element stuff */
1450 +
1451 +static gboolean
1452 +gst_dri2videosink_configure_overlay (GstDRI2VideoSink * self, gint width,
1453 +    gint height, gint video_par_n, gint video_par_d, gint display_par_n,
1454 +    gint display_par_d)
1455 +{
1456 +  guint calculated_par_n;
1457 +  guint calculated_par_d;
1458 +
1459 +  if (!gst_video_calculate_display_ratio (&calculated_par_n, &calculated_par_d,
1460 +          width, height, video_par_n, video_par_d, display_par_n,
1461 +          display_par_d)) {
1462 +    GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, (NULL),
1463 +        ("Error calculating the output display ratio of the video."));
1464 +    return FALSE;
1465 +  }
1466 +
1467 +  GST_DEBUG_OBJECT (self,
1468 +      "video width/height: %dx%d, calculated display ratio: %d/%d",
1469 +      width, height, calculated_par_n, calculated_par_d);
1470 +
1471 +  /* now find a width x height that respects this display ratio.
1472 +   * prefer those that have one of w/h the same as the incoming video
1473 +   * using wd / hd = calculated_pad_n / calculated_par_d */
1474 +
1475 +  /* start with same height, because of interlaced video */
1476 +  /* check hd / calculated_par_d is an integer scale factor, and scale wd with the PAR */
1477 +  if (height % calculated_par_d == 0) {
1478 +    GST_DEBUG_OBJECT (self, "keeping video height");
1479 +    GST_VIDEO_SINK_WIDTH (self) = (guint)
1480 +        gst_util_uint64_scale_int (height, calculated_par_n, calculated_par_d);
1481 +    GST_VIDEO_SINK_HEIGHT (self) = height;
1482 +  } else if (width % calculated_par_n == 0) {
1483 +    GST_DEBUG_OBJECT (self, "keeping video width");
1484 +    GST_VIDEO_SINK_WIDTH (self) = width;
1485 +    GST_VIDEO_SINK_HEIGHT (self) = (guint)
1486 +        gst_util_uint64_scale_int (width, calculated_par_d, calculated_par_n);
1487 +  } else {
1488 +    GST_DEBUG_OBJECT (self, "approximating while keeping video height");
1489 +    GST_VIDEO_SINK_WIDTH (self) = (guint)
1490 +        gst_util_uint64_scale_int (height, calculated_par_n, calculated_par_d);
1491 +    GST_VIDEO_SINK_HEIGHT (self) = height;
1492 +  }
1493 +  GST_DEBUG_OBJECT (self, "scaling to %dx%d",
1494 +      GST_VIDEO_SINK_WIDTH (self),
1495 +      GST_VIDEO_SINK_HEIGHT (self));
1496 +
1497 +  return TRUE;
1498 +}
1499 +
1500 +static gboolean
1501 +gst_dri2videosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
1502 +{
1503 +  GstDRI2VideoSink *self;
1504 +  gboolean ret = TRUE;
1505 +  GstStructure *structure;
1506 +  gint width, height;
1507 +  const GValue *fps;
1508 +  const GValue *caps_par;
1509 +
1510 +  self = GST_DRI2VIDEOSINK (bsink);
1511 +
1512 +  GST_DEBUG_OBJECT (self,
1513 +      "sinkconnect possible caps with given caps %", caps);
1514 +
1515 +  if (self->current_caps) {
1516 +    GST_DEBUG_OBJECT (self, "already have caps set");
1517 +    if (gst_caps_is_equal (self->current_caps, caps)) {
1518 +      GST_DEBUG_OBJECT (self, "caps are equal!");
1519 +      return TRUE;
1520 +    }
1521 +    GST_DEBUG_OBJECT (self, "caps are different");
1522 +  }
1523 +
1524 +  structure = gst_caps_get_structure (caps, 0);
1525 +
1526 +  ret = gst_video_format_parse_caps_strided (caps, &self->format,
1527 +      &width, &height, &self->rowstride);
1528 +  if (self->rowstride == 0)
1529 +    self->rowstride =
1530 +        gst_video_format_get_row_stride (self->format, 0, width);
1531 +  fps = gst_structure_get_value (structure, "framerate");
1532 +  ret &= (fps != NULL);
1533 +  if (!ret) {
1534 +    GST_ERROR_OBJECT (self, "problem at parsing caps");
1535 +    return FALSE;
1536 +  }
1537 +
1538 +  self->video_width = width;
1539 +  self->video_height = height;
1540 +
1541 +  /* figure out if we are dealing w/ interlaced */
1542 +  self->interlaced = FALSE;
1543 +  gst_structure_get_boolean (structure, "interlaced",
1544 +      &self->interlaced);
1545 +
1546 +  /* get video's pixel-aspect-ratio */
1547 +  caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
1548 +  if (caps_par) {
1549 +    self->video_par_n = gst_value_get_fraction_numerator (caps_par);
1550 +    self->video_par_d = gst_value_get_fraction_denominator (caps_par);
1551 +  } else {
1552 +    self->video_par_n = 1;
1553 +    self->video_par_d = 1;
1554 +  }
1555 +
1556 +  /* get display's pixel-aspect-ratio */
1557 +  if (self->display_par) {
1558 +    self->display_par_n =
1559 +        gst_value_get_fraction_numerator (self->display_par);
1560 +    self->display_par_d =
1561 +        gst_value_get_fraction_denominator (self->display_par);
1562 +  } else {
1563 +    self->display_par_n = 1;
1564 +    self->display_par_d = 1;
1565 +  }
1566 +
1567 +  if (!gst_dri2videosink_configure_overlay (self, width, height,
1568 +          self->video_par_n, self->video_par_d,
1569 +          self->display_par_n, self->display_par_d))
1570 +    return FALSE;
1571 +
1572 +  /* Notify application to set xwindow id now */
1573 +  g_mutex_lock (self->flow_lock);
1574 +  if (!self->xwindow) {
1575 +    g_mutex_unlock (self->flow_lock);
1576 +    gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (self));
1577 +  } else {
1578 +    g_mutex_unlock (self->flow_lock);
1579 +  }
1580 +
1581 +  g_mutex_lock (self->flow_lock);
1582 +
1583 +  gst_dri2window_check_caps (
1584 +      gst_dri2videosink_get_window (self), caps);
1585 +
1586 +  g_mutex_unlock (self->flow_lock);
1587 +
1588 +  gst_dri2videosink_set_event_handling (GST_X_OVERLAY (self), TRUE);
1589 +
1590 +  self->fps_n = gst_value_get_fraction_numerator (fps);
1591 +  self->fps_d = gst_value_get_fraction_denominator (fps);
1592 +
1593 +  self->current_caps = gst_caps_ref (caps);
1594 +
1595 +  return TRUE;
1596 +}
1597 +
1598 +static GstCaps *
1599 +gst_dri2videosink_getcaps (GstBaseSink * bsink)
1600 +{
1601 +  return gst_caps_copy (gst_pad_get_pad_template_caps (bsink->sinkpad));
1602 +}
1603 +
1604 +static GstStateChangeReturn
1605 +gst_dri2videosink_change_state (GstElement * element, GstStateChange transition)
1606 +{
1607 +  GstDRI2VideoSink *self;
1608 +  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1609 +  GstDRI2Context *dcontext;
1610 +
1611 +  self = GST_DRI2VIDEOSINK (element);
1612 +
1613 +  GST_DEBUG_OBJECT (self, "%d -> %d",
1614 +      GST_STATE_TRANSITION_CURRENT (transition),
1615 +      GST_STATE_TRANSITION_NEXT (transition));
1616 +
1617 +  switch (transition) {
1618 +    case GST_STATE_CHANGE_NULL_TO_READY:
1619 +      if (self->dcontext == NULL) {
1620 +        dcontext = gst_dri2context_new (GST_ELEMENT (self));
1621 +        if (dcontext == NULL)
1622 +          return GST_STATE_CHANGE_FAILURE;
1623 +        GST_OBJECT_LOCK (self);
1624 +        self->dcontext = dcontext;
1625 +        GST_OBJECT_UNLOCK (self);
1626 +      }
1627 +
1628 +      /* update object's pixel-aspect-ratio with calculated one */
1629 +      if (!self->display_par) {
1630 +        self->display_par = g_new0 (GValue, 1);
1631 +        gst_value_init_and_copy (self->display_par,
1632 +            self->dcontext->par);
1633 +        GST_DEBUG_OBJECT (self, "set calculated PAR on object's PAR");
1634 +      }
1635 +
1636 +      gst_dri2videosink_manage_event_thread (self);
1637 +      break;
1638 +    case GST_STATE_CHANGE_READY_TO_PAUSED:
1639 +      if (self->xwindow)
1640 +        gst_dri2window_set_pool_valid (self->xwindow, TRUE);
1641 +      break;
1642 +    case GST_STATE_CHANGE_PAUSED_TO_READY:
1643 +      if (self->xwindow)
1644 +        gst_dri2window_set_pool_valid (self->xwindow, FALSE);
1645 +      break;
1646 +    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1647 +      break;
1648 +    default:
1649 +      break;
1650 +  }
1651 +
1652 +  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1653 +
1654 +  switch (transition) {
1655 +    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1656 +      break;
1657 +    case GST_STATE_CHANGE_PAUSED_TO_READY:
1658 +      self->fps_n = 0;
1659 +      self->fps_d = 1;
1660 +      GST_VIDEO_SINK_WIDTH (self) = 0;
1661 +      GST_VIDEO_SINK_HEIGHT (self) = 0;
1662 +      break;
1663 +    case GST_STATE_CHANGE_READY_TO_NULL:
1664 +      gst_dri2videosink_reset (self);
1665 +      break;
1666 +    default:
1667 +      break;
1668 +  }
1669 +
1670 +  return ret;
1671 +}
1672 +
1673 +static void
1674 +gst_dri2videosink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1675 +    GstClockTime * start, GstClockTime * end)
1676 +{
1677 +  GstDRI2VideoSink *self;
1678 +
1679 +  self = GST_DRI2VIDEOSINK (bsink);
1680 +
1681 +  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1682 +    *start = GST_BUFFER_TIMESTAMP (buf);
1683 +    if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1684 +      *end = *start + GST_BUFFER_DURATION (buf);
1685 +    } else {
1686 +      if (self->fps_n > 0) {
1687 +        *end = *start +
1688 +            gst_util_uint64_scale_int (GST_SECOND, self->fps_d,
1689 +            self->fps_n);
1690 +      }
1691 +    }
1692 +  }
1693 +}
1694 +
1695 +static GstFlowReturn
1696 +gst_dri2videosink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
1697 +{
1698 +  GstDRI2VideoSink *self = GST_DRI2VIDEOSINK (bsink);
1699 +  GstDRI2Window *xwindow;
1700 +  GstFlowReturn ret;
1701 +  GstBuffer *newbuf;
1702 +
1703 +  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
1704 +
1705 +  GST_LOG_OBJECT (self, "render buffer: %p (%"GST_TIME_FORMAT")",
1706 +      buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1707 +
1708 +  if (! GST_IS_DRI2_BUFFER (buf)) {
1709 +    /* special case check for sub-buffers:  In certain cases, places like
1710 +     * GstBaseTransform, which might check that the buffer is writable
1711 +     * before copying metadata, timestamp, and such, will find that the
1712 +     * buffer has more than one reference to it.  In these cases, they
1713 +     * will create a sub-buffer with an offset=0 and length equal to the
1714 +     * original buffer size.
1715 +     *
1716 +     * This could happen in two scenarios: (1) a tee in the pipeline, and
1717 +     * (2) because the refcnt is incremented in gst_mini_object_free()
1718 +     * before the finalize function is called, and decremented after it
1719 +     * returns..  but returning this buffer to the buffer pool in the
1720 +     * finalize function, could wake up a thread blocked in _buffer_alloc()
1721 +     * which could run and get a buffer w/ refcnt==2 before the thread
1722 +     * originally unref'ing the buffer returns from finalize function and
1723 +     * decrements the refcnt back to 1!
1724 +     */
1725 +    if (buf->parent &&
1726 +        (GST_BUFFER_DATA (buf) == GST_BUFFER_DATA (buf->parent)) &&
1727 +        (GST_BUFFER_SIZE (buf) == GST_BUFFER_SIZE (buf->parent))) {
1728 +      GST_DEBUG_OBJECT (self, "I have a sub-buffer!");
1729 +      return gst_dri2videosink_show_frame (bsink, buf->parent);
1730 +    }
1731 +  }
1732 +
1733 +  g_mutex_lock (self->flow_lock);
1734 +
1735 +  xwindow = gst_dri2videosink_get_window (self);
1736 +
1737 +  if (!xwindow) {
1738 +    GST_ERROR_OBJECT (self, "no drawable!");
1739 +    ret = GST_FLOW_UNEXPECTED;
1740 +    goto beach;
1741 +  }
1742 +
1743 +  newbuf = gst_dri2window_buffer_prepare (xwindow, buf);
1744 +  if (newbuf)
1745 +    buf = newbuf;
1746 +
1747 +  ret = gst_dri2window_buffer_show (xwindow, buf);
1748 +
1749 +  if (ret == GST_FLOW_OK) {
1750 +    gst_buffer_replace (&self->last_buf, self->display_buf);
1751 +    gst_buffer_replace (&self->display_buf, buf);
1752 +  }
1753 +
1754 +  if (newbuf)
1755 +    gst_buffer_unref (newbuf);
1756 +
1757 +beach:
1758 +  g_mutex_unlock (self->flow_lock);
1759 +
1760 +  return ret;
1761 +}
1762 +
1763 +
1764 +/* Buffer management
1765 + *
1766 + * The buffer_alloc function must either return a buffer with given size and
1767 + * caps or create a buffer with different caps attached to the buffer. This
1768 + * last option is called reverse negotiation, ie, where the sink suggests a
1769 + * different format from the upstream peer. 
1770 + *
1771 + * We try to do reverse negotiation when our geometry changes and we like a
1772 + * resized buffer.
1773 + */
1774 +static GstFlowReturn
1775 +gst_dri2videosink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
1776 +    GstCaps * caps, GstBuffer ** buf)
1777 +{
1778 +  GstDRI2VideoSink *self = GST_DRI2VIDEOSINK (bsink);
1779 +  GstDRI2Window *xwindow;
1780 +
1781 +  GST_LOG_OBJECT (self,
1782 +      "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT
1783 +      " and offset %" G_GUINT64_FORMAT, size, caps, offset);
1784 +
1785 +  if (G_UNLIKELY (!caps)) {
1786 +    GST_WARNING_OBJECT (self, "have no caps, doing fallback allocation");
1787 +    return GST_FLOW_OK;
1788 +  }
1789 +
1790 +  /* if we don't have caps set, just pre-emptively take the caps
1791 +   * for the buffer that is being requested..  we need caps set
1792 +   * in case we need to create our own private window, because
1793 +   * we want to know what size to create it:
1794 +   */
1795 +  if (!self->current_caps) {
1796 +    GST_DEBUG_OBJECT (self, "setting requested caps");
1797 +    gst_dri2videosink_setcaps (bsink, caps);
1798 +  }
1799 +
1800 +  xwindow = gst_dri2videosink_get_window (self);
1801 +  if (!xwindow) {
1802 +    GST_ERROR_OBJECT (self, "no drawable!");
1803 +    return GST_FLOW_UNEXPECTED;
1804 +  }
1805 +
1806 +  return gst_dri2window_buffer_alloc (xwindow, size, caps, buf);
1807 +}
1808 +
1809 +/* Interfaces stuff */
1810 +
1811 +static gboolean
1812 +gst_dri2videosink_interface_supported (GstImplementsInterface * iface,
1813 +    GType type)
1814 +{
1815 +  if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_NAVIGATION)
1816 +    return TRUE;
1817 +  else
1818 +    return FALSE;
1819 +}
1820 +
1821 +static void
1822 +gst_dri2videosink_interface_init (GstImplementsInterfaceClass * klass)
1823 +{
1824 +  klass->supported = gst_dri2videosink_interface_supported;
1825 +}
1826 +
1827 +/*
1828 + * GstXOverlay Interface:
1829 + */
1830 +
1831 +static void
1832 +gst_dri2videosink_set_window_handle (GstXOverlay * overlay, guintptr id)
1833 +{
1834 +  XID xwindow_id = id;
1835 +  GstDRI2VideoSink *self = GST_DRI2VIDEOSINK (overlay);
1836 +
1837 +  g_return_if_fail (GST_IS_DRI2VIDEOSINK (self));
1838 +
1839 +  g_mutex_lock (self->flow_lock);
1840 +
1841 +  /* If we already use that window return */
1842 +  if (self->xwindow && (xwindow_id == self->xwindow->window)) {
1843 +    g_mutex_unlock (self->flow_lock);
1844 +    return;
1845 +  }
1846 +
1847 +  /* If the element has not initialized the X11 context try to do so */
1848 +  if (!(self->dcontext ||
1849 +      (self->dcontext = gst_dri2context_new (GST_ELEMENT (self))))) {
1850 +    g_mutex_unlock (self->flow_lock);
1851 +    /* we have thrown a GST_ELEMENT_ERROR now */
1852 +    return;
1853 +  }
1854 +
1855 +  /* If a window is there already we destroy it */
1856 +  if (self->xwindow) {
1857 +    gst_dri2window_delete (self->xwindow);
1858 +    self->xwindow = NULL;
1859 +  }
1860 +
1861 +  /* If the xid is 0 we will create an internal one in buffer_alloc */
1862 +  if (xwindow_id != 0) {
1863 +    self->xwindow = gst_dri2window_new_from_handle (self->dcontext,
1864 +        xwindow_id);
1865 +    gst_dri2videosink_xwindow_update_geometry (self);
1866 +  }
1867 +
1868 +  g_mutex_unlock (self->flow_lock);
1869 +
1870 +  gst_dri2videosink_set_event_handling (overlay, TRUE);
1871 +}
1872 +
1873 +static void
1874 +gst_dri2videosink_expose (GstXOverlay * overlay)
1875 +{
1876 +  GstDRI2VideoSink *self = GST_DRI2VIDEOSINK (overlay);
1877 +
1878 +  if (self->display_buf) {
1879 +    gst_dri2videosink_show_frame (
1880 +        GST_BASE_SINK (self), self->display_buf);
1881 +  }
1882 +}
1883 +
1884 +static void
1885 +gst_dri2videosink_set_event_handling (GstXOverlay * overlay,
1886 +    gboolean handle_events)
1887 +{
1888 +  GstDRI2VideoSink *self = GST_DRI2VIDEOSINK (overlay);
1889 +  long event_mask;
1890 +
1891 +  g_mutex_lock (self->flow_lock);
1892 +
1893 +  if (G_UNLIKELY (!self->xwindow)) {
1894 +    g_mutex_unlock (self->flow_lock);
1895 +    return;
1896 +  }
1897 +
1898 +  g_mutex_lock (self->dcontext->x_lock);
1899 +
1900 +  event_mask = ExposureMask | StructureNotifyMask |
1901 +      PointerMotionMask | KeyPressMask | KeyReleaseMask;
1902 +
1903 +  if (self->xwindow->internal) {
1904 +    event_mask |= ButtonPressMask | ButtonReleaseMask;
1905 +  }
1906 +
1907 +  XSelectInput (self->dcontext->x_display,
1908 +      self->xwindow->window, event_mask);
1909 +
1910 +  g_mutex_unlock (self->dcontext->x_lock);
1911 +
1912 +  g_mutex_unlock (self->flow_lock);
1913 +}
1914 +
1915 +static void
1916 +gst_dri2videosink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
1917 +    gint width, gint height)
1918 +{
1919 +  GstDRI2VideoSink *self = GST_DRI2VIDEOSINK (overlay);
1920 +
1921 +  /* FIXME: how about some locking? */
1922 +  if (width >= 0 && height >= 0) {
1923 +    self->render_rect.x = x;
1924 +    self->render_rect.y = y;
1925 +    self->render_rect.w = width;
1926 +    self->render_rect.h = height;
1927 +    self->have_render_rect = TRUE;
1928 +  } else {
1929 +    self->render_rect.x = 0;
1930 +    self->render_rect.y = 0;
1931 +    self->render_rect.w = self->xwindow->width;
1932 +    self->render_rect.h = self->xwindow->height;
1933 +    self->have_render_rect = FALSE;
1934 +  }
1935 +  GST_DEBUG_OBJECT (self, "render_rect is %d,%d - %dX%d",
1936 +      self->render_rect.x, self->render_rect.y,
1937 +      self->render_rect.w, self->render_rect.h);
1938 +}
1939 +
1940 +static void
1941 +gst_dri2videosink_xoverlay_init (GstXOverlayClass * iface)
1942 +{
1943 +  iface->set_window_handle = gst_dri2videosink_set_window_handle;
1944 +  iface->expose = gst_dri2videosink_expose;
1945 +  iface->handle_events = gst_dri2videosink_set_event_handling;
1946 +  iface->set_render_rectangle = gst_dri2videosink_set_render_rectangle;
1947 +}
1948 +
1949 +/*
1950 + * GstNavigation Interface:
1951 + */
1952 +
1953 +static void
1954 +gst_dri2videosink_send_event (GstNavigation * navigation,
1955 +    GstStructure * structure)
1956 +{
1957 +  GstDRI2VideoSink *self = GST_DRI2VIDEOSINK (navigation);
1958 +  GstPad *peer;
1959 +
1960 +  if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (self)))) {
1961 +    GstVideoRectangle result;
1962 +    gdouble x, y, xscale = 1.0, yscale = 1.0;
1963 +
1964 +    if (self->keep_aspect) {
1965 +      GstVideoRectangle src = {
1966 +        .w = GST_VIDEO_SINK_WIDTH (self),
1967 +        .h = GST_VIDEO_SINK_HEIGHT (self),
1968 +      };
1969 +      GstVideoRectangle dst = {
1970 +        .w = self->render_rect.w,
1971 +        .h = self->render_rect.h,
1972 +      };
1973 +
1974 +      gst_video_sink_center_rect (src, dst, &result, TRUE);
1975 +      result.x += self->render_rect.x;
1976 +      result.y += self->render_rect.y;
1977 +    } else {
1978 +      result = self->render_rect;
1979 +    }
1980 +
1981 +    /* We calculate scaling using the original video frames geometry to
1982 +     * include pixel aspect ratio scaling.
1983 +     */
1984 +    xscale = (gdouble) self->video_width / result.w;
1985 +    yscale = (gdouble) self->video_height / result.h;
1986 +
1987 +    /* Note: this doesn't account for crop top/left offsets.. which
1988 +     * is probably not quite right.. OTOH, I don't think the ducati
1989 +     * decoder elements subtract back out the crop offsets as the
1990 +     * event propagates upstream, so as long as the one receiving
1991 +     * the event is upstream of the decoder, the net effect will be
1992 +     * correct..  although this might be worth fixing correctly at
1993 +     * some point.
1994 +     */
1995 +
1996 +    /* Converting pointer coordinates to the non scaled geometry */
1997 +    if (gst_structure_get_double (structure, "pointer_x", &x)) {
1998 +      x = MIN (x, result.x + result.w);
1999 +      x = MAX (x - result.x, 0);
2000 +      gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
2001 +          (gdouble) x * xscale, NULL);
2002 +    }
2003 +    if (gst_structure_get_double (structure, "pointer_y", &y)) {
2004 +      y = MIN (y, result.y + result.h);
2005 +      y = MAX (y - result.y, 0);
2006 +      gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
2007 +          (gdouble) y * yscale, NULL);
2008 +    }
2009 +
2010 +    gst_pad_send_event (peer, gst_event_new_navigation (structure));
2011 +    gst_object_unref (peer);
2012 +  }
2013 +}
2014 +
2015 +static void
2016 +gst_dri2videosink_navigation_init (GstNavigationInterface * iface)
2017 +{
2018 +  iface->send_event = gst_dri2videosink_send_event;
2019 +}
2020 +
2021 +static void
2022 +gst_dri2videosink_set_property (GObject * object, guint prop_id,
2023 +    const GValue * value, GParamSpec * pspec)
2024 +{
2025 +  GstDRI2VideoSink *self;
2026 +
2027 +  g_return_if_fail (GST_IS_DRI2VIDEOSINK (object));
2028 +
2029 +  self = GST_DRI2VIDEOSINK (object);
2030 +
2031 +  switch (prop_id) {
2032 +    case PROP_FORCE_ASPECT_RATIO:
2033 +      self->keep_aspect = g_value_get_boolean (value);
2034 +      break;
2035 +    default:
2036 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2037 +      break;
2038 +  }
2039 +}
2040 +
2041 +static void
2042 +gst_dri2videosink_get_property (GObject * object, guint prop_id,
2043 +    GValue * value, GParamSpec * pspec)
2044 +{
2045 +  GstDRI2VideoSink *self;
2046 +
2047 +  g_return_if_fail (GST_IS_DRI2VIDEOSINK (object));
2048 +
2049 +  self = GST_DRI2VIDEOSINK (object);
2050 +
2051 +  switch (prop_id) {
2052 +    case PROP_FORCE_ASPECT_RATIO:
2053 +      g_value_set_boolean (value, self->keep_aspect);
2054 +      break;
2055 +    default:
2056 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2057 +      break;
2058 +  }
2059 +}
2060 +
2061 +static void
2062 +gst_dri2videosink_reset (GstDRI2VideoSink * self)
2063 +{
2064 +  GThread *thread;
2065 +
2066 +  GST_OBJECT_LOCK (self);
2067 +  self->running = FALSE;
2068 +  thread = self->event_thread;
2069 +  self->event_thread = NULL;
2070 +  GST_OBJECT_UNLOCK (self);
2071 +
2072 +  if (thread)
2073 +    g_thread_join (thread);
2074 +
2075 +  gst_buffer_replace (&self->last_buf, NULL);
2076 +  gst_buffer_replace (&self->display_buf, NULL);
2077 +
2078 +  self->render_rect.x = self->render_rect.y = 0;
2079 +  self->render_rect.w = self->render_rect.h = 0;
2080 +  self->have_render_rect = FALSE;
2081 +
2082 +  if (self->xwindow) {
2083 +    gst_dri2window_delete (self->xwindow);
2084 +    self->xwindow = NULL;
2085 +  }
2086 +
2087 +  g_free (self->display_par);
2088 +  self->display_par = NULL;
2089 +  GST_OBJECT_LOCK (self);
2090 +  if (self->dcontext)
2091 +    gst_dri2context_delete (self->dcontext);
2092 +  self->dcontext = NULL;
2093 +  GST_OBJECT_UNLOCK (self);
2094 +}
2095 +
2096 +static void
2097 +gst_dri2videosink_finalize (GObject * object)
2098 +{
2099 +  GstDRI2VideoSink *self;
2100 +
2101 +  self = GST_DRI2VIDEOSINK (object);
2102 +
2103 +  gst_dri2videosink_reset (self);
2104 +
2105 +  if (self->flow_lock) {
2106 +    g_mutex_free (self->flow_lock);
2107 +    self->flow_lock = NULL;
2108 +  }
2109 +
2110 +  G_OBJECT_CLASS (parent_class)->finalize (object);
2111 +}
2112 +
2113 +static void
2114 +gst_dri2videosink_init (GstDRI2VideoSink * self)
2115 +{
2116 +  self->running = FALSE;
2117 +
2118 +  self->fps_n = 0;
2119 +  self->fps_d = 1;
2120 +  self->video_width = 0;
2121 +  self->video_height = 0;
2122 +
2123 +  self->flow_lock = g_mutex_new ();
2124 +
2125 +  self->keep_aspect = FALSE;
2126 +  self->current_caps = NULL;
2127 +  self->dcontext = NULL;
2128 +  self->xwindow = NULL;
2129 +  self->display_buf = NULL;
2130 +  self->event_thread = NULL;
2131 +  self->display_par = NULL;
2132 +}
2133 +
2134 +static void
2135 +gst_dri2videosink_base_init (gpointer g_class)
2136 +{
2137 +  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
2138 +
2139 +  gst_element_class_set_details_simple (element_class,
2140 +      "DRI2 Video sink", "Sink/Video",
2141 +      "dri2videosink",
2142 +      "Rob Clark <rob@ti.com>");
2143 +
2144 +  gst_element_class_add_pad_template (element_class,
2145 +      gst_static_pad_template_get (&gst_dri2videosink_sink_template_factory));
2146 +}
2147 +
2148 +static void
2149 +gst_dri2videosink_class_init (GstDRI2VideoSinkClass * klass)
2150 +{
2151 +  GObjectClass *gobject_class;
2152 +  GstElementClass *gstelement_class;
2153 +  GstBaseSinkClass *gstbasesink_class;
2154 +
2155 +  gobject_class = (GObjectClass *) klass;
2156 +  gstelement_class = (GstElementClass *) klass;
2157 +  gstbasesink_class = (GstBaseSinkClass *) klass;
2158 +
2159 +  parent_class = g_type_class_peek_parent (klass);
2160 +
2161 +  gobject_class->finalize = gst_dri2videosink_finalize;
2162 +  gobject_class->set_property = gst_dri2videosink_set_property;
2163 +  gobject_class->get_property = gst_dri2videosink_get_property;
2164 +
2165 +  g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
2166 +      g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
2167 +          "When enabled, reverse caps negotiation (scaling) will respect "
2168 +          "original aspect ratio", FALSE,
2169 +          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2170 +
2171 +  gstelement_class->change_state = gst_dri2videosink_change_state;
2172 +
2173 +  gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_dri2videosink_setcaps);
2174 +  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_dri2videosink_getcaps);
2175 +  gstbasesink_class->buffer_alloc =
2176 +      GST_DEBUG_FUNCPTR (gst_dri2videosink_buffer_alloc);
2177 +  gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_dri2videosink_get_times);
2178 +
2179 +  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_dri2videosink_show_frame);
2180 +}
2181 +
2182 +GType
2183 +gst_dri2videosink_get_type (void)
2184 +{
2185 +  static GType self_type = 0;
2186 +
2187 +  if (!self_type) {
2188 +    static const GTypeInfo self_info = {
2189 +      sizeof (GstDRI2VideoSinkClass),
2190 +      gst_dri2videosink_base_init,
2191 +      NULL,
2192 +      (GClassInitFunc) gst_dri2videosink_class_init,
2193 +      NULL,
2194 +      NULL,
2195 +      sizeof (GstDRI2VideoSink), 0, (GInstanceInitFunc) gst_dri2videosink_init,
2196 +    };
2197 +    static const GInterfaceInfo iface_info = {
2198 +      (GInterfaceInitFunc) gst_dri2videosink_interface_init, NULL, NULL,
2199 +    };
2200 +    static const GInterfaceInfo overlay_info = {
2201 +      (GInterfaceInitFunc) gst_dri2videosink_xoverlay_init, NULL, NULL,
2202 +    };
2203 +    static const GInterfaceInfo navigation_info = {
2204 +      (GInterfaceInitFunc) gst_dri2videosink_navigation_init, NULL, NULL,
2205 +    };
2206 +
2207 +    self_type = g_type_register_static (GST_TYPE_VIDEO_SINK,
2208 +        "GstDRI2VideoSink", &self_info, 0);
2209 +
2210 +    g_type_add_interface_static (self_type,
2211 +        GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
2212 +    g_type_add_interface_static (self_type, GST_TYPE_X_OVERLAY,
2213 +        &overlay_info);
2214 +    g_type_add_interface_static (self_type, GST_TYPE_NAVIGATION,
2215 +        &navigation_info);
2216 +  }
2217 +
2218 +  return self_type;
2219 +}
2220 diff --git a/sys/dri2/gstdri2videosink.h b/sys/dri2/gstdri2videosink.h
2221 new file mode 100644
2222 index 0000000..c2cd061
2223 --- /dev/null
2224 +++ b/sys/dri2/gstdri2videosink.h
2225 @@ -0,0 +1,101 @@
2226 +/*
2227 + * GStreamer
2228 + *
2229 + * Copyright (C) 2012 Texas Instruments
2230 + * Copyright (C) 2012 Collabora Ltd
2231 + *
2232 + * Authors:
2233 + *  Alessandro Decina <alessandro.decina@collabora.co.uk>
2234 + *  Rob Clark <rob.clark@linaro.org>
2235 + *
2236 + * This library is free software; you can redistribute it and/or
2237 + * modify it under the terms of the GNU Lesser General Public
2238 + * License as published by the Free Software Foundation
2239 + * version 2.1 of the License.
2240 + *
2241 + * This library is distributed in the hope that it will be useful,
2242 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2243 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2244 + * Lesser General Public License for more details.
2245 + *
2246 + * You should have received a copy of the GNU Lesser General Public
2247 + * License along with this library; if not, write to the Free Software
2248 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
2249 + */
2250 +
2251 +#ifndef __GST_DRI2VIDEOSINK_H__
2252 +#define __GST_DRI2VIDEOSINK_H__
2253 +
2254 +#include <gst/video/gstvideosink.h>
2255 +
2256 +#include "gstdri2util.h"
2257 +
2258 +G_BEGIN_DECLS
2259 +#define GST_TYPE_DRI2VIDEOSINK (gst_dri2videosink_get_type())
2260 +#define GST_DRI2VIDEOSINK(obj) \
2261 +  (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_DRI2VIDEOSINK, GstDRI2VideoSink))
2262 +#define GST_DRI2VIDEOSINK_CLASS(klass) \
2263 +  (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_DRI2VIDEOSINK, GstDRI2VideoSinkClass))
2264 +#define GST_IS_DRI2VIDEOSINK(obj) \
2265 +  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_DRI2VIDEOSINK))
2266 +#define GST_IS_DRI2VIDEOSINK_CLASS(klass) \
2267 +  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_DRI2VIDEOSINK))
2268 +
2269 +typedef struct _GstDRI2VideoSink GstDRI2VideoSink;
2270 +typedef struct _GstDRI2VideoSinkClass GstDRI2VideoSinkClass;
2271 +
2272 +struct _GstDRI2VideoSink
2273 +{
2274 +  /* Our parent class */
2275 +  GstVideoSink videosink;
2276 +
2277 +  gboolean running;
2278 +
2279 +  /* Framerate numerator and denominator */
2280 +  gint fps_n, fps_d;
2281 +  /* size of incoming video */
2282 +  guint video_width, video_height;
2283 +
2284 +  GstVideoFormat format;
2285 +  gint rowstride;
2286 +  gboolean interlaced;
2287 +
2288 +  GThread *event_thread;
2289 +  GMutex *flow_lock;
2290 +
2291 +  gboolean keep_aspect;
2292 +
2293 +  GstCaps *current_caps;
2294 +  GstDRI2Context *dcontext;
2295 +  GstDRI2Window *xwindow;
2296 +
2297 +  GstVideoRectangle render_rect;
2298 +  gboolean have_render_rect;
2299 +
2300 +  GValue *display_par;
2301 +  gint video_par_n;
2302 +  gint video_par_d;
2303 +  gint display_par_n;
2304 +  gint display_par_d;
2305 +
2306 +  gchar *media_title;
2307 +  GstBuffer *display_buf;
2308 +
2309 +  /* also keep the last buffer, to give the GPU some time to finish
2310 +   * it's blit.. the decoder will block if the buffer isn't done yet
2311 +   * for correctness, but really we'd like to minimize that and keep
2312 +   * the GPU pipeline full, so we hold back the last buffer from the
2313 +   * pool for one extra frame.
2314 +   */
2315 +  GstBuffer *last_buf;
2316 +};
2317 +
2318 +struct _GstDRI2VideoSinkClass
2319 +{
2320 +  GstVideoSinkClass parent_class;
2321 +};
2322 +
2323 +GType gst_dri2videosink_get_type (void);
2324 +
2325 +G_END_DECLS
2326 +#endif /* __GST_DRI2VIDEOSINK_H__ */
2327 -- 
2328 1.7.9.5
2329