xvimagesink.c 70.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* GStreamer
 * Copyright (C) <2003> Julien Moutte <julien@moutte.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
19

20
21
22
23
24
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* Our interfaces */
25
26
27
#include <gst/interfaces/navigation.h>
#include <gst/interfaces/xoverlay.h>
#include <gst/interfaces/colorbalance.h>
28
29
30
31

/* Object header */
#include "xvimagesink.h"

32
33
34
35
36
/* Debugging category */
#include <gst/gstinfo.h>
GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
#define GST_CAT_DEFAULT gst_debug_xvimagesink

37
38
39
40
41
42
43
44
45
46
47
48
typedef struct
{
  unsigned long flags;
  unsigned long functions;
  unsigned long decorations;
  long input_mode;
  unsigned long status;
}
MotifWmHints, MwmHints;

#define MWM_HINTS_DECORATIONS   (1L << 1)

49
50
static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);

51
//static void gst_xvimagesink_send_pending_navigation (GstXvImageSink * xvimagesink);
52

53
/* ElementFactory information */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
54
55
56
57
58
static GstElementDetails gst_xvimagesink_details =
GST_ELEMENT_DETAILS ("Video sink",
    "Sink/Video",
    "A Xv based videosink",
    "Julien Moutte <julien@moutte.net>");
59
60
61

/* Default template - initiated with class struct to allow gst-register to work
   without X running */
David Schleef's avatar
David Schleef committed
62
static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
63
64
65
66
    GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-raw-rgb, "
67
        "framerate = (double) [ 0.0, MAX ], "
68
69
        "width = (int) [ 1, MAX ], "
        "height = (int) [ 1, MAX ]; "
70
        "video/x-raw-yuv, "
71
        "framerate = (double) [ 0.0, MAX ], "
72
        "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
73
74
75
76
    );

enum
{
77
78
79
80
81
  ARG_0,
  ARG_CONTRAST,
  ARG_BRIGHTNESS,
  ARG_HUE,
  ARG_SATURATION,
82
  ARG_DISPLAY,
83
84
  ARG_SYNCHRONOUS,
  ARG_PIXEL_ASPECT_RATIO
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
85
      /* FILL ME */
86
87
};

88
static GstVideoSinkClass *parent_class = NULL;
89
90
91
92
93
94
95

/* ============================================================= */
/*                                                               */
/*                       Private Methods                         */
/*                                                               */
/* ============================================================= */

96
97
98
99
100
101
102
103
104
/* xvimage buffers */

#define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())

#define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
#define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))

/* This function destroys a GstXvImage handling XShm availability */
static void
Wim Taymans's avatar
Wim Taymans committed
105
gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
106
107
108
109
{
  GstXvImageSink *xvimagesink;

  xvimagesink = xvimage->xvimagesink;
Wim Taymans's avatar
Wim Taymans committed
110
111
  if (xvimagesink == NULL)
    goto no_sink;
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));

  /* If the destroyed image is the current one we destroy our reference too */
  if (xvimagesink->cur_image == xvimage)
    xvimagesink->cur_image = NULL;

  g_mutex_lock (xvimagesink->x_lock);

#ifdef HAVE_XSHM
  if (xvimagesink->xcontext->use_xshm) {
    if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
      XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
      XSync (xvimagesink->xcontext->disp, FALSE);
      shmdt (xvimage->SHMInfo.shmaddr);
    }
    if (xvimage->SHMInfo.shmid > 0)
      shmctl (xvimage->SHMInfo.shmid, IPC_RMID, 0);
    if (xvimage->xvimage)
      XFree (xvimage->xvimage);
  } else
#endif /* HAVE_XSHM */
  {
    if (xvimage->xvimage) {
      if (xvimage->xvimage->data) {
        g_free (xvimage->xvimage->data);
      }
      XFree (xvimage->xvimage);
    }
  }

  XSync (xvimagesink->xcontext->disp, FALSE);

  g_mutex_unlock (xvimagesink->x_lock);
Wim Taymans's avatar
Wim Taymans committed
146

147
148
149
  xvimage->xvimagesink = NULL;
  gst_object_unref (xvimagesink);

Wim Taymans's avatar
Wim Taymans committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  return;

