| /* |
| SDL - Simple DirectMedia Layer |
| Copyright (C) 1997-2003 Sam Lantinga |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public |
| License along with this library; if not, write to the Free |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
| Sam Lantinga |
| slouken@libsdl.org |
| */ |
| #include "SDL_config.h" |
| |
| #include "SDL_QuartzVideo.h" |
| #include "SDL_QuartzWindow.h" |
| #include "../SDL_yuvfuncs.h" |
| |
| |
| #define yuv_idh (this->hidden->yuv_idh) |
| #define yuv_matrix (this->hidden->yuv_matrix) |
| #define yuv_codec (this->hidden->yuv_codec) |
| #define yuv_seq (this->hidden->yuv_seq) |
| #define yuv_pixmap (this->hidden->yuv_pixmap) |
| #define yuv_data (this->hidden->yuv_data) |
| #define yuv_width (this->hidden->yuv_width) |
| #define yuv_height (this->hidden->yuv_height) |
| #define yuv_port (this->hidden->yuv_port) |
| |
| |
| static int QZ_LockYUV (_THIS, SDL_Overlay *overlay) { |
| |
| return 0; |
| } |
| |
| static void QZ_UnlockYUV (_THIS, SDL_Overlay *overlay) { |
| |
| ; |
| } |
| |
| static int QZ_DisplayYUV (_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst) { |
| |
| OSErr err; |
| CodecFlags flags; |
| |
| if (dst->x != 0 || dst->y != 0) { |
| |
| SDL_SetError ("Need a dst at (0,0)"); |
| return -1; |
| } |
| |
| if (dst->w != yuv_width || dst->h != yuv_height) { |
| |
| Fixed scale_x, scale_y; |
| |
| scale_x = FixDiv ( Long2Fix (dst->w), Long2Fix (overlay->w) ); |
| scale_y = FixDiv ( Long2Fix (dst->h), Long2Fix (overlay->h) ); |
| |
| SetIdentityMatrix (yuv_matrix); |
| ScaleMatrix (yuv_matrix, scale_x, scale_y, Long2Fix (0), Long2Fix (0)); |
| |
| SetDSequenceMatrix (yuv_seq, yuv_matrix); |
| |
| yuv_width = dst->w; |
| yuv_height = dst->h; |
| } |
| |
| if( ( err = DecompressSequenceFrameS( |
| yuv_seq, |
| (void*)yuv_pixmap, |
| sizeof (PlanarPixmapInfoYUV420), |
| codecFlagUseImageBuffer, &flags, nil ) != noErr ) ) |
| { |
| SDL_SetError ("DecompressSequenceFrameS failed"); |
| } |
| |
| return err != noErr; |
| } |
| |
| static void QZ_FreeHWYUV (_THIS, SDL_Overlay *overlay) { |
| |
| CDSequenceEnd (yuv_seq); |
| ExitMovies(); |
| |
| SDL_free (overlay->hwfuncs); |
| SDL_free (overlay->pitches); |
| SDL_free (overlay->pixels); |
| |
| if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { |
| [ qz_window close ]; |
| qz_window = nil; |
| } |
| |
| SDL_free (yuv_matrix); |
| DisposeHandle ((Handle)yuv_idh); |
| } |
| |
| /* check for 16 byte alignment, bail otherwise */ |
| #define CHECK_ALIGN(x) do { if ((Uint32)x & 15) { SDL_SetError("Alignment error"); return NULL; } } while(0) |
| |
| /* align a byte offset, return how much to add to make it a multiple of 16 */ |
| #define ALIGN(x) ((16 - (x & 15)) & 15) |
| |
| SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height, |
| Uint32 format, SDL_Surface *display) { |
| |
| Uint32 codec; |
| OSStatus err; |
| CGrafPtr port; |
| SDL_Overlay *overlay; |
| |
| if (format == SDL_YV12_OVERLAY || |
| format == SDL_IYUV_OVERLAY) { |
| |
| codec = kYUV420CodecType; |
| } |
| else { |
| SDL_SetError ("Hardware: unsupported video format"); |
| return NULL; |
| } |
| |
| yuv_idh = (ImageDescriptionHandle) NewHandleClear (sizeof(ImageDescription)); |
| if (yuv_idh == NULL) { |
| SDL_OutOfMemory(); |
| return NULL; |
| } |
| |
| yuv_matrix = (MatrixRecordPtr) SDL_malloc (sizeof(MatrixRecord)); |
| if (yuv_matrix == NULL) { |
| SDL_OutOfMemory(); |
| return NULL; |
| } |
| |
| if ( EnterMovies() != noErr ) { |
| SDL_SetError ("Could not init QuickTime for YUV playback"); |
| return NULL; |
| } |
| |
| err = FindCodec (codec, bestSpeedCodec, nil, &yuv_codec); |
| if (err != noErr) { |
| SDL_SetError ("Could not find QuickTime codec for format"); |
| return NULL; |
| } |
| |
| if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { |
| |
| /* |
| Acceleration requires a window to be present. |
| A CGrafPtr that points to the screen isn't good enough |
| */ |
| NSRect content = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); |
| |
| qz_window = [ [ SDL_QuartzWindow alloc ] |
| initWithContentRect:content |
| styleMask:NSBorderlessWindowMask |
| backing:NSBackingStoreBuffered defer:NO ]; |
| |
| if (qz_window == nil) { |
| SDL_SetError ("Could not create the Cocoa window"); |
| return NULL; |
| } |
| |
| [ qz_window setContentView:[ [ NSQuickDrawView alloc ] init ] ]; |
| [ qz_window setReleasedWhenClosed:YES ]; |
| [ qz_window center ]; |
| [ qz_window setAcceptsMouseMovedEvents:YES ]; |
| [ qz_window setLevel:CGShieldingWindowLevel() ]; |
| [ qz_window makeKeyAndOrderFront:nil ]; |
| |
| port = [ [ qz_window contentView ] qdPort ]; |
| SetPort (port); |
| |
| /* |
| BUG: would like to remove white flash when window kicks in |
| { |
| Rect r; |
| SetRect (&r, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); |
| PaintRect (&r); |
| QDFlushPortBuffer (port, nil); |
| } |
| */ |
| } |
| else { |
| port = [ window_view qdPort ]; |
| SetPort (port); |
| } |
| |
| SetIdentityMatrix (yuv_matrix); |
| |
| HLock ((Handle)yuv_idh); |
| |
| (**yuv_idh).idSize = sizeof(ImageDescription); |
| (**yuv_idh).cType = codec; |
| (**yuv_idh).version = 1; |
| (**yuv_idh).revisionLevel = 0; |
| (**yuv_idh).width = width; |
| (**yuv_idh).height = height; |
| (**yuv_idh).hRes = Long2Fix(72); |
| (**yuv_idh).vRes = Long2Fix(72); |
| (**yuv_idh).spatialQuality = codecLosslessQuality; |
| (**yuv_idh).frameCount = 1; |
| (**yuv_idh).clutID = -1; |
| (**yuv_idh).dataSize = 0; |
| (**yuv_idh).depth = 24; |
| |
| HUnlock ((Handle)yuv_idh); |
| |
| err = DecompressSequenceBeginS ( |
| &yuv_seq, |
| yuv_idh, |
| NULL, |
| 0, |
| port, |
| NULL, |
| NULL, |
| yuv_matrix, |
| 0, |
| NULL, |
| codecFlagUseImageBuffer, |
| codecLosslessQuality, |
| yuv_codec); |
| |
| if (err != noErr) { |
| SDL_SetError ("Error trying to start YUV codec."); |
| return NULL; |
| } |
| |
| overlay = (SDL_Overlay*) SDL_malloc (sizeof(*overlay)); |
| if (overlay == NULL) { |
| SDL_OutOfMemory(); |
| return NULL; |
| } |
| |
| overlay->format = format; |
| overlay->w = width; |
| overlay->h = height; |
| overlay->planes = 3; |
| overlay->hw_overlay = 1; |
| { |
| int offset; |
| Uint8 **pixels; |
| Uint16 *pitches; |
| int plane2, plane3; |
| |
| if (format == SDL_IYUV_OVERLAY) { |
| |
| plane2 = 1; /* Native codec format */ |
| plane3 = 2; |
| } |
| else if (format == SDL_YV12_OVERLAY) { |
| |
| /* switch the U and V planes */ |
| plane2 = 2; /* U plane maps to plane 3 */ |
| plane3 = 1; /* V plane maps to plane 2 */ |
| } |
| else { |
| SDL_SetError("Unsupported YUV format"); |
| return NULL; |
| } |
| |
| pixels = (Uint8**) SDL_malloc (sizeof(*pixels) * 3); |
| pitches = (Uint16*) SDL_malloc (sizeof(*pitches) * 3); |
| if (pixels == NULL || pitches == NULL) { |
| SDL_OutOfMemory(); |
| return NULL; |
| } |
| |
| /* Fix: jc.bertin@free.fr |
| PlanarPixmapInfoYUV420 is a big-endian struct */ |
| yuv_pixmap = (PlanarPixmapInfoYUV420*) |
| SDL_malloc (sizeof(PlanarPixmapInfoYUV420) + |
| (width * height * 2)); |
| if (yuv_pixmap == NULL) { |
| SDL_OutOfMemory (); |
| return NULL; |
| } |
| |
| /* CHECK_ALIGN(yuv_pixmap); */ |
| offset = sizeof(PlanarPixmapInfoYUV420); |
| /* offset += ALIGN(offset); */ |
| /* CHECK_ALIGN(offset); */ |
| |
| pixels[0] = (Uint8*)yuv_pixmap + offset; |
| /* CHECK_ALIGN(pixels[0]); */ |
| |
| pitches[0] = width; |
| yuv_pixmap->componentInfoY.offset = EndianS32_NtoB(offset); |
| yuv_pixmap->componentInfoY.rowBytes = EndianU32_NtoB(width); |
| |
| offset += width * height; |
| pixels[plane2] = (Uint8*)yuv_pixmap + offset; |
| pitches[plane2] = width / 2; |
| yuv_pixmap->componentInfoCb.offset = EndianS32_NtoB(offset); |
| yuv_pixmap->componentInfoCb.rowBytes = EndianU32_NtoB(width / 2); |
| |
| offset += (width * height / 4); |
| pixels[plane3] = (Uint8*)yuv_pixmap + offset; |
| pitches[plane3] = width / 2; |
| yuv_pixmap->componentInfoCr.offset = EndianS32_NtoB(offset); |
| yuv_pixmap->componentInfoCr.rowBytes = EndianU32_NtoB(width / 2); |
| |
| overlay->pixels = pixels; |
| overlay->pitches = pitches; |
| } |
| |
| overlay->hwfuncs = SDL_malloc (sizeof(*overlay->hwfuncs)); |
| if (overlay->hwfuncs == NULL) { |
| SDL_OutOfMemory(); |
| return NULL; |
| } |
| |
| overlay->hwfuncs->Lock = QZ_LockYUV; |
| overlay->hwfuncs->Unlock = QZ_UnlockYUV; |
| overlay->hwfuncs->Display = QZ_DisplayYUV; |
| overlay->hwfuncs->FreeHW = QZ_FreeHWYUV; |
| |
| yuv_width = overlay->w; |
| yuv_height = overlay->h; |
| |
| return overlay; |
| } |