symbian-qemu-0.9.1-12/libsdl-trunk/src/video/quartz/SDL_QuartzYUV.m
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/libsdl-trunk/src/video/quartz/SDL_QuartzYUV.m	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,330 @@
+/*
+    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;
+}