no_sink:
  {
    GST_WARNING ("no sink found");
    return;
  }
}

static void
gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
{
  GstXvImageSink *xvimagesink;

  xvimagesink = xvimage->xvimagesink;
  if (xvimagesink == NULL)
    goto no_sink;

  /* If our geometry changed we can't reuse that image. */
  if ((xvimage->width != xvimagesink->video_width) ||
      (xvimage->height != xvimagesink->video_height)) {
    GST_DEBUG ("destroy image as its size changed %dx%d vs current %dx%d",
        xvimage->width, xvimage->height,
        xvimagesink->video_width, xvimagesink->video_height);
    gst_xvimage_buffer_destroy (xvimage);
  } else {
    /* In that case we can reuse the image and add it to our image pool. */
    GST_DEBUG ("recycling image in pool");
    /* need to increment the refcount again to recycle */
    gst_buffer_ref (GST_BUFFER (xvimage));
    g_mutex_lock (xvimagesink->pool_lock);
    xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
        xvimage);
    g_mutex_unlock (xvimagesink->pool_lock);
  }
  return;

no_sink:
  {
    GST_WARNING ("no sink found");
    return;
  }
192
193
}

Wim Taymans's avatar
Wim Taymans committed
194
195
196
197
198
199
200
201
static void
gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
{
  /* make sure it is not recycled */
  xvimage->width = -1;
  xvimage->height = -1;
  gst_buffer_unref (GST_BUFFER (xvimage));
}
202
203

static void
204
gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
205
{
206
#ifdef HAVE_XSHM
207
208
  xvimage->SHMInfo.shmaddr = ((void *) -1);
  xvimage->SHMInfo.shmid = -1;
209
#endif
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
}

static void
gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
{
  GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);

  mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
      gst_xvimage_buffer_finalize;
}

GType
gst_xvimage_buffer_get_type (void)
{
  static GType _gst_xvimage_buffer_type;

  if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
    static const GTypeInfo xvimage_buffer_info = {
      sizeof (GstBufferClass),
      NULL,
      NULL,
      gst_xvimage_buffer_class_init,
      NULL,
      NULL,
      sizeof (GstXvImageBuffer),
      0,
236
      (GInstanceInitFunc) gst_xvimage_buffer_init,
237
238
239
240
241
242
243
244
      NULL
    };
    _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
        "GstXvImageBuffer", &xvimage_buffer_info, 0);
  }
  return _gst_xvimage_buffer_type;
}

245
246
/* X11 stuff */

247
248
249
#ifdef HAVE_XSHM
static gboolean error_caught = FALSE;

Julien Moutte's avatar
Julien Moutte committed
250
static int
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
251
gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
Julien Moutte's avatar
Julien Moutte committed
252
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
253
254
  char error_msg[1024];

Julien Moutte's avatar
Julien Moutte committed
255
  XGetErrorText (display, xevent->error_code, error_msg, 1024);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
256
  GST_DEBUG ("xvimagesink failed to use XShm calls. error: %s", error_msg);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
257
  error_caught = TRUE;
Julien Moutte's avatar
Julien Moutte committed
258
259
260
261
262
263
  return 0;
}

/* This function checks that it is actually really possible to create an image
   using XShm */
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
264
gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
Julien Moutte's avatar
Julien Moutte committed
265
{
266
267
268
  XvImage *xvimage;
  XShmSegmentInfo SHMInfo;
  gint size;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
269
  int (*handler) (Display *, XErrorEvent *);
Tim Ringenbach's avatar
Tim Ringenbach committed
270
  gboolean result = FALSE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
271

Julien Moutte's avatar
Julien Moutte committed
272
  g_return_val_if_fail (xcontext != NULL, FALSE);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
273

Julien Moutte's avatar
Julien Moutte committed
274
  /* Setting an error handler to catch failure */
Tim Ringenbach's avatar
Tim Ringenbach committed
275
  error_caught = FALSE;
Julien Moutte's avatar
Julien Moutte committed
276
  handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
277

Julien Moutte's avatar
Julien Moutte committed
278
  /* Trying to create a 1x1 picture */
279
  GST_DEBUG ("XvShmCreateImage of 1x1");
280
281
282
  xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
      xcontext->im_format, NULL, 1, 1, &SHMInfo);
  if (!xvimage) {
283
284
285
    GST_WARNING ("could not XvShmCreateImage a 1x1 image");
    goto beach;
  }
