diff src/video/quartz/SDL_QuartzYUV.m @ 761:c5b2b6d2d1fe

Date: Wed, 31 Dec 2003 21:55:30 +0100 From: Max Horn Subject: SDL: video/quartz cleanup while doing some experimental changes in the quartz code, I was annoyed by having to recompile that one big .o file over and over again. So I decided to finally realize one TODO: properly splitting the code over multiple files :-). With two exceptions, I didn't make code changes, only rearranged files and added new headers. Since there are several new files, making a patch didn't work out so well, so I decided to just send you all the new & modified files. The one source change I made is related to showing/hiding the mouse. I renamed cursor_visible to cursor_should_be_visible and cursor_hidden to cursor_visible; I think that makes reading the code easier. Then I added two new functions: QZ_ShowMouse and QZ_HideMouse. They help manage cursor_visible (the former 'cursor_hidden'). Finally I replaced the Carbon ShowCursor/HiderCuror calls by [NSCursor hide] and [NSCursor unhide]. The API docs are not conclusive, but it might be that with those the "cursor_visible" (former 'cursor_hidden') hack may not be necessary anymore; however so far I didn't test this hypothesis, so I left that in. The other change was to remove in_foreground and use [NSApp isActive] instead: Manually keeping track of whether we are in the foreground is error prone. This should work better in some corner cases.
author Sam Lantinga <slouken@libsdl.org>
date Sun, 04 Jan 2004 14:55:35 +0000
parents
children 19418e4422cb
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/quartz/SDL_QuartzYUV.m	Sun Jan 04 14:55:35 2004 +0000
@@ -0,0 +1,327 @@
+/*
+    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_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 *dstrect) {
+
+    OSErr err;
+    CodecFlags flags;
+
+    if (dstrect->x != 0 || dstrect->y != 0) {
+
+        SDL_SetError ("Need a dstrect at (0,0)");
+        return -1;
+    }
+
+    if (dstrect->w != yuv_width || dstrect->h != yuv_height) {
+
+        Fixed scale_x, scale_y;
+
+        scale_x = FixDiv ( Long2Fix (dstrect->w), Long2Fix (overlay->w) );
+        scale_y = FixDiv ( Long2Fix (dstrect->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 = dstrect->w;
+        yuv_height = dstrect->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();
+
+    free (overlay->hwfuncs);
+    free (overlay->pitches);
+    free (overlay->pixels);
+
+    if (SDL_VideoSurface->flags & SDL_FULLSCREEN) {
+        [ qz_window close ];
+        qz_window = nil;
+    }
+
+    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) 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*) 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**) malloc (sizeof(*pixels) * 3);
+        pitches = (Uint16*) malloc (sizeof(*pitches) * 3);
+        if (pixels == NULL || pitches == NULL) {
+            SDL_OutOfMemory();
+            return NULL;
+        }
+
+        yuv_pixmap = (PlanarPixmapInfoYUV420*)
+            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 = offset;
+        yuv_pixmap->componentInfoY.rowBytes = width;
+
+        offset += width * height;
+        pixels[plane2] = (Uint8*)yuv_pixmap + offset;
+        pitches[plane2] = width / 2;
+        yuv_pixmap->componentInfoCb.offset = offset;
+        yuv_pixmap->componentInfoCb.rowBytes = width / 2;
+
+        offset += (width * height / 4);
+        pixels[plane3] = (Uint8*)yuv_pixmap + offset;
+        pitches[plane3] = width / 2;
+        yuv_pixmap->componentInfoCr.offset = offset;
+        yuv_pixmap->componentInfoCr.rowBytes = width / 2;
+
+        overlay->pixels = pixels;
+        overlay->pitches = pitches;
+    }
+
+    overlay->hwfuncs = 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;
+}