sys/osxvideo/: Fix leaks when running a NSApp.

Original commit message from CVS:
* 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.
This commit is contained in:
Edward Hervey 2007-03-14 16:30:19 +00:00
parent f8cc260297
commit 045440b483
5 changed files with 237 additions and 55 deletions

View file

@ -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> 2007-03-14 Thomas Vander Stichele <thomas at apestaart dot org>
* po/hu.po: * po/hu.po:

View file

@ -43,6 +43,7 @@ struct _GstOSXImage;
int width, height; int width, height;
BOOL fullscreen; BOOL fullscreen;
NSOpenGLContext* fullScreenContext; NSOpenGLContext* fullScreenContext;
NSOpenGLContext* actualContext;
} }
- (void) drawQuad; - (void) drawQuad;
- (void) drawRect: (NSRect) rect; - (void) drawRect: (NSRect) rect;

View file

@ -41,6 +41,7 @@
@ implementation GstOSXVideoSinkWindow @ implementation GstOSXVideoSinkWindow
/* The object has to be released */
- (id) initWithContentRect: (NSRect) rect - (id) initWithContentRect: (NSRect) rect
styleMask: (unsigned int) styleMask styleMask: (unsigned int) styleMask
backing: (NSBackingStoreType) bufferingType backing: (NSBackingStoreType) bufferingType
@ -84,7 +85,7 @@
- (void) sendEvent:(NSEvent *) event { - (void) sendEvent:(NSEvent *) event {
BOOL taken = NO; 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) { if ([event type] == NSKeyDown) {
} }
@ -128,14 +129,15 @@
self = [super initWithFrame: frame pixelFormat:fmt]; self = [super initWithFrame: frame pixelFormat:fmt];
[[self openGLContext] makeCurrentContext]; actualContext = [self openGLContext];
[[self openGLContext] update]; [actualContext makeCurrentContext];
[actualContext update];
/* Black background */ /* Black background */
glClearColor (0.0, 0.0, 0.0, 0.0); glClearColor (0.0, 0.0, 0.0, 0.0);
pi_texture = 0; pi_texture = 0;
data = g_malloc (2 * 320 * 240); data = nil;
width = frame.size.width; width = frame.size.width;
height = frame.size.height; height = frame.size.height;
@ -154,7 +156,7 @@
return; return;
} }
[[self openGLContext] makeCurrentContext]; [actualContext makeCurrentContext];
bounds = [self bounds]; bounds = [self bounds];
@ -163,25 +165,28 @@
} }
- (void) initTextures { - (void) initTextures {
NSOpenGLContext *currentContext;
if (fullscreen) [actualContext makeCurrentContext];
currentContext = fullScreenContext;
else
currentContext =[self openGLContext];
[currentContext makeCurrentContext];
/* Free previous texture if any */ /* Free previous texture if any */
if (initDone) { if (pi_texture) {
glDeleteTextures (1, &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 */ /* Create textures */
glGenTextures (1, &pi_texture); glGenTextures (1, &pi_texture);
glEnable (GL_TEXTURE_RECTANGLE_EXT); glEnable (GL_TEXTURE_RECTANGLE_EXT);
glEnable (GL_UNPACK_CLIENT_STORAGE_APPLE); glEnable (GL_UNPACK_CLIENT_STORAGE_APPLE);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
/* Use VRAM texturing */ /* Use VRAM texturing */
@ -192,7 +197,6 @@
our buffer */ our buffer */
glPixelStorei (GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); glPixelStorei (GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
/* Linear interpolation */ /* Linear interpolation */
glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_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); GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 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, 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; initDone = 1;
} }
- (void) reloadTexture { - (void) reloadTexture {
NSOpenGLContext *currentContext;
if (!initDone) { if (!initDone) {
return; return;
} }
GST_LOG ("Reloading Texture"); GST_LOG ("Reloading Texture");
if (fullscreen) [actualContext makeCurrentContext];
currentContext = fullScreenContext;
else
currentContext =[self openGLContext];
[currentContext makeCurrentContext];
glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
/* glTexSubImage2D is faster than glTexImage2D /* glTexSubImage2D is faster than glTexImage2D
http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/ http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/
TextureRange/MainOpenGLView.m.htm */ 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 { - (void) cleanUp {
@ -260,15 +262,9 @@
} }
- (void) drawRect:(NSRect) rect { - (void) drawRect:(NSRect) rect {
NSOpenGLContext *currentContext;
long params[] = { 1 }; long params[] = { 1 };
if (fullscreen) { [actualContext makeCurrentContext];
currentContext = fullScreenContext;
} else {
currentContext =[self openGLContext];
}
[currentContext makeCurrentContext];
CGLSetParameter (CGLGetCurrentContext (), kCGLCPSwapInterval, params); CGLSetParameter (CGLGetCurrentContext (), kCGLCPSwapInterval, params);
@ -276,7 +272,7 @@
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (!initDone) { if (!initDone) {
[[self openGLContext] flushBuffer]; [actualContext flushBuffer];
return; return;
} }
@ -284,7 +280,7 @@
glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); // FIXME glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); // FIXME
[self drawQuad]; [self drawQuad];
/* Draw */ /* Draw */
[currentContext flushBuffer]; [actualContext flushBuffer];
} }
- (void) displayTexture { - (void) displayTexture {
@ -337,6 +333,8 @@
return; return;
} }
actualContext = fullScreenContext;
/* Capture display, switch to fullscreen */ /* Capture display, switch to fullscreen */
if (CGCaptureAllDisplays () != CGDisplayNoErr) { if (CGCaptureAllDisplays () != CGDisplayNoErr) {
GST_WARNING ("CGCaptureAllDisplays() failed"); GST_WARNING ("CGCaptureAllDisplays() failed");
@ -353,7 +351,13 @@
} else if (fullscreen && !flag) { } else if (fullscreen && !flag) {
// fullscreen now and needs to go back to normal // fullscreen now and needs to go back to normal
initDone = NO; initDone = NO;
actualContext = [self openGLContext];
[NSOpenGLContext clearCurrentContext]; [NSOpenGLContext clearCurrentContext];
[fullScreenContext clearDrawable];
[fullScreenContext release];
fullScreenContext = nil;
CGReleaseAllDisplays (); CGReleaseAllDisplays ();
@ -373,11 +377,24 @@
width = w; width = w;
height = h; 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); // data = g_malloc0 (2 * w * h);
[self reloadTexture]; [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 @end

View file

@ -65,12 +65,12 @@ struct _GstOSXWindow {
gboolean internal; gboolean internal;
GstOSXVideoSinkWindow* win; GstOSXVideoSinkWindow* win;
GstGLView* gstview; GstGLView* gstview;
NSAutoreleasePool *pool;
}; };
struct _GstOSXVideoSink { struct _GstOSXVideoSink {
/* Our element stuff */ /* Our element stuff */
GstVideoSink videosink; GstVideoSink videosink;
GstOSXWindow *osxwindow; GstOSXWindow *osxwindow;
gint fps_n; gint fps_n;
@ -92,6 +92,16 @@ struct _GstOSXVideoSinkClass {
GType gst_osx_video_sink_get_type(void); 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 G_END_DECLS
#endif /* __GST_OSX_VIDEO_SINK_H__ */ #endif /* __GST_OSX_VIDEO_SINK_H__ */

View file

@ -27,7 +27,7 @@
/* Object header */ /* Object header */
#include "osxvideosink.h" #include "osxvideosink.h"
#include <unistd.h>
#import "cocoawindow.h" #import "cocoawindow.h"
/* Debugging category */ /* Debugging category */
@ -51,9 +51,31 @@ GST_STATIC_PAD_TEMPLATE ("sink",
"framerate = (fraction) [ 0, MAX ], " "framerate = (fraction) [ 0, MAX ], "
"width = (int) [ 1, MAX ], " "width = (int) [ 1, MAX ], "
"height = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], "
#ifdef G_BYTE_ORDER == G_BIG_ENDIAN
"format = (fourcc) YUY2")
#else
"format = (fourcc) UYVY") "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 enum
{ {
ARG_0, ARG_0,
@ -64,18 +86,113 @@ enum
static GstVideoSinkClass *parent_class = NULL; static GstVideoSinkClass *parent_class = NULL;
/* cocoa event loop - needed if not run in own app */ /* cocoa event loop - needed if not run in own app */
/* FIXME : currently disabled since a huge memory leak happens if it is run. */ gint
gpointer
cocoa_event_loop (GstOSXVideoSink * vsink) cocoa_event_loop (GstOSXVideoSink * vsink)
{ {
GST_DEBUG_OBJECT (vsink, "About to start cocoa event loop"); NSAutoreleasePool *pool;
[NSApp run]; pool = [[NSAutoreleasePool alloc] init];
GST_DEBUG_OBJECT (vsink, "Cocoa event loop ended"); 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;
}
}
}
return NULL; [pool release];
return TRUE;
}
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;
}
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 */ /* This function handles osx window creation */
@ -84,6 +201,7 @@ gst_osx_video_sink_osxwindow_new (GstOSXVideoSink * osxvideosink, gint width,
gint height) gint height)
{ {
NSRect rect; NSRect rect;
GstOSXWindow *osxwindow = NULL; GstOSXWindow *osxwindow = NULL;
g_return_val_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink), 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->width = width;
osxwindow->height = height; osxwindow->height = height;
osxwindow->internal = TRUE; osxwindow->internal = TRUE;
osxwindow->pool = [[NSAutoreleasePool alloc] init];
if (osxvideosink->embed == FALSE) { if (osxvideosink->embed == FALSE) {
NSAutoreleasePool *pool; ProcessSerialNumber psn;
unsigned int mask = NSTitledWindowMask |
NSClosableWindowMask |
NSResizableWindowMask |
NSTexturedBackgroundWindowMask |
NSMiniaturizableWindowMask;
rect.origin.x = 100.0; rect.origin.x = 100.0;
rect.origin.y = 100.0; rect.origin.y = 100.0;
rect.size.width = (float) osxwindow->width; rect.size.width = (float) osxwindow->width;
rect.size.height = (float) osxwindow->height; rect.size.height = (float) osxwindow->height;
pool =[[NSAutoreleasePool alloc] init]; if (!GetCurrentProcess(&psn)) {
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
}
[NSApplication sharedApplication]; [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->win makeKeyAndOrderFront:NSApp];
osxwindow->gstview =[osxwindow->win gstView]; osxwindow->gstview =[osxwindow->win gstView];
[osxwindow->gstview autorelease];
if (osxvideosink->fullscreen) if (osxvideosink->fullscreen)
[osxwindow->gstview setFullScreen:YES]; [osxwindow->gstview setFullScreen:YES];
[pool release]; CreateApplicationMenus();
/* Start Cocoa event loop */ [NSApp finishLaunching];
// g_thread_create ((GThreadFunc) cocoa_event_loop, osxvideosink, FALSE, NULL); [NSApp setDelegate:[[GstAppDelegate alloc] init]];
[NSApp setRunning];
// insert event dispatch in the glib main loop
g_idle_add ((GSourceFunc) cocoa_event_loop, osxvideosink);
} else { } else {
/* Needs to be embedded */ /* 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.width = (float) osxwindow->width;
rect.size.height = (float) osxwindow->height; rect.size.height = (float) osxwindow->height;
osxwindow->gstview =[[GstGLView alloc] initWithFrame:rect]; osxwindow->gstview =[[GstGLView alloc] initWithFrame:rect];
[osxwindow->gstview autorelease];
/* send signal /* send signal
FIXME: need to send a bus message */ FIXME: need to send a bus message */
/*g_signal_emit (G_OBJECT(osxvideosink), /*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 (osxwindow != NULL);
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink)); g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
[osxwindow->pool release];
g_free (osxwindow); g_free (osxwindow);
} }
@ -149,7 +292,7 @@ gst_osx_video_sink_osxwindow_resize (GstOSXVideoSink * osxvideosink,
GstOSXWindow * osxwindow, guint width, guint height) GstOSXWindow * osxwindow, guint width, guint height)
{ {
NSSize size; NSSize size;
NSAutoreleasePool *subPool = [[NSAutoreleasePool alloc] init];
g_return_if_fail (osxwindow != NULL); g_return_if_fail (osxwindow != NULL);
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink)); 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.width = width;
size.height = height; size.height = height;
/* Call relevant cocoa function to resize window */ /* Call relevant cocoa function to resize window */
[osxwindow->win setContentSize:size]; [osxwindow->win setContentSize:size];
[subPool release];
} }
static void static void
@ -350,10 +494,8 @@ static void
gst_osx_video_sink_init (GstOSXVideoSink * osxvideosink) gst_osx_video_sink_init (GstOSXVideoSink * osxvideosink)
{ {
osxvideosink->osxwindow = NULL; osxvideosink->osxwindow = NULL;
osxvideosink->fps_n = 0; osxvideosink->fps_n = 0;
osxvideosink->fps_d = 0; osxvideosink->fps_d = 0;