286
  size = xvimage->data_size;
Julien Moutte's avatar
Julien Moutte committed
287

288
289
290
  SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
  if (SHMInfo.shmid == -1) {
    GST_WARNING ("could not get shared memory of %d bytes", size);
291
292
293
    goto beach;
  }

294
295
  SHMInfo.shmaddr = shmat (SHMInfo.shmid, 0, 0);
  if (SHMInfo.shmaddr == ((void *) -1)) {
296
297
298
299
    GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
    goto beach;
  }

300
301
  xvimage->data = SHMInfo.shmaddr;
  SHMInfo.readOnly = FALSE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
302

303
  if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
304
305
306
    GST_WARNING ("Failed to XShmAttach");
    goto beach;
  }
Julien Moutte's avatar
Julien Moutte committed
307

308
309
310
311
312
  /* store whether we succeeded in result and reset error_caught */
  result = !error_caught;
  error_caught = FALSE;

beach:
Tim Ringenbach's avatar
Tim Ringenbach committed
313
  XSetErrorHandler (handler);
314

Tim Ringenbach's avatar
Tim Ringenbach committed
315
  XSync (xcontext->disp, FALSE);
316
317
318
319
320
321
322
323
324
  if (SHMInfo.shmaddr != ((void *) -1)) {
    XShmDetach (xcontext->disp, &SHMInfo);
    XSync (xcontext->disp, FALSE);
    shmdt (SHMInfo.shmaddr);
  }
  if (SHMInfo.shmid > 0)
    shmctl (SHMInfo.shmid, IPC_RMID, 0);
  if (xvimage)
    XFree (xvimage);
Tim Ringenbach's avatar
Tim Ringenbach committed
325
  return result;
Julien Moutte's avatar
Julien Moutte committed
326
}
327
#endif /* HAVE_XSHM */
Julien Moutte's avatar
Julien Moutte committed
328

329
/* This function handles GstXvImage creation depending on XShm availability */
330
static GstXvImageBuffer *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
331
332
gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink,
    gint width, gint height)
333
{
334
  GstXvImageBuffer *xvimage = NULL;
335
  gboolean succeeded = FALSE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
336

337
  g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
338
  GST_LOG_OBJECT (xvimagesink, "creating %dx%d", width, height);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
339

340
  xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
341

342
343
  xvimage->width = width;
  xvimage->height = height;
344
  xvimage->im_format = xvimagesink->xcontext->im_format;
345
  xvimage->xvimagesink = gst_object_ref (xvimagesink);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
346

347
348
349
  g_mutex_lock (xvimagesink->x_lock);

#ifdef HAVE_XSHM
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
350
351
  if (xvimagesink->xcontext->use_xshm) {
    xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
352
        xvimagesink->xcontext->xv_port_id,
353
354
        xvimage->im_format, NULL,
        xvimage->width, xvimage->height, &xvimage->SHMInfo);
355
356
357
358
359
360
361
    if (!xvimage->xvimage) {
      GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL),
          ("could not XvShmCreateImage a %dx%d image"));
      goto beach;
    }

    /* we have to use the returned data_size for our shm size */
362
    xvimage->size = xvimage->xvimage->data_size;
363
    GST_LOG_OBJECT (xvimagesink, "XShm image size is %d", xvimage->size);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
364
365

    xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
366
        IPC_CREAT | 0777);
367
368
369
370
371
    if (xvimage->SHMInfo.shmid == -1) {
      GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL),
          ("could not get shared memory of %d bytes", xvimage->size));
      goto beach;
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
372
373

    xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, 0, 0);
374
    if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
375
376
377
378
      GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL),
          ("Failed to shmat: %s", g_strerror (errno)));
      goto beach;
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
379

380
    xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
381
382
    xvimage->SHMInfo.readOnly = FALSE;

383
384
385
386
387
    if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
      GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL),
          ("Failed to XShmAttach"));
      goto beach;
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
388
389
390

    XSync (xvimagesink->xcontext->disp, FALSE);
  } else
