/
SDL_phyuv.c
511 lines (426 loc) · 15.3 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
20
slouken@libsdl.org
21
22
23
24
25
26
27
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
28
/* This is the QNX Realtime Platform version of SDL YUV video overlays */
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <Ph.h>
#include <Pt.h>
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_phyuv_c.h"
#include "SDL_yuvfuncs.h"
42
#define OVERLAY_STATE_UNINIT 0
43
44
45
#define OVERLAY_STATE_ACTIVE 1
/* The functions used to manipulate software video overlays */
46
47
static struct private_yuvhwfuncs ph_yuvfuncs =
{
48
49
50
51
ph_LockYUVOverlay,
ph_UnlockYUVOverlay,
ph_DisplayYUVOverlay,
ph_FreeYUVOverlay
52
53
};
54
int grab_ptrs2(PgVideoChannel_t* channel, FRAMEDATA* Frame0, FRAMEDATA* Frame1)
55
{
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
int planes = 0;
/* Buffers have moved; re-obtain the pointers */
Frame0->Y = (unsigned char *)PdGetOffscreenContextPtr(channel->yplane1);
Frame1->Y = (unsigned char *)PdGetOffscreenContextPtr(channel->yplane2);
Frame0->U = (unsigned char *)PdGetOffscreenContextPtr(channel->uplane1);
Frame1->U = (unsigned char *)PdGetOffscreenContextPtr(channel->uplane2);
Frame0->V = (unsigned char *)PdGetOffscreenContextPtr(channel->vplane1);
Frame1->V = (unsigned char *)PdGetOffscreenContextPtr(channel->vplane2);
if (Frame0->Y)
planes++;
if (Frame0->U)
planes++;
71
72
73
if (Frame0->V)
planes++;
74
75
return planes;
76
77
}
78
SDL_Overlay* ph_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface* display)
79
{
80
81
82
SDL_Overlay* overlay;
struct private_yuvhwdata* hwdata;
int vidport;
83
84
85
86
87
88
89
90
int rtncode;
int planes;
int i=0;
PhPoint_t pos;
/* Create the overlay structure */
overlay = calloc(1, sizeof(SDL_Overlay));
91
92
if (overlay == NULL)
{
93
SDL_OutOfMemory();
94
return NULL;
95
96
97
98
99
100
}
/* Fill in the basic members */
overlay->format = format;
overlay->w = width;
overlay->h = height;
101
overlay->hwdata = NULL;
102
103
104
105
106
107
108
/* Set up the YUV surface function structure */
overlay->hwfuncs = &ph_yuvfuncs;
/* Create the pixel data and lookup tables */
hwdata = calloc(1, sizeof(struct private_yuvhwdata));
109
110
if (hwdata == NULL)
{
111
112
SDL_OutOfMemory();
SDL_FreeYUVOverlay(overlay);
113
return NULL;
114
115
}
116
117
overlay->hwdata = hwdata;
118
PhDCSetCurrent(0);
119
120
if (overlay->hwdata->channel == NULL)
{
121
if ((overlay->hwdata->channel = PgCreateVideoChannel(Pg_VIDEO_CHANNEL_SCALER, 0)) == NULL)
122
{
123
124
SDL_SetError("ph_CreateYUVOverlay(): Create channel failed: %s\n", strerror(errno));
SDL_FreeYUVOverlay(overlay);
125
return NULL;
126
127
128
129
}
}
130
131
overlay->hwdata->forcedredraw=0;
132
PtGetAbsPosition(window, &pos.x, &pos.y);
133
134
135
136
137
138
overlay->hwdata->CurrentWindowPos.x = pos.x;
overlay->hwdata->CurrentWindowPos.y = pos.y;
overlay->hwdata->CurrentViewPort.pos.x = 0;
overlay->hwdata->CurrentViewPort.pos.y = 0;
overlay->hwdata->CurrentViewPort.size.w = width;
overlay->hwdata->CurrentViewPort.size.h = height;
139
overlay->hwdata->State = OVERLAY_STATE_UNINIT;
140
141
overlay->hwdata->FrameData0 = (FRAMEDATA *) calloc(1, sizeof(FRAMEDATA));
overlay->hwdata->FrameData1 = (FRAMEDATA *) calloc(1, sizeof(FRAMEDATA));
142
143
vidport = -1;
144
i=0;
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
overlay->hwdata->ischromakey=0;
do {
memset(&overlay->hwdata->caps, 0x00, sizeof(PgScalerCaps_t));
overlay->hwdata->caps.size = sizeof(PgScalerCaps_t);
rtncode = PgGetScalerCapabilities(overlay->hwdata->channel, i, &overlay->hwdata->caps);
if (rtncode==0)
{
if (overlay->hwdata->caps.format==format)
{
if ((overlay->hwdata->caps.flags & Pg_SCALER_CAP_DST_CHROMA_KEY) == Pg_SCALER_CAP_DST_CHROMA_KEY)
{
overlay->hwdata->ischromakey=1;
}
160
vidport=1;
161
162
163
164
165
166
167
168
169
break;
}
}
else
{
break;
}
i++;
} while(1);
170
171
172
if (vidport == -1)
173
174
175
{
SDL_SetError("No available video ports for requested format\n");
SDL_FreeYUVOverlay(overlay);
176
return NULL;
177
}
178
179
180
181
overlay->hwdata->format = format;
overlay->hwdata->props.format = format;
overlay->hwdata->props.size = sizeof(PgScalerProps_t);
182
183
overlay->hwdata->props.src_dim.w = width;
overlay->hwdata->props.src_dim.h = height;
184
185
186
187
/* overlay->hwdata->chromakey = PgGetOverlayChromaColor(); */
overlay->hwdata->chromakey = PgRGB(12, 6, 12); /* very dark pink color */
overlay->hwdata->props.color_key = overlay->hwdata->chromakey;
188
189
PhAreaToRect(&overlay->hwdata->CurrentViewPort, &overlay->hwdata->props.viewport);
190
191
overlay->hwdata->props.flags = Pg_SCALER_PROP_DOUBLE_BUFFER;
192
193
194
195
if ((overlay->hwdata->ischromakey)&&(overlay->hwdata->chromakey))
{
overlay->hwdata->props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE;
196
overlay->hwdata->props.flags |= Pg_SCALER_PROP_CHROMA_SPECIFY_KEY_MASK;
197
198
199
200
201
}
else
{
overlay->hwdata->props.flags &= ~Pg_SCALER_PROP_CHROMA_ENABLE;
}
202
203
rtncode = PgConfigScalerChannel(overlay->hwdata->channel, &overlay->hwdata->props);
204
205
206
207
switch(rtncode)
{
case -1: SDL_SetError("PgConfigScalerChannel failed\n");
208
209
SDL_FreeYUVOverlay(overlay);
return NULL;
210
211
212
213
214
case 1:
case 0:
default:
break;
}
215
216
planes = grab_ptrs2(overlay->hwdata->channel, overlay->hwdata->FrameData0, overlay->hwdata->FrameData1);
217
218
if(overlay->hwdata->channel->yplane1 != NULL)
219
overlay->hwdata->YStride = overlay->hwdata->channel->yplane1->pitch;
220
if(overlay->hwdata->channel->uplane1 != NULL)
221
overlay->hwdata->UStride = overlay->hwdata->channel->uplane1->pitch;
222
if(overlay->hwdata->channel->vplane1 != NULL)
223
overlay->hwdata->VStride = overlay->hwdata->channel->vplane1->pitch;
224
225
226
227
228
229
230
231
232
233
234
/* check for the validness of all planes */
if ((overlay->hwdata->channel->yplane1 == NULL) &&
(overlay->hwdata->channel->uplane1 == NULL) &&
(overlay->hwdata->channel->vplane1 == NULL))
{
SDL_FreeYUVOverlay(overlay);
SDL_SetError("PgConfigScaler() returns all planes equal NULL\n");
return NULL;
}
/*
235
overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel);
236
237
238
if (overlay->hwdata->current==0)
{
239
overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0;
240
}
241
else
242
{
243
overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1;
244
245
246
}
*/
overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0;
247
248
/*
249
overlay->hwdata->locked = 1;
250
*/
251
252
253
254
255
256
257
258
259
260
261
/* Find the pitch and offset values for the overlay */
overlay->planes = planes;
overlay->pitches = calloc(overlay->planes, sizeof(Uint16));
overlay->pixels = calloc(overlay->planes, sizeof(Uint8*));
if (!overlay->pitches || !overlay->pixels)
{
SDL_OutOfMemory();
SDL_FreeYUVOverlay(overlay);
return(NULL);
}
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
if (overlay->planes > 0)
{
overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch;
overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y;
}
if (overlay->planes > 1)
{
overlay->pitches[1] = overlay->hwdata->channel->uplane1->pitch;
overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U;
}
if (overlay->planes > 2)
{
overlay->pitches[2] = overlay->hwdata->channel->vplane1->pitch;
overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V;
}
278
279
280
281
overlay->hwdata->State = OVERLAY_STATE_ACTIVE;
overlay->hwdata->scaler_on = 0;
overlay->hw_overlay = 1;
282
283
284
285
current_overlay=overlay;
return overlay;
286
}
287
288
int ph_LockYUVOverlay(_THIS, SDL_Overlay* overlay)
289
290
{
if (overlay == NULL)
291
{
292
return -1;
293
}
294
295
296
297
overlay->hwdata->locked = 1;
/* overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel);
298
299
if (overlay->hwdata->current == -1)
{
300
SDL_SetError("ph_LockYUVOverlay: PgNextFrame() failed, bailing out\n");
301
SDL_FreeYUVOverlay(overlay);
302
return 0;
303
}
304
305
if (overlay->hwdata->current == 0)
306
{
307
overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0;
308
}
309
else
310
{
311
overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1;
312
}
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
if (overlay->planes > 0)
{
overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch;
overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y;
}
if (overlay->planes > 1)
{
overlay->pitches[1] = overlay->hwdata->channel->uplane1->pitch;
overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U;
}
if (overlay->planes > 2)
{
overlay->pitches[2] = overlay->hwdata->channel->vplane1->pitch;
overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V;
}
329
*/
330
331
return(0);
332
333
}
334
void ph_UnlockYUVOverlay(_THIS, SDL_Overlay* overlay)
335
{
336
if (overlay == NULL)
337
{
338
return;
339
340
}
341
overlay->hwdata->locked = 0;
342
343
}
344
int ph_DisplayYUVOverlay(_THIS, SDL_Overlay* overlay, SDL_Rect* dstrect)
345
{
346
347
int rtncode;
PhPoint_t pos;
348
349
350
SDL_Rect backrect;
PhRect_t windowextent;
int winchanged=0;
351
352
353
if ((overlay == NULL) || (overlay->hwdata==NULL))
{
354
return -1;
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
}
if (overlay->hwdata->State == OVERLAY_STATE_UNINIT)
{
return -1;
}
PtGetAbsPosition(window, &pos.x, &pos.y);
if ((pos.x!=overlay->hwdata->CurrentWindowPos.x) ||
(pos.y!=overlay->hwdata->CurrentWindowPos.y))
{
winchanged=1;
overlay->hwdata->CurrentWindowPos.x=pos.x;
overlay->hwdata->CurrentWindowPos.y=pos.y;
}
370
371
372
373
374
375
376
377
/* If CurrentViewPort position/size has been changed, then move/resize the viewport */
if ((overlay->hwdata->CurrentViewPort.pos.x != dstrect->x) ||
(overlay->hwdata->CurrentViewPort.pos.y != dstrect->y) ||
(overlay->hwdata->CurrentViewPort.size.w != dstrect->w) ||
(overlay->hwdata->CurrentViewPort.size.h != dstrect->h) ||
(overlay->hwdata->scaler_on==0) || (winchanged==1) ||
(overlay->hwdata->forcedredraw==1))
378
{
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
if (overlay->hwdata->ischromakey==1)
{
/* restore screen behind the overlay/chroma color. */
backrect.x=overlay->hwdata->CurrentViewPort.pos.x;
backrect.y=overlay->hwdata->CurrentViewPort.pos.y;
backrect.w=overlay->hwdata->CurrentViewPort.size.w;
backrect.h=overlay->hwdata->CurrentViewPort.size.h;
this->UpdateRects(this, 1, &backrect);
/* Draw the new rectangle of the chroma color at the viewport position */
PgSetFillColor(overlay->hwdata->chromakey);
PgDrawIRect(dstrect->x, dstrect->y, dstrect->x+dstrect->w-1, dstrect->y+dstrect->h-1, Pg_DRAW_FILL);
PgFlush();
}
394
395
396
overlay->hwdata->props.flags |= Pg_SCALER_PROP_SCALER_ENABLE;
overlay->hwdata->scaler_on = 1;
397
398
399
400
401
402
403
404
405
PhWindowQueryVisible(Ph_QUERY_CONSOLE, 0, PtWidgetRid(window), &windowextent);
overlay->hwdata->CurrentViewPort.pos.x = pos.x-windowextent.ul.x+dstrect->x;
overlay->hwdata->CurrentViewPort.pos.y = pos.y-windowextent.ul.y+dstrect->y;
overlay->hwdata->CurrentViewPort.size.w = dstrect->w;
overlay->hwdata->CurrentViewPort.size.h = dstrect->h;
PhAreaToRect(&overlay->hwdata->CurrentViewPort, &overlay->hwdata->props.viewport);
overlay->hwdata->CurrentViewPort.pos.x = dstrect->x;
overlay->hwdata->CurrentViewPort.pos.y = dstrect->y;
406
407
rtncode = PgConfigScalerChannel(overlay->hwdata->channel, &(overlay->hwdata->props));
408
409
410
411
switch(rtncode)
{
case -1:
412
SDL_SetError("PgConfigScalerChannel() function failed\n");
413
SDL_FreeYUVOverlay(overlay);
414
return -1;
415
416
417
418
419
420
421
422
case 1:
grab_ptrs2(overlay->hwdata->channel, overlay->hwdata->FrameData0, overlay->hwdata->FrameData1);
break;
case 0:
default:
break;
}
}
423
424
425
426
/*
if (overlay->hwdata->locked==0)
427
428
429
430
{
overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel);
if (overlay->hwdata->current == -1)
{
431
SDL_SetError("ph_LockYUVOverlay: PgNextFrame() failed, bailing out\n");
432
433
434
SDL_FreeYUVOverlay(overlay);
return 0;
}
435
436
if (overlay->hwdata->current == 0)
437
{
438
overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0;
439
}
440
else
441
{
442
overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1;
443
}
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
if (overlay->planes > 0)
{
overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch;
overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y;
}
if (overlay->planes > 1)
{
overlay->pitches[1] = overlay->hwdata->channel->uplane1->pitch;
overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U;
}
if (overlay->planes > 2)
{
overlay->pitches[2] = overlay->hwdata->channel->vplane1->pitch;
overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V;
}
}
461
*/
462
463
return 0;
464
465
466
467
}
void ph_FreeYUVOverlay(_THIS, SDL_Overlay *overlay)
{
468
469
SDL_Rect backrect;
470
if (overlay == NULL)
471
{
472
return;
473
}
474
475
if (overlay->hwdata == NULL)
476
{
477
return;
478
479
480
481
482
483
484
485
486
487
}
current_overlay=NULL;
/* restore screen behind the overlay/chroma color. */
backrect.x=overlay->hwdata->CurrentViewPort.pos.x;
backrect.y=overlay->hwdata->CurrentViewPort.pos.y;
backrect.w=overlay->hwdata->CurrentViewPort.size.w;
backrect.h=overlay->hwdata->CurrentViewPort.size.h;
this->UpdateRects(this, 1, &backrect);
488
489
490
491
492
/* it is need for some buggy drivers, that can't hide overlay before */
/* freeing buffer, so we got trash on the srceen */
overlay->hwdata->props.flags &= ~Pg_SCALER_PROP_SCALER_ENABLE;
PgConfigScalerChannel(overlay->hwdata->channel, &(overlay->hwdata->props));
493
494
495
overlay->hwdata->scaler_on = 0;
overlay->hwdata->State = OVERLAY_STATE_UNINIT;
496
497
498
499
500
501
502
if (overlay->hwdata->channel != NULL)
{
PgDestroyVideoChannel(overlay->hwdata->channel);
overlay->hwdata->channel = NULL;
return;
}
503
504
505
506
507
508
509
510
overlay->hwdata->CurrentFrameData = NULL;
free(overlay->hwdata->FrameData0);
free(overlay->hwdata->FrameData1);
overlay->hwdata->FrameData0 = NULL;
overlay->hwdata->FrameData1 = NULL;
free(overlay->hwdata);
511
}