summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--sys/osxvideo/cocoawindow.h1
-rw-r--r--sys/osxvideo/cocoawindow.m91
-rw-r--r--sys/osxvideo/osxvideosink.h12
-rw-r--r--sys/osxvideo/osxvideosink.m176
5 files changed, 237 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index 87ceac3c..7cdf7d0e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2007-03-14 Edward Hervey <edward@fluendo.com>
+
+ * sys/osxvideo/cocoawindow.h:
+ * sys/osxvideo/cocoawindow.m:
+ * sys/osxvideo/osxvideosink.h:
+ * sys/osxvideo/osxvideosink.m:
+ Fix leaks when running a NSApp.
+ Accept any kind of resolutions.
+ Works in fullscreen. Can maximize.
+ Only thing left before being able to move this to -good is documentation
+ and embedded window support.
+
2007-03-14 Thomas Vander Stichele <thomas at apestaart dot org>
* po/hu.po:
diff --git a/sys/osxvideo/cocoawindow.h b/sys/osxvideo/cocoawindow.h
index f479c995..340bd160 100644
--- a/sys/osxvideo/cocoawindow.h
+++ b/sys/osxvideo/cocoawindow.h
@@ -43,6 +43,7 @@ struct _GstOSXImage;
int width, height;
BOOL fullscreen;
NSOpenGLContext* fullScreenContext;
+ NSOpenGLContext* actualContext;
}
- (void) drawQuad;
- (void) drawRect: (NSRect) rect;
diff --git a/sys/osxvideo/cocoawindow.m b/sys/osxvideo/cocoawindow.m
index e191de45..9b5e7b31 100644
--- a/sys/osxvideo/cocoawindow.m
+++ b/sys/osxvideo/cocoawindow.m
@@ -41,6 +41,7 @@
@ implementation GstOSXVideoSinkWindow
+/* The object has to be released */
- (id) initWithContentRect: (NSRect) rect
styleMask: (unsigned int) styleMask
backing: (NSBackingStoreType) bufferingType
@@ -84,7 +85,7 @@
- (void) sendEvent:(NSEvent *) event {
BOOL taken = NO;
- GST_LOG ("event %p type:%d", event,[event type]);
+ GST_DEBUG ("event %p type:%d", event,[event type]);
if ([event type] == NSKeyDown) {
}
@@ -128,14 +129,15 @@
self = [super initWithFrame: frame pixelFormat:fmt];
- [[self openGLContext] makeCurrentContext];
- [[self openGLContext] update];
+ actualContext = [self openGLContext];
+ [actualContext makeCurrentContext];
+ [actualContext update];
/* Black background */
glClearColor (0.0, 0.0, 0.0, 0.0);
pi_texture = 0;
- data = g_malloc (2 * 320 * 240);
+ data = nil;
width = frame.size.width;
height = frame.size.height;
@@ -154,7 +156,7 @@
return;
}
- [[self openGLContext] makeCurrentContext];
+ [actualContext makeCurrentContext];
bounds = [self bounds];
@@ -163,25 +165,28 @@
}
- (void) initTextures {
- NSOpenGLContext *currentContext;
- if (fullscreen)
- currentContext = fullScreenContext;
- else
- currentContext =[self openGLContext];
-
- [currentContext makeCurrentContext];
+ [actualContext makeCurrentContext];
/* Free previous texture if any */
- if (initDone) {
+ if (pi_texture) {
glDeleteTextures (1, &pi_texture);
}
+
+ if (data) {
+ data = g_realloc (data, width * height * sizeof(short)); // short or 3byte?
+ } else {
+ data = g_malloc0(width * height * sizeof(short));
+ }
/* Create textures */
glGenTextures (1, &pi_texture);
glEnable (GL_TEXTURE_RECTANGLE_EXT);
glEnable (GL_UNPACK_CLIENT_STORAGE_APPLE);
+ glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
+
glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
/* Use VRAM texturing */
@@ -192,7 +197,6 @@
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);
@@ -203,36 +207,34 @@
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);
+ // glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); WHY ??
glTexImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,
- width, height, 0, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data);
+ 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];
+ [actualContext makeCurrentContext];
glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
/* 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
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0,
+ width, height,
+ GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data); //FIXME
}
- (void) cleanUp {
@@ -260,15 +262,9 @@
}
- (void) drawRect:(NSRect) rect {
- NSOpenGLContext *currentContext;
long params[] = { 1 };
- if (fullscreen) {
- currentContext = fullScreenContext;
- } else {
- currentContext =[self openGLContext];
- }
- [currentContext makeCurrentContext];
+ [actualContext makeCurrentContext];
CGLSetParameter (CGLGetCurrentContext (), kCGLCPSwapInterval, params);
@@ -276,7 +272,7 @@
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (!initDone) {
- [[self openGLContext] flushBuffer];
+ [actualContext flushBuffer];
return;
}
@@ -284,7 +280,7 @@
glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); // FIXME
[self drawQuad];
/* Draw */
- [currentContext flushBuffer];
+ [actualContext flushBuffer];
}
- (void) displayTexture {
@@ -337,6 +333,8 @@
return;
}
+ actualContext = fullScreenContext;
+
/* Capture display, switch to fullscreen */
if (CGCaptureAllDisplays () != CGDisplayNoErr) {
GST_WARNING ("CGCaptureAllDisplays() failed");
@@ -353,7 +351,13 @@
} else if (fullscreen && !flag) {
// fullscreen now and needs to go back to normal
initDone = NO;
+
+ actualContext = [self openGLContext];
+
[NSOpenGLContext clearCurrentContext];
+ [fullScreenContext clearDrawable];
+ [fullScreenContext release];
+ fullScreenContext = nil;
CGReleaseAllDisplays ();
@@ -373,11 +377,24 @@
width = w;
height = h;
- // FIXME : so, do we free, or don't we ?
- //if (data) g_free(data);
+// if (data) g_free(data);
- data = g_malloc0 (2 * w * h);
- [self reloadTexture];
+// data = g_malloc0 (2 * w * h);
+ [self initTextures];
}
+- (void) dealloc {
+ GST_LOG ("dealloc called");
+ if (data) g_free(data);
+
+ if (fullScreenContext) {
+ [NSOpenGLContext clearCurrentContext];
+ [fullScreenContext clearDrawable];
+ [fullScreenContext release];
+ if (actualContext == fullScreenContext) actualContext = nil;
+ fullScreenContext = nil;
+ }
+
+ [super dealloc];
+}
@end
diff --git a/sys/osxvideo/osxvideosink.h b/sys/osxvideo/osxvideosink.h
index 2c144f5e..d7fba966 100644
--- a/sys/osxvideo/osxvideosink.h
+++ b/sys/osxvideo/osxvideosink.h
@@ -65,12 +65,12 @@ struct _GstOSXWindow {
gboolean internal;
GstOSXVideoSinkWindow* win;
GstGLView* gstview;
+ NSAutoreleasePool *pool;
};
struct _GstOSXVideoSink {
/* Our element stuff */
GstVideoSink videosink;
-
GstOSXWindow *osxwindow;
gint fps_n;
@@ -92,6 +92,16 @@ struct _GstOSXVideoSinkClass {
GType gst_osx_video_sink_get_type(void);
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+@interface NSApplication(AppleMenu)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+#endif
+
+@interface GstAppDelegate : NSObject
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+@end
+
G_END_DECLS
#endif /* __GST_OSX_VIDEO_SINK_H__ */
diff --git a/sys/osxvideo/osxvideosink.m b/sys/osxvideo/osxvideosink.m
index 0122c4cb..a521d068 100644
--- a/sys/osxvideo/osxvideosink.m
+++ b/sys/osxvideo/osxvideosink.m
@@ -27,7 +27,7 @@
/* Object header */
#include "osxvideosink.h"
-
+#include <unistd.h>
#import "cocoawindow.h"
/* Debugging category */
@@ -51,9 +51,31 @@ GST_STATIC_PAD_TEMPLATE ("sink",
"framerate = (fraction) [ 0, MAX ], "
"width = (int) [ 1, MAX ], "
"height = (int) [ 1, MAX ], "
+#ifdef G_BYTE_ORDER == G_BIG_ENDIAN
+ "format = (fourcc) YUY2")
+#else
"format = (fourcc) UYVY")
+#endif
);
+// much of the following cocoa NSApp code comes from libsdl and libcaca
+@implementation NSApplication(Gst)
+- (void)setRunning
+{
+ _running = 1;
+}
+@end
+
+@implementation GstAppDelegate : NSObject
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
+{
+ // destroy stuff here!
+ GST_DEBUG("Kill me please!");
+ return NSTerminateNow;
+}
+@end
+
+
enum
{
ARG_0,
@@ -64,18 +86,113 @@ enum
static GstVideoSinkClass *parent_class = NULL;
+
/* cocoa event loop - needed if not run in own app */
-/* FIXME : currently disabled since a huge memory leak happens if it is run. */
-gpointer
+gint
cocoa_event_loop (GstOSXVideoSink * vsink)
{
- GST_DEBUG_OBJECT (vsink, "About to start cocoa event loop");
+ NSAutoreleasePool *pool;
+
+ pool = [[NSAutoreleasePool alloc] init];
+
+ if ([NSApp isRunning]) {
+ NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode dequeue:YES ];
+ if ( event != nil ) {
+ switch ([event type]) {
+ default: //XXX Feed me please
+ [NSApp sendEvent:event];
+ break;
+ }
+ }
+ }
+
+ [pool release];
- [NSApp run];
+ return TRUE;
+}
- GST_DEBUG_OBJECT (vsink, "Cocoa event loop ended");
+static NSString *
+GetApplicationName(void)
+{
+ NSDictionary *dict;
+ NSString *appName = 0;
+
+ /* Determine the application name */
+ dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
+ if (dict)
+ appName = [dict objectForKey: @"CFBundleName"];
+
+ if (![appName length])
+ appName = [[NSProcessInfo processInfo] processName];
+
+ return appName;
+}
- return NULL;
+static void
+CreateApplicationMenus(void)
+{
+ NSString *appName;
+ NSString *title;
+ NSMenu *appleMenu;
+ NSMenu *windowMenu;
+ NSMenuItem *menuItem;
+
+ /* Create the main menu bar */
+ [NSApp setMainMenu:[[NSMenu alloc] init]];
+
+ /* Create the application menu */
+ appName = GetApplicationName();
+ appleMenu = [[NSMenu alloc] initWithTitle:@""];
+
+ /* Add menu items */
+ title = [@"About " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Hide " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@/*"h"*/""];
+
+ menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@/*"h"*/""];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+
+ [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Quit " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@/*"q"*/""];
+
+ /* Put menu into the menubar */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ [menuItem setSubmenu:appleMenu];
+ [[NSApp mainMenu] addItem:menuItem];
+ [menuItem release];
+
+ /* Tell the application object that this is now the application menu */
+ [NSApp setAppleMenu:appleMenu];
+ [appleMenu release];
+
+
+ /* Create the window menu */
+ windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ /* "Minimize" item */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@/*"m"*/""];
+ [windowMenu addItem:menuItem];
+ [menuItem release];
+
+ /* Put menu into the menubar */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
+ [menuItem setSubmenu:windowMenu];
+ [[NSApp mainMenu] addItem:menuItem];
+ [menuItem release];
+
+ /* Tell the application object that this is now the window menu */
+ [NSApp setWindowsMenu:windowMenu];
+ [windowMenu release];
}
/* This function handles osx window creation */
@@ -84,6 +201,7 @@ gst_osx_video_sink_osxwindow_new (GstOSXVideoSink * osxvideosink, gint width,
gint height)
{
NSRect rect;
+
GstOSXWindow *osxwindow = NULL;
g_return_val_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink), NULL);
@@ -93,28 +211,50 @@ gst_osx_video_sink_osxwindow_new (GstOSXVideoSink * osxvideosink, gint width,
osxwindow->width = width;
osxwindow->height = height;
osxwindow->internal = TRUE;
+ osxwindow->pool = [[NSAutoreleasePool alloc] init];
if (osxvideosink->embed == FALSE) {
- NSAutoreleasePool *pool;
+ ProcessSerialNumber psn;
+ unsigned int mask = NSTitledWindowMask |
+ NSClosableWindowMask |
+ NSResizableWindowMask |
+ NSTexturedBackgroundWindowMask |
+ NSMiniaturizableWindowMask;
rect.origin.x = 100.0;
rect.origin.y = 100.0;
rect.size.width = (float) osxwindow->width;
rect.size.height = (float) osxwindow->height;
- pool =[[NSAutoreleasePool alloc] init];
+ if (!GetCurrentProcess(&psn)) {
+ TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+ SetFrontProcess(&psn);
+ }
[NSApplication sharedApplication];
- osxwindow->win =[[GstOSXVideoSinkWindow alloc] initWithContentRect: rect styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask backing: NSBackingStoreBuffered defer: NO screen:nil];
+
+ osxwindow->win =[[GstOSXVideoSinkWindow alloc]
+ initWithContentRect: rect
+ styleMask: mask
+ backing: NSBackingStoreBuffered
+ defer: NO
+ screen: nil];
+ [osxwindow->win autorelease];
+ [NSApplication sharedApplication];
[osxwindow->win makeKeyAndOrderFront:NSApp];
osxwindow->gstview =[osxwindow->win gstView];
+ [osxwindow->gstview autorelease];
if (osxvideosink->fullscreen)
[osxwindow->gstview setFullScreen:YES];
- [pool release];
+ CreateApplicationMenus();
+
+ [NSApp finishLaunching];
+ [NSApp setDelegate:[[GstAppDelegate alloc] init]];
- /* Start Cocoa event loop */
-// g_thread_create ((GThreadFunc) cocoa_event_loop, osxvideosink, FALSE, NULL);
+ [NSApp setRunning];
+ // insert event dispatch in the glib main loop
+ g_idle_add ((GSourceFunc) cocoa_event_loop, osxvideosink);
} else {
/* Needs to be embedded */
@@ -123,6 +263,7 @@ gst_osx_video_sink_osxwindow_new (GstOSXVideoSink * osxvideosink, gint width,
rect.size.width = (float) osxwindow->width;
rect.size.height = (float) osxwindow->height;
osxwindow->gstview =[[GstGLView alloc] initWithFrame:rect];
+ [osxwindow->gstview autorelease];
/* send signal
FIXME: need to send a bus message */
/*g_signal_emit (G_OBJECT(osxvideosink),
@@ -140,6 +281,8 @@ gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink,
g_return_if_fail (osxwindow != NULL);
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
+ [osxwindow->pool release];
+
g_free (osxwindow);
}
@@ -149,7 +292,7 @@ gst_osx_video_sink_osxwindow_resize (GstOSXVideoSink * osxvideosink,
GstOSXWindow * osxwindow, guint width, guint height)
{
NSSize size;
-
+ NSAutoreleasePool *subPool = [[NSAutoreleasePool alloc] init];
g_return_if_fail (osxwindow != NULL);
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
@@ -159,7 +302,8 @@ gst_osx_video_sink_osxwindow_resize (GstOSXVideoSink * osxvideosink,
size.width = width;
size.height = height;
/* Call relevant cocoa function to resize window */
-[osxwindow->win setContentSize:size];
+ [osxwindow->win setContentSize:size];
+ [subPool release];
}
static void
@@ -350,10 +494,8 @@ static void
gst_osx_video_sink_init (GstOSXVideoSink * osxvideosink)
{
-
osxvideosink->osxwindow = NULL;
-
osxvideosink->fps_n = 0;
osxvideosink->fps_d = 0;