Julien Moutte's avatar
Julien Moutte committed
391
#endif /* HAVE_XSHM */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
392
393
  {
    xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
394
        xvimagesink->xcontext->xv_port_id,
395
        xvimage->im_format, NULL, xvimage->width, xvimage->height);
396
397
398
399
400
    if (!xvimage->xvimage) {
      GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL),
          ("could not XvCreateImage a %dx%d image"));
      goto beach;
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
401

402
    /* we have to use the returned data_size for our image size */
403
404
    xvimage->size = xvimage->xvimage->data_size;
    xvimage->xvimage->data = g_malloc (xvimage->size);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
405
406
407

    XSync (xvimagesink->xcontext->disp, FALSE);
  }
408
  succeeded = TRUE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
409

410
411
412
  GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
  GST_BUFFER_SIZE (xvimage) = xvimage->size;

413
beach:
414
415
  g_mutex_unlock (xvimagesink->x_lock);

416
  if (!succeeded) {
Wim Taymans's avatar
Wim Taymans committed
417
    gst_xvimage_buffer_free (xvimage);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
418
419
    xvimage = NULL;
  }
420

421
422
423
424
425
  return xvimage;
}

/* This function puts a GstXvImage on a GstXvImageSink's window */
static void
426
427
gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
    GstXvImageBuffer * xvimage)
428
429
430
{
  g_return_if_fail (xvimage != NULL);
  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
431
  g_return_if_fail (xvimagesink->xwindow != NULL);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
432

433
434
435
  /* Store a reference to the last image we put */
  if (xvimagesink->cur_image != xvimage)
    xvimagesink->cur_image = xvimage;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
436

437
  g_mutex_lock (xvimagesink->x_lock);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
438

439
  /* We scale to the window's geometry */
440
#ifdef HAVE_XSHM
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
441
  if (xvimagesink->xcontext->use_xshm) {
442
443
444
445
    GST_LOG_OBJECT (xvimagesink,
        "XvShmPutImage with image %dx%d and window %dx%d",
        xvimage->width, xvimage->height,
        xvimagesink->xwindow->width, xvimagesink->xwindow->height);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
446
    XvShmPutImage (xvimagesink->xcontext->disp,
447
448
449
450
451
        xvimagesink->xcontext->xv_port_id,
        xvimagesink->xwindow->win,
        xvimagesink->xwindow->gc, xvimage->xvimage,
        0, 0, xvimage->width, xvimage->height,
        0, 0, xvimagesink->xwindow->width, xvimagesink->xwindow->height, FALSE);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
452
  } else
Julien Moutte's avatar
Julien Moutte committed
453
#endif /* HAVE_XSHM */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
454
455
  {
    XvPutImage (xvimagesink->xcontext->disp,
456
457
458
459
460
        xvimagesink->xcontext->xv_port_id,
        xvimagesink->xwindow->win,
        xvimagesink->xwindow->gc, xvimage->xvimage,
        0, 0, xvimage->width, xvimage->height,
        0, 0, xvimagesink->xwindow->width, xvimagesink->xwindow->height);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
461
462
463
464
  }

  XSync (xvimagesink->xcontext->disp, FALSE);

465
466
467
  g_mutex_unlock (xvimagesink->x_lock);
}

468
469
470
471
472
473
474
475
476
477
static gboolean
gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
    GstXWindow * window)
{
  Atom hints_atom = None;
  MotifWmHints *hints;

  g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
  g_return_val_if_fail (window != NULL, FALSE);

478
479
  g_mutex_lock (xvimagesink->x_lock);

480
  hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS", 1);
481
  if (hints_atom == None) {
482
    g_mutex_unlock (xvimagesink->x_lock);
483
484
485
    return FALSE;
  }

486
487
  hints = g_malloc0 (sizeof (MotifWmHints));

488
489
490
491
492
493
494
495
496
  hints->flags |= MWM_HINTS_DECORATIONS;
  hints->decorations = 1 << 0;

  XChangeProperty (xvimagesink->xcontext->disp, window->win,
      hints_atom, hints_atom, 32, PropModeReplace,
      (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));

  XSync (xvimagesink->xcontext->disp, FALSE);

497
498
  g_mutex_unlock (xvimagesink->x_lock);

499
500
501
502
503
  g_free (hints);

  return TRUE;
}

