1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 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 (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* This is the DirectDraw implementation of YUV video overlays */ 25 #include "directx.h" 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 overlay->hwdata = NULL; 294 } 295 } 296 297