SDL-1.2.14
[sdl_omap.git] / src / video / directfb / SDL_DirectFB_yuv.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 DirectFB implementation of YUV video overlays */
25
26 #include "SDL_video.h"
27 #include "SDL_DirectFB_yuv.h"
28 #include "../SDL_yuvfuncs.h"
29
30
31 /* The functions used to manipulate software video overlays */
32 static struct private_yuvhwfuncs directfb_yuvfuncs = {
33   DirectFB_LockYUVOverlay,
34   DirectFB_UnlockYUVOverlay,
35   DirectFB_DisplayYUVOverlay,
36   DirectFB_FreeYUVOverlay
37 };
38
39 struct private_yuvhwdata {
40   DFBDisplayLayerID      layer_id;
41
42   IDirectFBDisplayLayer *layer;
43   IDirectFBSurface      *surface;
44
45   /* These are just so we don't have to allocate them separately */
46   Uint16 pitches[3];
47   Uint8 *planes[3];
48 };
49
50 static DFBEnumerationResult
51 enum_layers_callback( DFBDisplayLayerID            id,
52                       DFBDisplayLayerDescription   desc,
53                       void                        *data )
54 {
55   struct private_yuvhwdata *hwdata = (struct private_yuvhwdata *) data;
56
57   /* we don't want the primary */
58   if (id == DLID_PRIMARY)
59     return DFENUM_OK;
60
61   /* take the one with a surface for video */
62   if ((desc.caps & DLCAPS_SURFACE) && (desc.type & DLTF_VIDEO))
63     {
64       hwdata->layer_id = id;
65
66       return DFENUM_CANCEL;
67     }
68
69   return DFENUM_OK;
70 }
71
72
73 static DFBResult CreateYUVSurface(_THIS, struct private_yuvhwdata *hwdata,
74                                   int width, int height, Uint32 format)
75 {
76   DFBResult              ret;
77   IDirectFB             *dfb = HIDDEN->dfb;
78   IDirectFBDisplayLayer *layer;
79   DFBDisplayLayerConfig  conf;
80
81   ret = dfb->EnumDisplayLayers (dfb, enum_layers_callback, hwdata);
82   if (ret)
83     {
84       SetDirectFBerror("IDirectFB::EnumDisplayLayers", ret);
85       return ret;
86     }
87
88   if (!hwdata->layer_id)
89     return DFB_UNSUPPORTED;
90
91   ret = dfb->GetDisplayLayer (dfb, hwdata->layer_id, &layer);
92   if (ret)
93     {
94       SetDirectFBerror("IDirectFB::GetDisplayLayer", ret);
95       return ret;
96     }
97
98   conf.flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT;
99   conf.width = width;
100   conf.height = height;
101
102   switch (format)
103     {
104     case SDL_YV12_OVERLAY:
105       conf.pixelformat = DSPF_YV12;
106       break;
107     case SDL_IYUV_OVERLAY:
108       conf.pixelformat = DSPF_I420;
109       break;
110     case SDL_YUY2_OVERLAY:
111       conf.pixelformat = DSPF_YUY2;
112       break;
113     case SDL_UYVY_OVERLAY:
114       conf.pixelformat = DSPF_UYVY;
115       break;
116     default:
117       fprintf (stderr, "SDL_DirectFB: Unsupported YUV format (0x%08x)!\n", format);
118       break;
119     }
120
121   /* Need to set coop level or newer DirectFB versions will fail here. */
122   ret = layer->SetCooperativeLevel (layer, DLSCL_ADMINISTRATIVE);
123   if (ret)
124     {
125       SetDirectFBerror("IDirectFBDisplayLayer::SetCooperativeLevel() failed", ret);
126       layer->Release (layer);
127       return ret;
128     }
129
130   ret = layer->SetConfiguration (layer, &conf);
131   if (ret)
132     {
133       SetDirectFBerror("IDirectFBDisplayLayer::SetConfiguration", ret);
134       layer->Release (layer);
135       return ret;
136     }
137
138   ret = layer->GetSurface (layer, &hwdata->surface);
139   if (ret)
140     {
141       SetDirectFBerror("IDirectFBDisplayLayer::GetSurface", ret);
142       layer->Release (layer);
143       return ret;
144     }
145
146   hwdata->layer = layer;
147
148   return DFB_OK;
149 }
150
151 SDL_Overlay *DirectFB_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display)
152 {
153   SDL_Overlay *overlay;
154   struct private_yuvhwdata *hwdata;
155
156   /* Create the overlay structure */
157   overlay = SDL_calloc (1, sizeof(SDL_Overlay));
158   if (!overlay)
159     {
160       SDL_OutOfMemory();
161       return NULL;
162     }
163         
164   /* Fill in the basic members */
165   overlay->format = format;
166   overlay->w = width;
167   overlay->h = height;
168
169   /* Set up the YUV surface function structure */
170   overlay->hwfuncs = &directfb_yuvfuncs;
171
172   /* Create the pixel data and lookup tables */
173   hwdata = SDL_calloc(1, sizeof(struct private_yuvhwdata));
174   overlay->hwdata = hwdata;
175   if (!hwdata)
176     {
177       SDL_OutOfMemory();
178       SDL_FreeYUVOverlay (overlay);
179       return NULL;
180     }
181
182   if (CreateYUVSurface (this, hwdata, width, height, format))
183     {
184       SDL_FreeYUVOverlay (overlay);
185       return NULL;
186     }
187
188   overlay->hw_overlay = 1;
189
190   /* Set up the plane pointers */
191   overlay->pitches = hwdata->pitches;
192   overlay->pixels = hwdata->planes;
193   switch (format)
194     {
195     case SDL_YV12_OVERLAY:
196     case SDL_IYUV_OVERLAY:
197       overlay->planes = 3;
198       break;
199     default:
200       overlay->planes = 1;
201       break;
202     }
203
204   /* We're all done.. */
205   return overlay;
206 }
207
208 int DirectFB_LockYUVOverlay(_THIS, SDL_Overlay *overlay)
209 {
210   DFBResult         ret;
211   void             *data;
212   int               pitch;
213   IDirectFBSurface *surface = overlay->hwdata->surface;
214
215   ret = surface->Lock (surface, DSLF_READ | DSLF_WRITE, &data, &pitch);
216   if (ret)
217     {
218       SetDirectFBerror("IDirectFBSurface::Lock", ret);
219       return -1;
220     }
221
222   /* Find the pitch and offset values for the overlay */
223   overlay->pitches[0] = (Uint16) pitch;
224   overlay->pixels[0]  = (Uint8*) data;
225
226   switch (overlay->format)
227     {
228     case SDL_YV12_OVERLAY:
229     case SDL_IYUV_OVERLAY:
230       /* Add the two extra planes */
231       overlay->pitches[1] = overlay->pitches[0] / 2;
232       overlay->pitches[2] = overlay->pitches[0] / 2;
233       overlay->pixels[1]  = overlay->pixels[0] + overlay->pitches[0] * overlay->h;
234       overlay->pixels[2]  = overlay->pixels[1] + overlay->pitches[1] * overlay->h / 2;
235       break;
236     default:
237       /* Only one plane, no worries */
238       break;
239     }
240
241   return 0;
242 }
243
244 void DirectFB_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay)
245 {
246   IDirectFBSurface *surface = overlay->hwdata->surface;
247
248   overlay->pixels[0] = overlay->pixels[1] = overlay->pixels[2] = NULL;
249
250   surface->Unlock (surface);
251 }
252
253 int DirectFB_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst)
254 {
255   DFBResult              ret;
256   DFBDisplayLayerConfig  conf;
257   IDirectFBDisplayLayer *primary = HIDDEN->layer;
258   IDirectFBDisplayLayer *layer   = overlay->hwdata->layer;
259
260   primary->GetConfiguration (primary, &conf);
261
262   ret = layer->SetScreenLocation (layer,
263                                   dst->x / (float) conf.width, dst->y / (float) conf.height,
264                                   dst->w / (float) conf.width, dst->h / (float) conf.height );
265   if (ret)
266     {
267       SetDirectFBerror("IDirectFBDisplayLayer::SetScreenLocation", ret);
268       return -1;
269     }
270
271   return 0;
272 }
273
274 void DirectFB_FreeYUVOverlay(_THIS, SDL_Overlay *overlay)
275 {
276   struct private_yuvhwdata *hwdata;
277
278   hwdata = overlay->hwdata;
279   if (hwdata)
280     {
281       if (hwdata->surface)
282         hwdata->surface->Release (hwdata->surface);
283
284       if (hwdata->layer)
285         hwdata->layer->Release (hwdata->layer);
286
287       free (hwdata);
288     }
289 }
290