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