504
505
/* This function handles a GstXWindow creation
 * The width and height are the actual pixel size on the display */
506
static GstXWindow *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
507
508
gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
    gint width, gint height)
509
510
511
{
  GstXWindow *xwindow = NULL;
  XGCValues values;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
512

513
  g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
514

515
  xwindow = g_new0 (GstXWindow, 1);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
516

517
518
  xwindow->width = width;
  xwindow->height = height;
Julien Moutte's avatar
Julien Moutte committed
519
  xwindow->internal = TRUE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
520

521
  g_mutex_lock (xvimagesink->x_lock);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
522

523
  xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
524
525
526
527
      xvimagesink->xcontext->root,
      0, 0, xwindow->width, xwindow->height,
      0, 0, xvimagesink->xcontext->black);

528
529
530
531
  /* We have to do that to prevent X from redrawing the background on 
   * ConfigureNotify. This takes away flickering of video when resizing. */
  XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
532
533
534
535
  XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
      StructureNotifyMask | PointerMotionMask | KeyPressMask |
      KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);

536
  xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
537
538
      xwindow->win, 0, &values);

539
  XMapRaised (xvimagesink->xcontext->disp, xwindow->win);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
540
541
542

  XSync (xvimagesink->xcontext->disp, FALSE);

543
  g_mutex_unlock (xvimagesink->x_lock);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
544

545
546
  gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow);

547
  gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (xvimagesink), xwindow->win);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
548

549
550
551
552
553
  return xwindow;
}

/* This function destroys a GstXWindow */
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
554
555
gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
    GstXWindow * xwindow)
556
557
558
{
  g_return_if_fail (xwindow != NULL);
  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
559

560
  g_mutex_lock (xvimagesink->x_lock);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
561

Julien Moutte's avatar
Julien Moutte committed
562
563
564
  /* If we did not create that window we just free the GC and let it live */
  if (xwindow->internal)
    XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win);
565
566
  else
    XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
567

568
  XFreeGC (xvimagesink->xcontext->disp, xwindow->gc);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
569
570
571

  XSync (xvimagesink->xcontext->disp, FALSE);

572
  g_mutex_unlock (xvimagesink->x_lock);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
573

574
575
576
  g_free (xwindow);
}

577
578
/* This function resizes a GstXWindow.
 * The width and height are the actual pixel size on the display. */
579
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
580
581
gst_xvimagesink_xwindow_resize (GstXvImageSink * xvimagesink,
    GstXWindow * xwindow, guint width, guint height)
582
583
584
{
  g_return_if_fail (xwindow != NULL);
  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
585

586
  g_mutex_lock (xvimagesink->x_lock);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
587

588
589
  xwindow->width = width;
  xwindow->height = height;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
590

591
  XResizeWindow (xvimagesink->xcontext->disp, xwindow->win,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
592
593
594
      xwindow->width, xwindow->height);

  XSync (xvimagesink->xcontext->disp, FALSE);
595
596
597
598

  g_mutex_unlock (xvimagesink->x_lock);
}

599
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
600
601
gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
    GstXWindow * xwindow)
602
603
604
{
  g_return_if_fail (xwindow != NULL);
  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
605

606
  g_mutex_lock (xvimagesink->x_lock);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
607

608
609
610
  XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
      xwindow->win);

611
  XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
612
613
      xvimagesink->xcontext->black);

614
  XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
615
616
      0, 0, xwindow->width, xwindow->height);

617
  XSync (xvimagesink->xcontext->disp, FALSE);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
618

619
620
621
  g_mutex_unlock (xvimagesink->x_lock);
}

