This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_x11yuv.c
438 lines (397 loc) · 13.3 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
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
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
/* This is the XFree86 Xv extension implementation of YUV video overlays */
26
#if SDL_VIDEO_DRIVER_X11_XV
27
28
#include <X11/Xlib.h>
29
#ifndef NO_SHARED_MEMORY
30
31
32
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
33
#endif
34
#include "../Xext/extensions/Xvlib.h"
35
36
#include "SDL_x11yuv_c.h"
37
#include "../SDL_yuvfuncs.h"
38
39
40
41
42
43
44
45
46
#define XFREE86_REFRESH_HACK
#ifdef XFREE86_REFRESH_HACK
#include "SDL_x11image_c.h"
#endif
/* Workaround when pitch != width */
#define PITCH_WORKAROUND
47
/* Fix for the NVidia GeForce 2 - use the last available adaptor */
48
49
50
#if 0 /* Apparently the NVidia drivers are fixed */
#define USE_LAST_ADAPTOR
#endif
51
52
53
/* The functions used to manipulate software video overlays */
static struct private_yuvhwfuncs x11_yuvfuncs = {
54
55
56
57
X11_LockYUVOverlay,
X11_UnlockYUVOverlay,
X11_DisplayYUVOverlay,
X11_FreeYUVOverlay
58
59
};
60
61
62
struct private_yuvhwdata
{
int port;
63
#ifndef NO_SHARED_MEMORY
64
65
int yuv_use_mitshm;
XShmSegmentInfo yuvshm;
66
#endif
67
SDL_NAME(XvImage) * image;
68
69
70
};
71
static int (*X_handler) (Display *, XErrorEvent *) = NULL;
72
73
74
75
#ifndef NO_SHARED_MEMORY
/* Shared memory error handler routine */
static int shm_error;
76
static int
77
shm_errhandler(Display * d, XErrorEvent * e)
78
{
79
80
81
82
if (e->error_code == BadAccess) {
shm_error = True;
return (0);
} else
83
return (X_handler(d, e));
84
85
86
}
#endif /* !NO_SHARED_MEMORY */
87
static int xv_error;
88
static int
89
xv_errhandler(Display * d, XErrorEvent * e)
90
{
91
92
93
94
if (e->error_code == BadMatch) {
xv_error = True;
return (0);
} else
95
return (X_handler(d, e));
96
}
97
98
SDL_Overlay *
99
100
X11_CreateYUVOverlay(_THIS, int width, int height, Uint32 format,
SDL_Surface * display)
101
{
102
103
104
105
106
SDL_Overlay *overlay;
struct private_yuvhwdata *hwdata;
int xv_port;
unsigned int i, j, k;
unsigned int adaptors;
107
SDL_NAME(XvAdaptorInfo) * ainfo;
108
int bpp;
109
#ifndef NO_SHARED_MEMORY
110
XShmSegmentInfo *yuvshm;
111
#endif
112
113
114
115
/* Look for the XVideo extension with a valid port for this format */
xv_port = -1;
if ((Success ==
116
SDL_NAME(XvQueryExtension) (GFX_Display, &j, &j, &j, &j, &j))
117
&& (Success ==
118
119
120
SDL_NAME(XvQueryAdaptors) (GFX_Display,
RootWindow(GFX_Display, SDL_Screen),
&adaptors, &ainfo))) {
121
#ifdef USE_LAST_ADAPTOR
122
for (i = 0; i < adaptors; ++i)
123
#else
124
for (i = 0; (i < adaptors) && (xv_port == -1); ++i)
125
#endif /* USE_LAST_ADAPTOR */
126
127
{
/* Check to see if the visual can be used */
128
if (BUGGY_XFREE86(<=, 4001)) {
129
130
131
132
133
134
135
136
137
138
139
140
141
142
int visual_ok = 0;
for (j = 0; j < ainfo[i].num_formats; ++j) {
if (ainfo[i].formats[j].visual_id == SDL_Visual->visualid) {
visual_ok = 1;
break;
}
}
if (!visual_ok) {
continue;
}
}
if ((ainfo[i].type & XvInputMask) &&
(ainfo[i].type & XvImageMask)) {
int num_formats;
143
144
145
146
147
SDL_NAME(XvImageFormatValues) * formats;
formats = SDL_NAME(XvListImageFormats) (GFX_Display,
ainfo[i].
base_id,
&num_formats);
148
#ifdef USE_LAST_ADAPTOR
149
for (j = 0; j < num_formats; ++j)
150
#else
151
for (j = 0; (j < num_formats) && (xv_port == -1); ++j)
152
#endif /* USE_LAST_ADAPTOR */
153
154
155
{
if ((Uint32) formats[j].id == format) {
for (k = 0; k < ainfo[i].num_ports; ++k) {
156
if (Success == SDL_NAME(XvGrabPort)
157
158
159
160
161
162
163
164
165
(GFX_Display,
ainfo[i].base_id + k, CurrentTime)) {
xv_port = ainfo[i].base_id + k;
break;
}
}
}
}
if (formats) {
166
XFree(formats);
167
168
169
}
}
}
170
SDL_NAME(XvFreeAdaptorInfo) (ainfo);
171
172
173
174
175
176
177
178
179
180
181
182
183
184
}
/* Precalculate the bpp for the pitch workaround below */
switch (format) {
/* Add any other cases we need to support... */
case SDL_YUY2_OVERLAY:
case SDL_UYVY_OVERLAY:
case SDL_YVYU_OVERLAY:
bpp = 2;
break;
default:
bpp = 1;
break;
}
185
186
#if 0
187
188
189
190
191
/*
* !!! FIXME:
* "Here are some diffs for X11 and yuv. Note that the last part 2nd
* diff should probably be a new call to XvQueryAdaptorFree with ainfo
* and the number of adaptors, instead of the loop through like I did."
192
193
194
195
*
* ACHTUNG: This is broken! It looks like XvFreeAdaptorInfo does this
* for you, so we end up with a double-free. I need to look at this
* more closely... --ryan.
196
*/
197
198
for (i = 0; i < adaptors; ++i) {
if (ainfo[i].name != NULL)
199
Xfree(ainfo[i].name);
200
if (ainfo[i].formats != NULL)
201
Xfree(ainfo[i].formats);
202
}
203
Xfree(ainfo);
204
#endif
205
206
if (xv_port == -1) {
207
SDL_SetError("No available video ports for requested format");
208
209
210
211
212
213
214
215
216
return (NULL);
}
/* Enable auto-painting of the overlay colorkey */
{
static const char *attr[] =
{ "XV_AUTOPAINT_COLORKEY", "XV_AUTOPAINT_COLOURKEY" };
unsigned int i;
217
218
219
SDL_NAME(XvSelectPortNotify) (GFX_Display, xv_port, True);
X_handler = XSetErrorHandler(xv_errhandler);
for (i = 0; i < sizeof(attr) / (sizeof attr[0]); ++i) {
220
221
222
Atom a;
xv_error = False;
223
a = XInternAtom(GFX_Display, attr[i], True);
224
if (a != None) {
225
226
SDL_NAME(XvSetPortAttribute) (GFX_Display, xv_port, a, 1);
XSync(GFX_Display, True);
227
228
229
230
231
if (!xv_error) {
break;
}
}
}
232
233
XSetErrorHandler(X_handler);
SDL_NAME(XvSelectPortNotify) (GFX_Display, xv_port, False);
234
235
236
}
/* Create the overlay structure */
237
overlay = (SDL_Overlay *) SDL_malloc(sizeof *overlay);
238
if (overlay == NULL) {
239
240
SDL_NAME(XvUngrabPort) (GFX_Display, xv_port, CurrentTime);
SDL_OutOfMemory();
241
242
return (NULL);
}
243
SDL_memset(overlay, 0, (sizeof *overlay));
244
245
246
247
248
249
250
251
252
253
254
/* Fill in the basic members */
overlay->format = format;
overlay->w = width;
overlay->h = height;
/* Set up the YUV surface function structure */
overlay->hwfuncs = &x11_yuvfuncs;
overlay->hw_overlay = 1;
/* Create the pixel data and lookup tables */
255
hwdata = (struct private_yuvhwdata *) SDL_malloc(sizeof *hwdata);
256
257
overlay->hwdata = hwdata;
if (hwdata == NULL) {
258
259
260
SDL_NAME(XvUngrabPort) (GFX_Display, xv_port, CurrentTime);
SDL_OutOfMemory();
SDL_FreeYUVOverlay(overlay);
261
262
263
return (NULL);
}
hwdata->port = xv_port;
264
#ifndef NO_SHARED_MEMORY
265
yuvshm = &hwdata->yuvshm;
266
267
268
SDL_memset(yuvshm, 0, sizeof(*yuvshm));
hwdata->image = SDL_NAME(XvShmCreateImage) (GFX_Display, xv_port, format,
0, width, height, yuvshm);
269
#ifdef PITCH_WORKAROUND
270
271
if (hwdata->image != NULL && hwdata->image->pitches[0] != (width * bpp)) {
/* Ajust overlay width according to pitch */
272
XFree(hwdata->image);
273
274
width = hwdata->image->pitches[0] / bpp;
hwdata->image =
275
276
SDL_NAME(XvShmCreateImage) (GFX_Display, xv_port, format, 0,
width, height, yuvshm);
277
}
278
#endif /* PITCH_WORKAROUND */
279
280
hwdata->yuv_use_mitshm = (hwdata->image != NULL);
if (hwdata->yuv_use_mitshm) {
281
282
yuvshm->shmid = shmget(IPC_PRIVATE, hwdata->image->data_size,
IPC_CREAT | 0777);
283
if (yuvshm->shmid >= 0) {
284
yuvshm->shmaddr = (char *) shmat(yuvshm->shmid, 0, 0);
285
286
287
yuvshm->readOnly = False;
if (yuvshm->shmaddr != (char *) -1) {
shm_error = False;
288
289
290
291
X_handler = XSetErrorHandler(shm_errhandler);
XShmAttach(GFX_Display, yuvshm);
XSync(GFX_Display, True);
XSetErrorHandler(X_handler);
292
if (shm_error)
293
shmdt(yuvshm->shmaddr);
294
295
296
} else {
shm_error = True;
}
297
shmctl(yuvshm->shmid, IPC_RMID, NULL);
298
299
300
301
} else {
shm_error = True;
}
if (shm_error) {
302
XFree(hwdata->image);
303
304
305
306
307
308
hwdata->yuv_use_mitshm = 0;
} else {
hwdata->image->data = yuvshm->shmaddr;
}
}
if (!hwdata->yuv_use_mitshm)
309
#endif /* NO_SHARED_MEMORY */
310
311
{
hwdata->image =
312
313
SDL_NAME(XvCreateImage) (GFX_Display, xv_port, format, 0,
width, height);
314
315
#ifdef PITCH_WORKAROUND
316
317
318
if (hwdata->image != NULL
&& hwdata->image->pitches[0] != (width * bpp)) {
/* Ajust overlay width according to pitch */
319
XFree(hwdata->image);
320
321
width = hwdata->image->pitches[0] / bpp;
hwdata->image =
322
323
SDL_NAME(XvCreateImage) (GFX_Display, xv_port, format, 0,
width, height);
324
}
325
#endif /* PITCH_WORKAROUND */
326
if (hwdata->image == NULL) {
327
328
SDL_SetError("Couldn't create XVideo image");
SDL_FreeYUVOverlay(overlay);
329
330
return (NULL);
}
331
hwdata->image->data = SDL_malloc(hwdata->image->data_size);
332
if (hwdata->image->data == NULL) {
333
334
SDL_OutOfMemory();
SDL_FreeYUVOverlay(overlay);
335
336
337
338
339
340
341
return (NULL);
}
}
/* Find the pitch and offset values for the overlay */
overlay->planes = hwdata->image->num_planes;
overlay->pitches =
342
(Uint16 *) SDL_malloc(overlay->planes * sizeof(Uint16));
343
overlay->pixels =
344
(Uint8 **) SDL_malloc(overlay->planes * sizeof(Uint8 *));
345
if (!overlay->pitches || !overlay->pixels) {
346
347
SDL_OutOfMemory();
SDL_FreeYUVOverlay(overlay);
348
349
350
351
352
353
354
return (NULL);
}
for (i = 0; i < overlay->planes; ++i) {
overlay->pitches[i] = hwdata->image->pitches[i];
overlay->pixels[i] = (Uint8 *) hwdata->image->data +
hwdata->image->offsets[i];
}
355
356
#ifdef XFREE86_REFRESH_HACK
357
358
359
360
/* Work around an XFree86 X server bug (?)
We can't perform normal updates in windows that have video
being output to them. See SDL_x11image.c for more details.
*/
361
X11_DisableAutoRefresh(this);
362
363
#endif
364
365
/* We're all done.. */
return (overlay);
366
367
}
368
int
369
X11_LockYUVOverlay(_THIS, SDL_Overlay * overlay)
370
{
371
return (0);
372
373
}
374
void
375
X11_UnlockYUVOverlay(_THIS, SDL_Overlay * overlay)
376
{
377
return;
378
379
}
380
int
381
382
X11_DisplayYUVOverlay(_THIS, SDL_Overlay * overlay, SDL_Rect * src,
SDL_Rect * dst)
383
{
384
struct private_yuvhwdata *hwdata;
385
386
hwdata = overlay->hwdata;
387
388
#ifndef NO_SHARED_MEMORY
389
if (hwdata->yuv_use_mitshm) {
390
391
392
393
SDL_NAME(XvShmPutImage) (GFX_Display, hwdata->port, SDL_Window,
SDL_GC, hwdata->image, src->x, src->y,
src->w, src->h, dst->x, dst->y, dst->w,
dst->h, False);
394
} else
395
#endif
396
{
397
398
399
SDL_NAME(XvPutImage) (GFX_Display, hwdata->port, SDL_Window,
SDL_GC, hwdata->image, src->x, src->y,
src->w, src->h, dst->x, dst->y, dst->w, dst->h);
400
}
401
XSync(GFX_Display, False);
402
return (0);
403
404
}
405
void
406
X11_FreeYUVOverlay(_THIS, SDL_Overlay * overlay)
407
{
408
struct private_yuvhwdata *hwdata;
409
410
411
hwdata = overlay->hwdata;
if (hwdata) {
412
SDL_NAME(XvUngrabPort) (GFX_Display, hwdata->port, CurrentTime);
413
#ifndef NO_SHARED_MEMORY
414
if (hwdata->yuv_use_mitshm) {
415
416
XShmDetach(GFX_Display, &hwdata->yuvshm);
shmdt(hwdata->yuvshm.shmaddr);
417
}
418
#endif
419
if (hwdata->image) {
420
XFree(hwdata->image);
421
}
422
SDL_free(hwdata);
423
424
}
if (overlay->pitches) {
425
SDL_free(overlay->pitches);
426
427
428
overlay->pitches = NULL;
}
if (overlay->pixels) {
429
SDL_free(overlay->pixels);
430
431
overlay->pixels = NULL;
}
432
#ifdef XFREE86_REFRESH_HACK
433
X11_EnableAutoRefresh(this);
434
435
436
#endif
}
437
#endif /* SDL_VIDEO_DRIVER_X11_XV */
438
/* vi: set ts=4 sw=4 expandtab: */