1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2003 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Library General Public 7 License as published by the Free Software Foundation; either 8 version 2 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 Library General Public License for more details. 14 15 You should have received a copy of the GNU Library General Public 16 License along with this library; if not, write to the Free 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 #include "SDL_QuartzVideo.h" 25 #include "SDL_QuartzWindow.h" 26 #include "../SDL_yuvfuncs.h" 27 28 29 #define yuv_idh (this->hidden->yuv_idh) 30 #define yuv_matrix (this->hidden->yuv_matrix) 31 #define yuv_codec (this->hidden->yuv_codec) 32 #define yuv_seq (this->hidden->yuv_seq) 33 #define yuv_pixmap (this->hidden->yuv_pixmap) 34 #define yuv_data (this->hidden->yuv_data) 35 #define yuv_width (this->hidden->yuv_width) 36 #define yuv_height (this->hidden->yuv_height) 37 #define yuv_port (this->hidden->yuv_port) 38 39 40 static int QZ_LockYUV (_THIS, SDL_Overlay *overlay) { 41 42 return 0; 43 } 44 45 static void QZ_UnlockYUV (_THIS, SDL_Overlay *overlay) { 46 47 ; 48 } 49 50 static int QZ_DisplayYUV (_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst) { 51 52 OSErr err; 53 CodecFlags flags; 54 55 if (dst->x != 0 || dst->y != 0) { 56 57 SDL_SetError ("Need a dst at (0,0)"); 58 return -1; 59 } 60 61 if (dst->w != yuv_width || dst->h != yuv_height) { 62 63 Fixed scale_x, scale_y; 64 65 scale_x = FixDiv ( Long2Fix (dst->w), Long2Fix (overlay->w) ); 66 scale_y = FixDiv ( Long2Fix (dst->h), Long2Fix (overlay->h) ); 67 68 SetIdentityMatrix (yuv_matrix); 69 ScaleMatrix (yuv_matrix, scale_x, scale_y, Long2Fix (0), Long2Fix (0)); 70 71 SetDSequenceMatrix (yuv_seq, yuv_matrix); 72 73 yuv_width = dst->w; 74 yuv_height = dst->h; 75 } 76 77 if( ( err = DecompressSequenceFrameS( 78 yuv_seq, 79 (void*)yuv_pixmap, 80 sizeof (PlanarPixmapInfoYUV420), 81 codecFlagUseImageBuffer, &flags, nil ) != noErr ) ) 82 { 83 SDL_SetError ("DecompressSequenceFrameS failed"); 84 } 85 86 return err != noErr; 87 } 88 89 static void QZ_FreeHWYUV (_THIS, SDL_Overlay *overlay) { 90 91 CDSequenceEnd (yuv_seq); 92 ExitMovies(); 93 94 SDL_free (overlay->hwfuncs); 95 SDL_free (overlay->pitches); 96 SDL_free (overlay->pixels); 97 98 if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { 99 [ qz_window close ]; 100 qz_window = nil; 101 } 102 103 SDL_free (yuv_matrix); 104 DisposeHandle ((Handle)yuv_idh); 105 } 106 107 /* check for 16 byte alignment, bail otherwise */ 108 #define CHECK_ALIGN(x) do { if ((Uint32)x & 15) { SDL_SetError("Alignment error"); return NULL; } } while(0) 109 110 /* align a byte offset, return how much to add to make it a multiple of 16 */ 111 #define ALIGN(x) ((16 - (x & 15)) & 15) 112 113 SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height, 114 Uint32 format, SDL_Surface *display) { 115 116 Uint32 codec; 117 OSStatus err; 118 CGrafPtr port; 119 SDL_Overlay *overlay; 120 121 if (format == SDL_YV12_OVERLAY || 122 format == SDL_IYUV_OVERLAY) { 123 124 codec = kYUV420CodecType; 125 } 126 else { 127 SDL_SetError ("Hardware: unsupported video format"); 128 return NULL; 129 } 130 131 yuv_idh = (ImageDescriptionHandle) NewHandleClear (sizeof(ImageDescription)); 132 if (yuv_idh == NULL) { 133 SDL_OutOfMemory(); 134 return NULL; 135 } 136 137 yuv_matrix = (MatrixRecordPtr) SDL_malloc (sizeof(MatrixRecord)); 138 if (yuv_matrix == NULL) { 139 SDL_OutOfMemory(); 140 return NULL; 141 } 142 143 if ( EnterMovies() != noErr ) { 144 SDL_SetError ("Could not init QuickTime for YUV playback"); 145 return NULL; 146 } 147 148 err = FindCodec (codec, bestSpeedCodec, nil, &yuv_codec); 149 if (err != noErr) { 150 SDL_SetError ("Could not find QuickTime codec for format"); 151 return NULL; 152 } 153 154 if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { 155 156 /* 157 Acceleration requires a window to be present. 158 A CGrafPtr that points to the screen isn't good enough 159 */ 160 NSRect content = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); 161 162 qz_window = [ [ SDL_QuartzWindow alloc ] 163 initWithContentRect:content 164 styleMask:NSBorderlessWindowMask 165 backing:NSBackingStoreBuffered defer:NO ]; 166 167 if (qz_window == nil) { 168 SDL_SetError ("Could not create the Cocoa window"); 169 return NULL; 170 } 171 172 [ qz_window setContentView:[ [ NSQuickDrawView alloc ] init ] ]; 173 [ qz_window setReleasedWhenClosed:YES ]; 174 [ qz_window center ]; 175 [ qz_window setAcceptsMouseMovedEvents:YES ]; 176 [ qz_window setLevel:CGShieldingWindowLevel() ]; 177 [ qz_window makeKeyAndOrderFront:nil ]; 178 179 port = [ [ qz_window contentView ] qdPort ]; 180 SetPort (port); 181 182 /* 183 BUG: would like to remove white flash when window kicks in 184 { 185 Rect r; 186 SetRect (&r, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); 187 PaintRect (&r); 188 QDFlushPortBuffer (port, nil); 189 } 190 */ 191 } 192 else { 193 port = [ window_view qdPort ]; 194 SetPort (port); 195 } 196 197 SetIdentityMatrix (yuv_matrix); 198 199 HLock ((Handle)yuv_idh); 200 201 (**yuv_idh).idSize = sizeof(ImageDescription); 202 (**yuv_idh).cType = codec; 203 (**yuv_idh).version = 1; 204 (**yuv_idh).revisionLevel = 0; 205 (**yuv_idh).width = width; 206 (**yuv_idh).height = height; 207 (**yuv_idh).hRes = Long2Fix(72); 208 (**yuv_idh).vRes = Long2Fix(72); 209 (**yuv_idh).spatialQuality = codecLosslessQuality; 210 (**yuv_idh).frameCount = 1; 211 (**yuv_idh).clutID = -1; 212 (**yuv_idh).dataSize = 0; 213 (**yuv_idh).depth = 24; 214 215 HUnlock ((Handle)yuv_idh); 216 217 err = DecompressSequenceBeginS ( 218 &yuv_seq, 219 yuv_idh, 220 NULL, 221 0, 222 port, 223 NULL, 224 NULL, 225 yuv_matrix, 226 0, 227 NULL, 228 codecFlagUseImageBuffer, 229 codecLosslessQuality, 230 yuv_codec); 231 232 if (err != noErr) { 233 SDL_SetError ("Error trying to start YUV codec."); 234 return NULL; 235 } 236 237 overlay = (SDL_Overlay*) SDL_malloc (sizeof(*overlay)); 238 if (overlay == NULL) { 239 SDL_OutOfMemory(); 240 return NULL; 241 } 242 243 overlay->format = format; 244 overlay->w = width; 245 overlay->h = height; 246 overlay->planes = 3; 247 overlay->hw_overlay = 1; 248 { 249 int offset; 250 Uint8 **pixels; 251 Uint16 *pitches; 252 int plane2, plane3; 253 254 if (format == SDL_IYUV_OVERLAY) { 255 256 plane2 = 1; /* Native codec format */ 257 plane3 = 2; 258 } 259 else if (format == SDL_YV12_OVERLAY) { 260 261 /* switch the U and V planes */ 262 plane2 = 2; /* U plane maps to plane 3 */ 263 plane3 = 1; /* V plane maps to plane 2 */ 264 } 265 else { 266 SDL_SetError("Unsupported YUV format"); 267 return NULL; 268 } 269 270 pixels = (Uint8**) SDL_malloc (sizeof(*pixels) * 3); 271 pitches = (Uint16*) SDL_malloc (sizeof(*pitches) * 3); 272 if (pixels == NULL || pitches == NULL) { 273 SDL_OutOfMemory(); 274 return NULL; 275 } 276 277 /* Fix: jc.bertin (at) free.fr 278 PlanarPixmapInfoYUV420 is a big-endian struct */ 279 yuv_pixmap = (PlanarPixmapInfoYUV420*) 280 SDL_malloc (sizeof(PlanarPixmapInfoYUV420) + 281 (width * height * 2)); 282 if (yuv_pixmap == NULL) { 283 SDL_OutOfMemory (); 284 return NULL; 285 } 286 287 /* CHECK_ALIGN(yuv_pixmap); */ 288 offset = sizeof(PlanarPixmapInfoYUV420); 289 /* offset += ALIGN(offset); */ 290 /* CHECK_ALIGN(offset); */ 291 292 pixels[0] = (Uint8*)yuv_pixmap + offset; 293 /* CHECK_ALIGN(pixels[0]); */ 294 295 pitches[0] = width; 296 yuv_pixmap->componentInfoY.offset = EndianS32_NtoB(offset); 297 yuv_pixmap->componentInfoY.rowBytes = EndianU32_NtoB(width); 298 299 offset += width * height; 300 pixels[plane2] = (Uint8*)yuv_pixmap + offset; 301 pitches[plane2] = width / 2; 302 yuv_pixmap->componentInfoCb.offset = EndianS32_NtoB(offset); 303 yuv_pixmap->componentInfoCb.rowBytes = EndianU32_NtoB(width / 2); 304 305 offset += (width * height / 4); 306 pixels[plane3] = (Uint8*)yuv_pixmap + offset; 307 pitches[plane3] = width / 2; 308 yuv_pixmap->componentInfoCr.offset = EndianS32_NtoB(offset); 309 yuv_pixmap->componentInfoCr.rowBytes = EndianU32_NtoB(width / 2); 310 311 overlay->pixels = pixels; 312 overlay->pitches = pitches; 313 } 314 315 overlay->hwfuncs = SDL_malloc (sizeof(*overlay->hwfuncs)); 316 if (overlay->hwfuncs == NULL) { 317 SDL_OutOfMemory(); 318 return NULL; 319 } 320 321 overlay->hwfuncs->Lock = QZ_LockYUV; 322 overlay->hwfuncs->Unlock = QZ_UnlockYUV; 323 overlay->hwfuncs->Display = QZ_DisplayYUV; 324 overlay->hwfuncs->FreeHW = QZ_FreeHWYUV; 325 326 yuv_width = overlay->w; 327 yuv_height = overlay->h; 328 329 return overlay; 330 } 331