622
623
624
/* This function commits our internal colorbalance settings to our grabbed Xv
   port. If the xcontext is not initialized yet it simply returns */
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
625
gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
626
627
{
  GList *channels = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
628

629
  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
630

631
632
633
  /* If we haven't initialized the X context we can't update anything */
  if (xvimagesink->xcontext == NULL)
    return;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
634

635
636
637
638
  /* For each channel of the colorbalance we calculate the correct value
     doing range conversion and then set the Xv port attribute to match our
     values. */
  channels = xvimagesink->xcontext->channels_list;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
639
640
641
642
643
644
645
646
647
648
649
650
651
652

  while (channels) {
    if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
      GstColorBalanceChannel *channel = NULL;
      gint value = 0;
      gdouble convert_coef;

      channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
      g_object_ref (channel);

      /* Our range conversion coef */
      convert_coef = (channel->max_value - channel->min_value) / 2000.0;

      if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
653
        value = (xvimagesink->hue + 1000) * convert_coef + channel->min_value;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
654
      } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
655
656
        value = (xvimagesink->saturation + 1000) * convert_coef +
            channel->min_value;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
657
      } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
658
659
        value = (xvimagesink->contrast + 1000) * convert_coef +
            channel->min_value;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
660
      } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
661
662
        value = (xvimagesink->brightness + 1000) * convert_coef +
            channel->min_value;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
663
      } else {
664
665
666
        g_warning ("got an unknown channel %s", channel->label);
        g_object_unref (channel);
        return;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
667
668
669
670
671
      }

      /* Committing to Xv port */
      g_mutex_lock (xvimagesink->x_lock);
      XvSetPortAttribute (xvimagesink->xcontext->disp,
672
673
          xvimagesink->xcontext->xv_port_id,
          XInternAtom (xvimagesink->xcontext->disp, channel->label, 1), value);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
674
675
676
      g_mutex_unlock (xvimagesink->x_lock);

      g_object_unref (channel);
677
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
678
679
    channels = g_list_next (channels);
  }
680
681
}

682
683
684
685
686
/* This function handles XEvents that might be in the queue. It generates
   GstEvent that will be sent upstream in the pipeline to handle interactivity
   and navigation. It will also listen for configure events on the window to
   trigger caps renegotiation so on the fly software scaling can work. */
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
687
gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink, GstPad * pad)
688
689
{
  XEvent e;
690
691
  guint pointer_x = 0, pointer_y = 0;
  gboolean pointer_moved = FALSE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
692

693
  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
694

695
696
697
698
  /* We get all pointer motion events, only the last position is
     interesting. */
  g_mutex_lock (xvimagesink->x_lock);
  while (XCheckWindowEvent (xvimagesink->xcontext->disp,
699
          xvimagesink->xwindow->win, PointerMotionMask, &e)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
700
701
702
703
    g_mutex_unlock (xvimagesink->x_lock);

    switch (e.type) {
      case MotionNotify:
704
705
706
707
        pointer_x = e.xmotion.x;
        pointer_y = e.xmotion.y;
        pointer_moved = TRUE;
        break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
708
      default:
709
        break;
710
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
711
712
713

    g_mutex_lock (xvimagesink->x_lock);
  }
714
715
  g_mutex_unlock (xvimagesink->x_lock);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
716
717
  if (pointer_moved) {
    GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
718
        pointer_x, pointer_y);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
719
    gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
720
        "mouse-move", 0, e.xbutton.x, e.xbutton.y);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
721
722
  }

723
724
725
  /* We get all events on our window to throw them upstream */
  g_mutex_lock (xvimagesink->x_lock);
  while (XCheckWindowEvent (xvimagesink->xcontext->disp,
726
727
728
          xvimagesink->xwindow->win,
          StructureNotifyMask | KeyPressMask |
          KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, &e)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
729
730
731
732
733
734
735
    KeySym keysym;

    /* We lock only for the X function call */
    g_mutex_unlock (xvimagesink->x_lock);

    switch (e.type) {
      case ConfigureNotify:
736
737
738
739
740
741
742
        /* Window got resized or moved. We update our data. */
        GST_DEBUG ("xvimagesink window is at %d, %d with geometry : %d,%d",
            e.xconfigure.x, e.xconfigure.y,
            e.xconfigure.width, e.xconfigure.height);
        xvimagesink->xwindow->width = e.xconfigure.width;
        xvimagesink->xwindow->height = e.xconfigure.height;
        break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
743
      case ButtonPress:
744
745
746
747
748
749
750
        /* Mouse button pressed over our window. We send upstream
           events for interactivity/navigation */
        GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
            e.xbutton.button, e.xbutton.x, e.xbutton.y);
        gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
            "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
        break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
751
      case ButtonRelease:
752
753
754
755
756
757
758
        /* Mouse button released over our window. We send upstream
           events for interactivity/navigation */
        GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
            e.xbutton.button, e.xbutton.x, e.xbutton.y);
        gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
            "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
        break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
