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