|
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 DirectDraw implementation of YUV video overlays */ |
|
25 |
|
26 #include "SDL_video.h" |
|
27 #include "SDL_dx5yuv_c.h" |
|
28 #include "../SDL_yuvfuncs.h" |
|
29 |
|
30 //#define USE_DIRECTX_OVERLAY |
|
31 |
|
32 /* The functions used to manipulate software video overlays */ |
|
33 static struct private_yuvhwfuncs dx5_yuvfuncs = { |
|
34 DX5_LockYUVOverlay, |
|
35 DX5_UnlockYUVOverlay, |
|
36 DX5_DisplayYUVOverlay, |
|
37 DX5_FreeYUVOverlay |
|
38 }; |
|
39 |
|
40 struct private_yuvhwdata { |
|
41 LPDIRECTDRAWSURFACE3 surface; |
|
42 |
|
43 /* These are just so we don't have to allocate them separately */ |
|
44 Uint16 pitches[3]; |
|
45 Uint8 *planes[3]; |
|
46 }; |
|
47 |
|
48 |
|
49 static LPDIRECTDRAWSURFACE3 CreateYUVSurface(_THIS, |
|
50 int width, int height, Uint32 format) |
|
51 { |
|
52 HRESULT result; |
|
53 LPDIRECTDRAWSURFACE dd_surface1; |
|
54 LPDIRECTDRAWSURFACE3 dd_surface3; |
|
55 DDSURFACEDESC ddsd; |
|
56 |
|
57 /* Set up the surface description */ |
|
58 SDL_memset(&ddsd, 0, sizeof(ddsd)); |
|
59 ddsd.dwSize = sizeof(ddsd); |
|
60 ddsd.dwFlags = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT); |
|
61 ddsd.dwWidth = width; |
|
62 ddsd.dwHeight= height; |
|
63 #ifdef USE_DIRECTX_OVERLAY |
|
64 ddsd.ddsCaps.dwCaps = (DDSCAPS_OVERLAY|DDSCAPS_VIDEOMEMORY); |
|
65 #else |
|
66 ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN|DDSCAPS_VIDEOMEMORY); |
|
67 #endif |
|
68 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat); |
|
69 ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC; |
|
70 ddsd.ddpfPixelFormat.dwFourCC = format; |
|
71 |
|
72 /* Create the DirectDraw video surface */ |
|
73 result = IDirectDraw2_CreateSurface(ddraw2, &ddsd, &dd_surface1, NULL); |
|
74 if ( result != DD_OK ) { |
|
75 SetDDerror("DirectDraw2::CreateSurface", result); |
|
76 return(NULL); |
|
77 } |
|
78 result = IDirectDrawSurface_QueryInterface(dd_surface1, |
|
79 &IID_IDirectDrawSurface3, (LPVOID *)&dd_surface3); |
|
80 IDirectDrawSurface_Release(dd_surface1); |
|
81 if ( result != DD_OK ) { |
|
82 SetDDerror("DirectDrawSurface::QueryInterface", result); |
|
83 return(NULL); |
|
84 } |
|
85 |
|
86 /* Make sure the surface format was set properly */ |
|
87 SDL_memset(&ddsd, 0, sizeof(ddsd)); |
|
88 ddsd.dwSize = sizeof(ddsd); |
|
89 result = IDirectDrawSurface3_Lock(dd_surface3, NULL, |
|
90 &ddsd, DDLOCK_NOSYSLOCK, NULL); |
|
91 if ( result != DD_OK ) { |
|
92 SetDDerror("DirectDrawSurface3::Lock", result); |
|
93 IDirectDrawSurface_Release(dd_surface3); |
|
94 return(NULL); |
|
95 } |
|
96 IDirectDrawSurface3_Unlock(dd_surface3, NULL); |
|
97 |
|
98 if ( !(ddsd.ddpfPixelFormat.dwFlags & DDPF_FOURCC) || |
|
99 (ddsd.ddpfPixelFormat.dwFourCC != format) ) { |
|
100 SDL_SetError("DDraw didn't use requested FourCC format"); |
|
101 IDirectDrawSurface_Release(dd_surface3); |
|
102 return(NULL); |
|
103 } |
|
104 |
|
105 /* We're ready to go! */ |
|
106 return(dd_surface3); |
|
107 } |
|
108 |
|
109 #ifdef DEBUG_YUV |
|
110 static char *PrintFOURCC(Uint32 code) |
|
111 { |
|
112 static char buf[5]; |
|
113 |
|
114 buf[3] = code >> 24; |
|
115 buf[2] = (code >> 16) & 0xFF; |
|
116 buf[1] = (code >> 8) & 0xFF; |
|
117 buf[0] = (code & 0xFF); |
|
118 return(buf); |
|
119 } |
|
120 #endif |
|
121 |
|
122 SDL_Overlay *DX5_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display) |
|
123 { |
|
124 SDL_Overlay *overlay; |
|
125 struct private_yuvhwdata *hwdata; |
|
126 |
|
127 #ifdef DEBUG_YUV |
|
128 DWORD numcodes; |
|
129 DWORD *codes; |
|
130 |
|
131 printf("FOURCC format requested: 0x%x\n", PrintFOURCC(format)); |
|
132 IDirectDraw2_GetFourCCCodes(ddraw2, &numcodes, NULL); |
|
133 if ( numcodes ) { |
|
134 DWORD i; |
|
135 codes = SDL_malloc(numcodes*sizeof(*codes)); |
|
136 if ( codes ) { |
|
137 IDirectDraw2_GetFourCCCodes(ddraw2, &numcodes, codes); |
|
138 for ( i=0; i<numcodes; ++i ) { |
|
139 fprintf(stderr, "Code %d: 0x%x\n", i, PrintFOURCC(codes[i])); |
|
140 } |
|
141 SDL_free(codes); |
|
142 } |
|
143 } else { |
|
144 fprintf(stderr, "No FOURCC codes supported\n"); |
|
145 } |
|
146 #endif |
|
147 |
|
148 /* Create the overlay structure */ |
|
149 overlay = (SDL_Overlay *)SDL_malloc(sizeof *overlay); |
|
150 if ( overlay == NULL ) { |
|
151 SDL_OutOfMemory(); |
|
152 return(NULL); |
|
153 } |
|
154 SDL_memset(overlay, 0, (sizeof *overlay)); |
|
155 |
|
156 /* Fill in the basic members */ |
|
157 overlay->format = format; |
|
158 overlay->w = width; |
|
159 overlay->h = height; |
|
160 |
|
161 /* Set up the YUV surface function structure */ |
|
162 overlay->hwfuncs = &dx5_yuvfuncs; |
|
163 |
|
164 /* Create the pixel data and lookup tables */ |
|
165 hwdata = (struct private_yuvhwdata *)SDL_malloc(sizeof *hwdata); |
|
166 overlay->hwdata = hwdata; |
|
167 if ( hwdata == NULL ) { |
|
168 SDL_OutOfMemory(); |
|
169 SDL_FreeYUVOverlay(overlay); |
|
170 return(NULL); |
|
171 } |
|
172 hwdata->surface = CreateYUVSurface(this, width, height, format); |
|
173 if ( hwdata->surface == NULL ) { |
|
174 SDL_FreeYUVOverlay(overlay); |
|
175 return(NULL); |
|
176 } |
|
177 overlay->hw_overlay = 1; |
|
178 |
|
179 /* Set up the plane pointers */ |
|
180 overlay->pitches = hwdata->pitches; |
|
181 overlay->pixels = hwdata->planes; |
|
182 switch (format) { |
|
183 case SDL_YV12_OVERLAY: |
|
184 case SDL_IYUV_OVERLAY: |
|
185 overlay->planes = 3; |
|
186 break; |
|
187 default: |
|
188 overlay->planes = 1; |
|
189 break; |
|
190 } |
|
191 |
|
192 /* We're all done.. */ |
|
193 return(overlay); |
|
194 } |
|
195 |
|
196 int DX5_LockYUVOverlay(_THIS, SDL_Overlay *overlay) |
|
197 { |
|
198 HRESULT result; |
|
199 LPDIRECTDRAWSURFACE3 surface; |
|
200 DDSURFACEDESC ddsd; |
|
201 |
|
202 surface = overlay->hwdata->surface; |
|
203 SDL_memset(&ddsd, 0, sizeof(ddsd)); |
|
204 ddsd.dwSize = sizeof(ddsd); |
|
205 result = IDirectDrawSurface3_Lock(surface, NULL, |
|
206 &ddsd, DDLOCK_NOSYSLOCK, NULL); |
|
207 if ( result == DDERR_SURFACELOST ) { |
|
208 result = IDirectDrawSurface3_Restore(surface); |
|
209 result = IDirectDrawSurface3_Lock(surface, NULL, &ddsd, |
|
210 (DDLOCK_NOSYSLOCK|DDLOCK_WAIT), NULL); |
|
211 } |
|
212 if ( result != DD_OK ) { |
|
213 SetDDerror("DirectDrawSurface3::Lock", result); |
|
214 return(-1); |
|
215 } |
|
216 |
|
217 /* Find the pitch and offset values for the overlay */ |
|
218 #if defined(NONAMELESSUNION) |
|
219 overlay->pitches[0] = (Uint16)ddsd.u1.lPitch; |
|
220 #else |
|
221 overlay->pitches[0] = (Uint16)ddsd.lPitch; |
|
222 #endif |
|
223 overlay->pixels[0] = (Uint8 *)ddsd.lpSurface; |
|
224 switch (overlay->format) { |
|
225 case SDL_YV12_OVERLAY: |
|
226 case SDL_IYUV_OVERLAY: |
|
227 /* Add the two extra planes */ |
|
228 overlay->pitches[1] = overlay->pitches[0] / 2; |
|
229 overlay->pitches[2] = overlay->pitches[0] / 2; |
|
230 overlay->pixels[1] = overlay->pixels[0] + |
|
231 overlay->pitches[0] * overlay->h; |
|
232 overlay->pixels[2] = overlay->pixels[1] + |
|
233 overlay->pitches[1] * overlay->h / 2; |
|
234 break; |
|
235 default: |
|
236 /* Only one plane, no worries */ |
|
237 break; |
|
238 } |
|
239 return(0); |
|
240 } |
|
241 |
|
242 void DX5_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay) |
|
243 { |
|
244 LPDIRECTDRAWSURFACE3 surface; |
|
245 |
|
246 surface = overlay->hwdata->surface; |
|
247 IDirectDrawSurface3_Unlock(surface, NULL); |
|
248 } |
|
249 |
|
250 int DX5_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst) |
|
251 { |
|
252 HRESULT result; |
|
253 LPDIRECTDRAWSURFACE3 surface; |
|
254 RECT srcrect, dstrect; |
|
255 |
|
256 surface = overlay->hwdata->surface; |
|
257 srcrect.top = src->y; |
|
258 srcrect.bottom = srcrect.top+src->h; |
|
259 srcrect.left = src->x; |
|
260 srcrect.right = srcrect.left+src->w; |
|
261 dstrect.top = SDL_bounds.top+dst->y; |
|
262 dstrect.left = SDL_bounds.left+dst->x; |
|
263 dstrect.bottom = dstrect.top+dst->h; |
|
264 dstrect.right = dstrect.left+dst->w; |
|
265 #ifdef USE_DIRECTX_OVERLAY |
|
266 result = IDirectDrawSurface3_UpdateOverlay(surface, &srcrect, |
|
267 SDL_primary, &dstrect, DDOVER_SHOW, NULL); |
|
268 if ( result != DD_OK ) { |
|
269 SetDDerror("DirectDrawSurface3::UpdateOverlay", result); |
|
270 return(-1); |
|
271 } |
|
272 #else |
|
273 result = IDirectDrawSurface3_Blt(SDL_primary, &dstrect, surface, &srcrect, |
|
274 DDBLT_WAIT, NULL); |
|
275 if ( result != DD_OK ) { |
|
276 SetDDerror("DirectDrawSurface3::Blt", result); |
|
277 return(-1); |
|
278 } |
|
279 #endif |
|
280 return(0); |
|
281 } |
|
282 |
|
283 void DX5_FreeYUVOverlay(_THIS, SDL_Overlay *overlay) |
|
284 { |
|
285 struct private_yuvhwdata *hwdata; |
|
286 |
|
287 hwdata = overlay->hwdata; |
|
288 if ( hwdata ) { |
|
289 if ( hwdata->surface ) { |
|
290 IDirectDrawSurface_Release(hwdata->surface); |
|
291 } |
|
292 SDL_free(hwdata); |
|
293 } |
|
294 } |
|
295 |