759
760
      case KeyPress:
      case KeyRelease:
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
        /* Key pressed/released over our window. We send upstream
           events for interactivity/navigation */
        GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d",
            e.xkey.keycode, e.xkey.x, e.xkey.y);
        keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp,
            e.xkey.keycode, 0);
        if (keysym != NoSymbol) {
          gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
              e.type == KeyPress ?
              "key-press" : "key-release", XKeysymToString (keysym));
        } else {
          gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
              e.type == KeyPress ? "key-press" : "key-release", "unknown");
        }
        break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
776
      default:
777
        GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
778
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
779
780
781

    g_mutex_lock (xvimagesink->x_lock);
  }
782
783
784
  g_mutex_unlock (xvimagesink->x_lock);
}

785
786
/* This function generates a caps with all supported format by the first
   Xv grabable port we find. We store each one of the supported formats in a
787
   format list and append the format to a newly created caps that we return
788
789
   If this function does not return NULL because of an error, it also grabs
   the port via XvGrabPort */
790
static GstCaps *
791
792
gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
    GstXContext * xcontext)
793
{
794
795
  gint i;
  guint nb_adaptors;
796
  XvAdaptorInfo *adaptors;
797
798
799
  gint nb_formats;
  XvImageFormatValues *formats = NULL;
  GstCaps *caps = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
800

801
  g_return_val_if_fail (xcontext != NULL, NULL);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
802

803
  /* First let's check that XVideo extension is available */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
804
  if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
805
    GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, (NULL),
806
        ("XVideo extension is not available"));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
807
808
809
    return NULL;
  }

810
811
  /* Then we get adaptors list */
  if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
812
          &nb_adaptors, &adaptors)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
813
    GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, (NULL),
814
        ("Failed getting XV adaptors list"));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
815
816
817
    return NULL;
  }

818
  xcontext->xv_port_id = 0;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
819

820
  GST_DEBUG ("Found %u XV adaptor(s)", nb_adaptors);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
821

822
  /* Now search for an adaptor that supports XvImageMask */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
823
824
825
826
827
828
  for (i = 0; i < nb_adaptors && !xcontext->xv_port_id; i++) {
    if (adaptors[i].type & XvImageMask) {
      gint j;

      /* We found such an adaptor, looking for an available port */
      for (j = 0; j < adaptors[i].num_ports && !xcontext->xv_port_id; j++) {
829
830
831
832
        /* We try to grab the port */
        if (Success == XvGrabPort (xcontext->disp, adaptors[i].base_id + j, 0)) {
          xcontext->xv_port_id = adaptors[i].base_id + j;
        }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
833
      }
834
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
835
836

    GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[i].name,
837
        adaptors[i].num_ports);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
838
839

  }
840
  XvFreeAdaptorInfo (adaptors);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
841

842
  if (!xcontext->xv_port_id) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
843
    GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY, (NULL),
844
845
846
847
        ("No port available"));
    return NULL;
  }

848
849
850
  /* Set XV_AUTOPAINT_COLORKEY */
  {
    int count;
Iain Holmes's avatar
Iain Holmes committed
851
    XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
852
853
854
855
856
857
858
859
860
861
        xcontext->xv_port_id, &count);
    static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";

    for (i = 0; i < count; i++)
      if (!strcmp (attr[i].name, autopaint)) {
        const Atom atom = XInternAtom (xcontext->disp, autopaint, False);

        XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, 1);
        break;
      }
Iain Holmes's avatar
Iain Holmes committed
862
863

    XFree (attr);
864
865
  }

