SDL-1.2.14
[sdl_omap.git] / src / video / photon / SDL_phyuv.c
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 }