diff options
author | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2010-05-01 00:02:36 +0000 |
---|---|---|
committer | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2010-05-01 00:02:36 +0000 |
commit | 7b39a3d5564fe6f17e9ce9bfecac4f7fe525a379 (patch) | |
tree | edd2cc35aa321f5800d21b19a4e67180bb0daa09 /src/native | |
parent | b8d1fe3ceb438d27c9061aff931adb74eaadc44b (diff) | |
download | jitsi-7b39a3d5564fe6f17e9ce9bfecac4f7fe525a379.zip jitsi-7b39a3d5564fe6f17e9ce9bfecac4f7fe525a379.tar.gz jitsi-7b39a3d5564fe6f17e9ce9bfecac4f7fe525a379.tar.bz2 |
Modifies the native VideoRender on Mac OS X (which is still not being enabled in this commit) (1) to spare a copying of the frame to be rendered and (2) to be somewhat more responsive.
Diffstat (limited to 'src/native')
4 files changed, 303 insertions, 145 deletions
diff --git a/src/native/jawtrenderer/JAWTRenderer.h b/src/native/jawtrenderer/JAWTRenderer.h index 0a73259..afb87af 100644 --- a/src/native/jawtrenderer/JAWTRenderer.h +++ b/src/native/jawtrenderer/JAWTRenderer.h @@ -7,7 +7,7 @@ void JAWTRenderer_close (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component); jlong JAWTRenderer_open(JNIEnv *jniEnv, jclass clazz, jobject component); -void JAWTRenderer_paint +jboolean JAWTRenderer_paint (JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, jobject g); jboolean JAWTRenderer_process (JNIEnv *jniEnv, jclass clazz, diff --git a/src/native/jawtrenderer/JAWTRenderer_MacOSX.m b/src/native/jawtrenderer/JAWTRenderer_MacOSX.m index b6442e8..1a60f6c 100644 --- a/src/native/jawtrenderer/JAWTRenderer_MacOSX.m +++ b/src/native/jawtrenderer/JAWTRenderer_MacOSX.m @@ -13,6 +13,8 @@ #define JAWT_RENDERER_TEXTURE_FORMAT GL_BGRA #define JAWT_RENDERER_TEXTURE_TYPE GL_UNSIGNED_BYTE +@class JAWTRenderer, JAWTRendererOpenGLTexture, JAWTRendererOpenGLView; + @interface JAWTRenderer : NSObject { @public @@ -21,22 +23,38 @@ jint dataHeight; jint dataLength; jint dataWidth; + + JAWTRendererOpenGLTexture *texture; + + JAWTRendererOpenGLView *view; + NSOpenGLContext *glContext; + BOOL glContextIsPrepared; } - (void)dealloc; - (id)init; @end /* JAWTRenderer */ +@interface JAWTRendererOpenGLTexture : NSObject +{ +@public + GLuint texture; + jint width; + jint height; + BOOL filled; +} + +- (id)init; +- (BOOL)setDataFromRenderer:(JAWTRenderer *)renderer; +@end /* JAWTRendererOpenGLTexture */ + @interface JAWTRendererOpenGLView : NSOpenGLView { @private JAWTRenderer *renderer; - GLuint texture; - jint textureWidth; - jint textureHeight; + JAWTRendererOpenGLTexture *texture; } -- (void)clearGLContext; - (void)dealloc; - (void)drawRect:(NSRect)rect; - (id)initWithFrame:(NSRect)frameRect; @@ -46,6 +64,8 @@ - (void)setRenderer:(JAWTRenderer *)renderer; @end /* JAWTRendererOpenGLView */ +static void JAWTRenderer_prepareOpenGL(); + void JAWTRenderer_close (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component) @@ -75,11 +95,12 @@ JAWTRenderer_open(JNIEnv *jniEnv, jclass clazz, jobject component) return (jlong) renderer; } -void +jboolean JAWTRenderer_paint (JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, jobject g) { NSView *component; + jboolean wantsPaint; component = ((JAWT_MacOSXDrawingSurfaceInfo *) (dsi->platformInfo))->cocoaViewRef; @@ -87,40 +108,56 @@ JAWTRenderer_paint { JAWTRenderer *renderer; NSAutoreleasePool *autoreleasePool; - NSArray *subviews; JAWTRendererOpenGLView *rendererView; renderer = (JAWTRenderer *) handle; autoreleasePool = [[NSAutoreleasePool alloc] init]; - subviews = [component subviews]; - if ([subviews count]) - rendererView = [subviews objectAtIndex:0]; - else + @synchronized(renderer) { + rendererView = renderer->view; + if (!rendererView) + { + rendererView + = [[JAWTRendererOpenGLView alloc] + initWithFrame:[component bounds]]; + [rendererView setRenderer:renderer]; - rendererView - = [[JAWTRendererOpenGLView alloc] - initWithFrame:[component bounds]]; - - [component addSubview:rendererView]; - [rendererView release]; - - /* - * Have the rendererView autosized by the component which contains - * it. And since the rendererView has just been created to fill the - * current bounds of the component, it will always fill it this way. - */ - [component setAutoresizesSubviews:YES]; - [rendererView - setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + [component addSubview:rendererView]; + [rendererView release]; - [rendererView setRenderer:renderer]; + /* + * Have the rendererView autosized by the component which + * contains it. And since the rendererView has just been created + * to fill the current bounds of the component, it will always + * fill it this way. + */ + [component setAutoresizesSubviews:YES]; + [rendererView + setAutoresizingMask: + (NSViewWidthSizable | NSViewHeightSizable)]; + } } + wantsPaint = JNI_FALSE; + [rendererView display]; [autoreleasePool release]; } + else + wantsPaint = JNI_TRUE; + return wantsPaint; +} + +static void +JAWTRenderer_prepareOpenGL() +{ + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glDisable(GL_CULL_FACE); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); } jboolean @@ -131,42 +168,87 @@ JAWTRenderer_process jint width, jint height) { JAWTRenderer *renderer; + NSAutoreleasePool *autoreleasePool; size_t dataSize; jint *rendererData; jboolean processed; renderer = (JAWTRenderer *) handle; + autoreleasePool = [[NSAutoreleasePool alloc] init]; @synchronized(renderer) { - dataSize = sizeof(jint) * length; - if (renderer->dataCapacity < length) + if (renderer->glContext) { - jint newRendererDataCapacity; - jint *newRendererData; - newRendererData = realloc(renderer->data, dataSize); - if (newRendererData) + /* + * Once we've started processing the specified data directly into + * the OpenGL texture, it's unlikely that we'll need the data + * copy/field of the renderer. + */ + if (renderer->data) { - renderer->data = rendererData = newRendererData; - renderer->dataCapacity = length; + free(renderer->data); + renderer->dataCapacity = 0; } - else - rendererData = NULL; - } - else - rendererData = renderer->data; - if (rendererData) - { - memcpy(rendererData, data, dataSize); + renderer->data = data; renderer->dataHeight = height; renderer->dataLength = length; renderer->dataWidth = width; + + [renderer->glContext makeCurrentContext]; + if (!(renderer->glContextIsPrepared)) + { + renderer->glContextIsPrepared = YES; + JAWTRenderer_prepareOpenGL(); + } + [renderer->texture setDataFromRenderer:renderer]; + + renderer->data = NULL; + renderer->dataLength = 0; + processed = JNI_TRUE; } else - processed = JNI_FALSE; + { + dataSize = sizeof(jint) * length; + if (renderer->dataCapacity < length) + { + jint newRendererDataCapacity; + jint *newRendererData; + + newRendererData = realloc(renderer->data, dataSize); + if (newRendererData) + { + renderer->data = rendererData = newRendererData; + renderer->dataCapacity = length; + } + else + rendererData = NULL; + } + else + rendererData = renderer->data; + if (rendererData) + { + memcpy(rendererData, data, dataSize); + renderer->dataHeight = height; + renderer->dataLength = length; + renderer->dataWidth = width; + processed = JNI_TRUE; + } + else + processed = JNI_FALSE; + } + if (renderer->view) + { + [renderer->view + performSelectorOnMainThread:@selector(display) + withObject:nil + waitUntilDone:NO]; + } } + + [autoreleasePool release]; return processed; } @@ -175,6 +257,7 @@ JAWTRenderer_process { if (data) free(data); + [texture release]; /* * Do not release the view because no reference to it has been previously @@ -194,20 +277,114 @@ JAWTRenderer_process dataHeight = 0; dataLength = 0; dataWidth = 0; + + texture = [[JAWTRendererOpenGLTexture alloc] init]; + + view = nil; + glContext = nil; + glContextIsPrepared = NO; } return self; } @end /* JAWTRenderer */ -@implementation JAWTRendererOpenGLView -- (void)clearGLContext +@implementation JAWTRendererOpenGLTexture +- (id)init +{ + self = [super init]; + if (self) + { + texture = 0; + width = 0; + height = 0; + filled = NO; + } + return self; +} + +- (BOOL)setDataFromRenderer:(JAWTRenderer *)renderer { - [super clearGLContext]; + if (renderer->data && renderer->dataLength) + { + if (texture + && ((width != renderer->dataWidth)) + || (height != renderer->dataHeight)) + { + glDeleteTextures(1, &texture); + texture = 0; + } + if (texture) + { + glBindTexture(JAWT_RENDERER_TEXTURE, texture); + glTexSubImage2D( + JAWT_RENDERER_TEXTURE, + 0, + 0, 0, + renderer->dataWidth, renderer->dataHeight, + JAWT_RENDERER_TEXTURE_FORMAT, + JAWT_RENDERER_TEXTURE_TYPE, + renderer->data); + } + else + { + glGenTextures(1, &texture); + glBindTexture(JAWT_RENDERER_TEXTURE, texture); + glTexParameterf(JAWT_RENDERER_TEXTURE, GL_TEXTURE_PRIORITY, 1.0); + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_STORAGE_HINT_APPLE, + GL_STORAGE_SHARED_APPLE); + + glTexImage2D( + JAWT_RENDERER_TEXTURE, + 0, + 4, + renderer->dataWidth, renderer->dataHeight, + 0, + JAWT_RENDERER_TEXTURE_FORMAT, + JAWT_RENDERER_TEXTURE_TYPE, + renderer->data); + } + width = renderer->dataWidth; + height = renderer->dataHeight; + filled = YES; + + /* + * We've just created the texture from the data so we don't want + * to do it again. + */ + renderer->dataLength = 0; + } + else + filled = NO; + return filled; } +@end /* JAWTRendererOpenGLTexture */ +@implementation JAWTRendererOpenGLView - (void)dealloc { [self setRenderer:nil]; + [texture release]; [super dealloc]; } @@ -218,98 +395,46 @@ JAWTRenderer_process { @synchronized(renderer) { - if (renderer->data && renderer->dataLength) + if (renderer->texture->filled) { - if (texture - && ((textureWidth != renderer->dataWidth)) - || (textureHeight != renderer->dataHeight)) - { - glDeleteTextures(1, &texture); - texture = 0; - } - if (texture) - { - glBindTexture(JAWT_RENDERER_TEXTURE, texture); - glTexSubImage2D( - JAWT_RENDERER_TEXTURE, - 0, - 0, 0, - renderer->dataWidth, renderer->dataHeight, - JAWT_RENDERER_TEXTURE_FORMAT, - JAWT_RENDERER_TEXTURE_TYPE, - renderer->data); - } - else - { - glGenTextures(1, &texture); - glBindTexture(JAWT_RENDERER_TEXTURE, texture); - glTexParameterf( - JAWT_RENDERER_TEXTURE, GL_TEXTURE_PRIORITY, 1.0); - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_STORAGE_HINT_APPLE, - GL_STORAGE_SHARED_APPLE); - - glTexImage2D( - JAWT_RENDERER_TEXTURE, - 0, - 4, - renderer->dataWidth, renderer->dataHeight, - 0, - JAWT_RENDERER_TEXTURE_FORMAT, - JAWT_RENDERER_TEXTURE_TYPE, - renderer->data); - } - textureWidth = renderer->dataWidth; - textureHeight = renderer->dataHeight; + JAWTRendererOpenGLTexture *swap; - /* - * We've just created the texture from the data so we don't want - * to do it again. - */ - renderer->dataLength = 0; + swap = texture; + texture = renderer->texture; + renderer->texture = swap; + + renderer->texture->filled = NO; } - } - } + else + [texture setDataFromRenderer:renderer]; - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT); - if (texture) + if (texture->texture) + { + glBindTexture(JAWT_RENDERER_TEXTURE, texture->texture); + glEnable(JAWT_RENDERER_TEXTURE); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-1.0, 1.0); + glTexCoord2f(texture->width, 0); + glVertex2f(1.0, 1.0); + glTexCoord2f(texture->width, texture->height); + glVertex2f(1.0, -1.0); + glTexCoord2f(0, texture->height); + glVertex2f(-1.0, -1.0); + glEnd(); + glDisable(JAWT_RENDERER_TEXTURE); + } + + glFlush(); + } + } + else { - glEnable(JAWT_RENDERER_TEXTURE); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex2f(-1.0, 1.0); - glTexCoord2f(textureWidth, 0); - glVertex2f(1.0, 1.0); - glTexCoord2f(textureWidth, textureHeight); - glVertex2f(1.0, -1.0); - glTexCoord2f(0, textureHeight); - glVertex2f(-1.0, -1.0); - glEnd(); - glDisable(JAWT_RENDERER_TEXTURE); + glClear(GL_COLOR_BUFFER_BIT); + glFlush(); } - - glFlush(); } - (id)initWithFrame:(NSRect)frameRect @@ -321,9 +446,7 @@ JAWTRenderer_process if (self) { renderer = nil; - texture = 0; - textureWidth = 0; - textureHeight = 0; + texture = [[JAWTRendererOpenGLTexture alloc] init]; } return self; } @@ -337,12 +460,7 @@ JAWTRenderer_process { [super prepareOpenGL]; - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glDisable(GL_CULL_FACE); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + JAWTRenderer_prepareOpenGL(); } - (void)reshape @@ -375,10 +493,47 @@ JAWTRenderer_process if (renderer != aRenderer) { if (renderer) + { + @synchronized(renderer) + { + if (renderer->view == self) + renderer->view = nil; + if (renderer->glContext) + { + [renderer->glContext release]; + renderer->glContext = nil; + renderer->glContextIsPrepared = NO; + } + } [renderer release]; + } renderer = aRenderer; if (renderer) + { [renderer retain]; + @synchronized(renderer) + { + NSOpenGLContext *glContext; + + renderer->view = self; + + glContext = [self openGLContext]; + if (glContext) + { + if (renderer->glContext) + { + [renderer->glContext release]; + renderer->glContext = nil; + renderer->glContextIsPrepared = NO; + } + + renderer->glContext + = [[NSOpenGLContext alloc] + initWithFormat:[NSOpenGLView defaultPixelFormat] + shareContext:glContext]; + } + } + } } } @end /* JAWTRendererOpenGLView */ diff --git a/src/native/jawtrenderer/net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.c b/src/native/jawtrenderer/net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.c index abc4e35..8cd8330 100644 --- a/src/native/jawtrenderer/net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.c +++ b/src/native/jawtrenderer/net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.c @@ -15,14 +15,16 @@ Java_net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRen return JAWTRenderer_open(jniEnv, clazz, component); } -JNIEXPORT void JNICALL +JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paint (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component, jobject g) { JAWT awt; + jboolean wantsPaint; awt.version = JAWT_VERSION_1_3; + wantsPaint = JNI_TRUE; if (JAWT_GetAWT(jniEnv, &awt) != JNI_FALSE) { JAWT_DrawingSurface *ds; @@ -46,7 +48,7 @@ Java_net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRen * the JAWT_DrawingSurface which is itself the value of the * field ds of the JAWT_DrawingSurfaceInfo. */ - JAWTRenderer_paint(dsi, clazz, handle, g); + wantsPaint = JAWTRenderer_paint(dsi, clazz, handle, g); ds->FreeDrawingSurfaceInfo(dsi); } ds->Unlock(ds); @@ -54,6 +56,7 @@ Java_net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRen awt.FreeDrawingSurface(ds); } } + return wantsPaint; } JNIEXPORT jboolean JNICALL diff --git a/src/native/jawtrenderer/net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h b/src/native/jawtrenderer/net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h index 8c70c47..9af6d62 100644 --- a/src/native/jawtrenderer/net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h +++ b/src/native/jawtrenderer/net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h @@ -26,9 +26,9 @@ JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_neomedia_jmfext_medi /* * Class: net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer * Method: paint - * Signature: (JLjava/awt/Component;Ljava/awt/Graphics;)V + * Signature: (JLjava/awt/Component;Ljava/awt/Graphics;)Z */ -JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paint +JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paint (JNIEnv *, jclass, jlong, jobject, jobject); /* |