866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
  /* We get all image formats supported by our port */
  formats = XvListImageFormats (xcontext->disp,
      xcontext->xv_port_id, &nb_formats);
  caps = gst_caps_new_empty ();
  for (i = 0; i < nb_formats; i++) {
    GstCaps *format_caps = NULL;

    /* We set the image format of the xcontext to an existing one. Sink
       connect method will override that but we need to have at least a
       valid image format so that we can make our xshm calls check before
       caps negotiation really happens. */
    xcontext->im_format = formats[i].id;

    switch (formats[i].type) {
      case XvRGB:
      {
        format_caps = gst_caps_new_simple ("video/x-raw-rgb",
            "endianness", G_TYPE_INT, xcontext->endianness,
            "depth", G_TYPE_INT, xcontext->depth,
            "bpp", G_TYPE_INT, xcontext->bpp,
            "blue_mask", G_TYPE_INT, formats[i].red_mask,
            "green_mask", G_TYPE_INT, formats[i].green_mask,
            "red_mask", G_TYPE_INT, formats[i].blue_mask,
889
890
            "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
            "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
891
            "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
892

893
        /* For RGB caps we store them and the image
894
895
896
897
898
899
900
901
902
903
904
905
           format so that we can get back the format
           when sinkconnect will give us a caps without
           format property */
        if (format_caps) {
          GstXvImageFormat *format = NULL;

          format = g_new0 (GstXvImageFormat, 1);
          if (format) {
            format->format = formats[i].id;
            format->caps = gst_caps_copy (format_caps);
            xcontext->formats_list =
                g_list_append (xcontext->formats_list, format);
906
907
          }
        }
908
        break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
909
      }
910
911
912
      case XvYUV:
        format_caps = gst_caps_new_simple ("video/x-raw-yuv",
            "format", GST_TYPE_FOURCC, formats[i].id,
913
914
            "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
            "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
915
            "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
916
917
918
919
        break;
      default:
        g_assert_not_reached ();
        break;
920
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
921

922
923
    gst_caps_append (caps, format_caps);
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
924

925
926
  if (formats)
    XFree (formats);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
927

928
929
930
  GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);

  if (gst_caps_is_empty (caps)) {
931
    gst_caps_unref (caps);
932
    XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
933
    GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
934
935
        ("No supported format found"));
    return NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
936
937
  }

938
  return caps;
939
940
}

941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
/* This function calculates the pixel aspect ratio based on the properties
 * in the xcontext structure and stores it there. */
static void
gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
{
  gint par[][2] = {
    {1, 1},                     /* regular screen */
    {16, 15},                   /* PAL TV */
    {11, 10},                   /* 525 line Rec.601 video */
    {54, 59}                    /* 625 line Rec.601 video */
  };
  gint i;
  gint index;
  gdouble ratio;
  gdouble delta;

#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))

  /* first calculate the "real" ratio based on the X values;
   * which is the "physical" w/h divided by the w/h in pixels of the display */
961
  ratio = (gdouble) (xcontext->widthmm * xcontext->height)
962
      / (xcontext->heightmm * xcontext->width);
963

964
965
966
967
968
  /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
   * override here */
  if (xcontext->width == 720 && xcontext->height == 576) {
    ratio = 4.0 * 576 / (3.0 * 720);
  }
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
  GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
  /* now find the one from par[][2] with the lowest delta to the real one */
  delta = DELTA (0);
  index = 0;

  for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
    gdouble this_delta = DELTA (i);

    if (this_delta < delta) {
      index = i;
      delta = this_delta;
    }
  }

  GST_DEBUG ("Decided on index %d (%d/%d)", index,
      par[index][0], par[index][1]);

986
987
988
989
990
991
992
  g_free (xcontext->par);
  xcontext->par = g_new0 (GValue, 1);
  g_value_init (xcontext->par, GST_TYPE_FRACTION);
  gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
  GST_DEBUG ("set xcontext PAR to %d/%d",
      gst_value_get_fraction_numerator (xcontext->par),
      gst_value_get_fraction_denominator (xcontext->par));
993
994
}

995
/* This function gets the X Display and global info about it. Everything is
996
   stored in our object and will be cleaned when the object is disposed. Note
997
   here that caps for supported format are generated without any window or
998
999
   image creation */
static GstXContext *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
1000
gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
For faster browsing, not all history is shown. View entire blame