summaryrefslogtreecommitdiffstats
path: root/sys/osxvideo/cocoawindow.m
diff options
context:
space:
mode:
Diffstat (limited to 'sys/osxvideo/cocoawindow.m')
-rw-r--r--sys/osxvideo/cocoawindow.m475
1 files changed, 475 insertions, 0 deletions
diff --git a/sys/osxvideo/cocoawindow.m b/sys/osxvideo/cocoawindow.m
new file mode 100644
index 00000000..e5f7694a
--- /dev/null
+++ b/sys/osxvideo/cocoawindow.m
@@ -0,0 +1,475 @@
+/* GStreamer
+ * Copyright (C) 2004 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ *
+ * 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 Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* inspiration gained from looking at source of osx video out of xine and vlc
+ * and is reflected in the code
+ */
+
+
+#include <Cocoa/Cocoa.h>
+#include <gst/gst.h>
+#import "cocoawindow.h"
+#import "osxvideosink.h"
+
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+
+/* Debugging category */
+#include <gst/gstinfo.h>
+
+@ implementation GstOSXVideoSinkWindow
+
+- (id) initWithContentRect: (NSRect) rect
+ styleMask: (unsigned int) styleMask
+ backing: (NSBackingStoreType) bufferingType
+ defer: (BOOL) flag
+ screen:(NSScreen *) aScreen
+{
+ self = [super initWithContentRect: rect
+ styleMask: styleMask
+ backing: bufferingType
+ defer: flag
+ screen:aScreen];
+
+ GST_DEBUG ("Initializing GstOSXvideoSinkWindow");
+
+ gstview = [[GstGLView alloc] initWithFrame:rect];
+
+ if (gstview)
+ [self setContentView:gstview];
+ [self setTitle:@"GStreamer Video Output"];
+
+ return self;
+}
+
+- (void) setContentSize:(NSSize) size {
+ width = size.width;
+ height = size.height;
+
+ [gstview setVideoSize: (int) width:(int) height];
+
+ [super setContentSize:size];
+}
+
+- (GstGLView *) gstView {
+ return gstview;
+}
+
+- (void) awakeFromNib {
+ [self setAcceptsMouseMovedEvents:YES];
+}
+
+- (void) sendEvent:(NSEvent *) event {
+ BOOL taken = NO;
+
+ GST_LOG ("event %p type:%d", event,[event type]);
+
+ if ([event type] == NSKeyDown) {
+ }
+ /*taken = [gstview keyDown:event]; */
+
+ if (!taken) {
+ [super sendEvent:event];
+ }
+}
+
+
+@end
+
+//
+// GstView
+// Deprecated QuickDraw implementation
+//
+
+@ implementation GstView
+
+- (void) drawRect:(NSRect) rect {
+ /*NSRect bounds = [self bounds];
+ [[NSColor greenColor] set];
+ [NSBezierPath fillRect:bounds]; */
+ [[NSColor blackColor] set];
+ NSRectFill (rect);
+ [super drawRect:rect];
+}
+
+- (id) initWithFrame:(NSRect) frame {
+ NSRect bounds =[self bounds];
+
+ [[NSColor greenColor] set];
+
+ self =[super initWithFrame:frame];
+ isPortSet = FALSE;
+ [NSBezierPath fillRect:bounds];
+ return self;
+}
+
+- (void) setVideoSize: (int) w:(int) h {
+ GST_LOG ("width:%d height:%d", w, h);
+
+ width = w;
+ height = h;
+}
+
+- (void) setVideoImage:(GstBuffer *) img {
+ if (isPortSet == FALSE) {
+ // first image
+ //GWorldPtr imgGWorld;
+ //Rect coords;
+ OSErr err;
+ ImageDescriptionPtr pimgdesc;
+
+ err = EnterMovies ();
+
+ if (err != noErr)
+ GST_ERROR ("EnterMovies error: %d", err);
+ /*SetRect(&coords,0,0,width,height);
+ NewGWorldFromPtr (&imgGWorld, kYUV420CodecType, &coords, 0, 0, 0, GST_BUFFER_DATA(img), width * 4);
+ MakeImageDescriptionForPixMap (GetGWorldPixMap(imgGWorld), &imgdesc);
+ DisposeGWorld(imgGWorld); */
+ imgdesc =
+ (ImageDescriptionHandle) NewHandleClear (sizeof (ImageDescription));
+ pimgdesc = *imgdesc;
+ pimgdesc->idSize = sizeof (ImageDescription);
+ pimgdesc->cType = kYUV420CodecType;
+ pimgdesc->version = 1;
+ pimgdesc->revisionLevel = 0;
+ pimgdesc->vendor = 'appl';
+ pimgdesc->width = width;
+ pimgdesc->height = height;
+ pimgdesc->hRes = Long2Fix (72);
+ pimgdesc->vRes = Long2Fix (72);
+ pimgdesc->spatialQuality = codecLosslessQuality;
+ pimgdesc->frameCount = 1;
+ pimgdesc->clutID = -1;
+ pimgdesc->dataSize = 0;
+ pimgdesc->depth = 12;
+
+ [self lockFocus];
+ port =[self qdPort];
+ g_warning ("port = 0x%x", (int) port);
+ err = DecompressSequenceBeginS (&qtseqid, imgdesc, NULL, 0, port, NULL, NULL, NULL, 0, // srcCopy
+ NULL, codecFlagUseImageBuffer, codecLosslessQuality, bestSpeedCodec);
+ if (err != noErr) {
+ GST_DEBUG ("DecompressSequenceBeginS error: %d", err);
+ }
+ [self unlockFocus];
+ isPortSet = TRUE;
+ }
+
+ OSErr err;
+ CodecFlags flags;
+
+ GST_DEBUG ("qtseqid: %d img data: %p size: %d", (int) qtseqid,
+ GST_BUFFER_DATA (img), GST_BUFFER_SIZE (img));
+ err =
+ DecompressSequenceFrameS (qtseqid, (char *) GST_BUFFER_DATA (img),
+ GST_BUFFER_SIZE (img), codecFlagUseImageBuffer, &flags, NULL);
+ if (err != noErr) {
+ GST_DEBUG ("DecompressSequenceS erro: %d", err);
+ } else {
+ //QDFlushPortBuffer (port, nil);
+ }
+
+}
+
+@end
+
+//
+// OpenGL implementation
+//
+
+@ implementation GstGLView
+
+- (id) initWithFrame:(NSRect) frame {
+ NSOpenGLPixelFormat *fmt;
+ NSOpenGLPixelFormatAttribute attribs[] = {
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFANoRecovery,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAColorSize, 24,
+ NSOpenGLPFAAlphaSize, 8,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAWindow,
+ 0
+ };
+
+ fmt = [[NSOpenGLPixelFormat alloc]
+ initWithAttributes:attribs];
+
+ if (!fmt) {
+ GST_WARNING ("Cannot create NSOpenGLPixelFormat");
+ return nil;
+ }
+
+ self = [super initWithFrame: frame pixelFormat:fmt];
+
+ [[self openGLContext] makeCurrentContext];
+ [[self openGLContext] update];
+
+ /* Black background */
+ glClearColor (0.0, 0.0, 0.0, 0.0);
+
+ pi_texture = 0;
+ data = g_malloc (2 * 320 * 240);
+ width = frame.size.width;
+ height = frame.size.height;
+
+ GST_LOG ("Width: %d Height: %d", width, height);
+
+ [self initTextures];
+ return self;
+}
+
+- (void) reshape {
+ NSRect bounds;
+
+ GST_LOG ("reshaping");
+
+ if (!initDone) {
+ return;
+ }
+
+ [[self openGLContext] makeCurrentContext];
+
+ bounds = [self bounds];
+
+ glViewport (0, 0, (GLint) bounds.size.width, (GLint) bounds.size.height);
+
+}
+
+- (void) initTextures {
+ NSOpenGLContext *currentContext;
+
+ if (fullscreen)
+ currentContext = fullScreenContext;
+ else
+ currentContext =[self openGLContext];
+
+ [currentContext makeCurrentContext];
+
+ /* Free previous texture if any */
+ if (initDone) {
+ glDeleteTextures (1, &pi_texture);
+ }
+ /* Create textures */
+ glGenTextures (1, &pi_texture);
+
+ glEnable (GL_TEXTURE_RECTANGLE_EXT);
+ glEnable (GL_UNPACK_CLIENT_STORAGE_APPLE);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
+
+ /* Use VRAM texturing */
+ glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
+
+ /* Tell the driver not to make a copy of the texture but to use
+ our buffer */
+ glPixelStorei (GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
+
+
+ /* Linear interpolation */
+ glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ /* I have no idea what this exactly does, but it seems to be
+ necessary for scaling */
+ glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
+ GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+
+ glTexImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,
+ width, height, 0, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data);
+
+
+ initDone = 1;
+}
+
+- (void) reloadTexture {
+ NSOpenGLContext *currentContext;
+
+ if (!initDone) {
+ return;
+ }
+
+ GST_LOG ("Reloading Texture");
+
+ if (fullscreen)
+ currentContext = fullScreenContext;
+ else
+ currentContext =[self openGLContext];
+ [currentContext makeCurrentContext];
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
+
+ /* glTexSubImage2D is faster than glTexImage2D
+ http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/
+ TextureRange/MainOpenGLView.m.htm */
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, width, height, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data); //FIXME
+}
+
+- (void) cleanUp {
+ initDone = 0;
+}
+
+- (void) drawQuad {
+ f_x = 1.0;
+ f_y = 1.0;
+
+ glBegin (GL_QUADS);
+ /* Top left */
+ glTexCoord2f (0.0, 0.0);
+ glVertex2f (-f_x, f_y);
+ /* Bottom left */
+ glTexCoord2f (0.0, (float) height);
+ glVertex2f (-f_x, -f_y);
+ /* Bottom right */
+ glTexCoord2f ((float) width, (float) height);
+ glVertex2f (f_x, -f_y);
+ /* Top right */
+ glTexCoord2f ((float) width, 0.0);
+ glVertex2f (f_x, f_y);
+ glEnd ();
+}
+
+- (void) drawRect:(NSRect) rect {
+ NSOpenGLContext *currentContext;
+ long params[] = { 1 };
+
+ if (fullscreen) {
+ currentContext = fullScreenContext;
+ } else {
+ currentContext =[self openGLContext];
+ }
+ [currentContext makeCurrentContext];
+
+ CGLSetParameter (CGLGetCurrentContext (), kCGLCPSwapInterval, params);
+
+ /* Black background */
+ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (!initDone) {
+ [[self openGLContext] flushBuffer];
+ return;
+ }
+
+ /* Draw */
+ glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); // FIXME
+ [self drawQuad];
+ /* Draw */
+ [currentContext flushBuffer];
+}
+
+- (void) displayTexture {
+ if ([self lockFocusIfCanDraw]) {
+
+ [self drawRect:[self bounds]];
+ [self reloadTexture];
+
+ [self unlockFocus];
+
+ }
+
+}
+
+- (char *) getTextureBuffer {
+ return data;
+}
+
+- (void) setFullScreen:(BOOL) flag {
+ if (!fullscreen && flag) {
+ // go to full screen
+ /* Create the new pixel format */
+ NSOpenGLPixelFormat *fmt;
+ NSOpenGLPixelFormatAttribute attribs[] = {
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFANoRecovery,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAColorSize, 24,
+ NSOpenGLPFAAlphaSize, 8,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAFullScreen,
+ NSOpenGLPFAScreenMask,
+ CGDisplayIDToOpenGLDisplayMask (kCGDirectMainDisplay),
+ 0
+ };
+
+ fmt = [[NSOpenGLPixelFormat alloc]
+ initWithAttributes:attribs];
+
+ if (!fmt) {
+ GST_WARNING ("Cannot create NSOpenGLPixelFormat");
+ return;
+ }
+
+ /* Create the new OpenGL context */
+ fullScreenContext = [[NSOpenGLContext alloc]
+ initWithFormat: fmt shareContext:nil];
+ if (!fullScreenContext) {
+ GST_WARNING ("Failed to create new NSOpenGLContext");
+ return;
+ }
+
+ /* Capture display, switch to fullscreen */
+ if (CGCaptureAllDisplays () != CGDisplayNoErr) {
+ GST_WARNING ("CGCaptureAllDisplays() failed");
+ return;
+ }
+ [fullScreenContext setFullScreen];
+ [fullScreenContext makeCurrentContext];
+
+ fullscreen = YES;
+
+ [self initTextures];
+ [self setNeedsDisplay:YES];
+
+ } else if (fullscreen && !flag) {
+ // fullscreen now and needs to go back to normal
+ initDone = NO;
+ [NSOpenGLContext clearCurrentContext];
+
+ CGReleaseAllDisplays ();
+
+ [self reshape];
+ [self initTextures];
+
+ [self setNeedsDisplay:YES];
+
+ fullscreen = NO;
+ initDone = YES;
+ }
+}
+
+- (void) setVideoSize: (int) w:(int) h {
+ GST_LOG ("width:%d, height:%d", w, h);
+
+ width = w;
+ height = h;
+
+ // FIXME : so, do we free, or don't we ?
+ //if (data) g_free(data);
+
+ data = g_malloc0 (2 * w * h);
+ [self reloadTexture];
+}
+
+@end