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    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 */
32static struct private_yuvhwfuncs directfb_yuvfuncs = {
33  DirectFB_LockYUVOverlay,
34  DirectFB_UnlockYUVOverlay,
35  DirectFB_DisplayYUVOverlay,
36  DirectFB_FreeYUVOverlay
37};
38
39struct 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
50static DFBEnumerationResult
51enum_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
73static 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
151SDL_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
208int 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
244void 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
253int 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
274void 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
291