Home | History | Annotate | Download | only in quartz
      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