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.

cusax-fix
Lyubomir Marinov 16 years ago
parent b8d1fe3ceb
commit 7b39a3d556

@ -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,

@ -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 */

@ -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

@ -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);
/*

@ -141,15 +141,48 @@ public synchronized Component getComponent()
{
component = new Canvas()
{
/**
* The indicator which determines whether the native counterpart
* of this <tt>JAWTRenderer</tt> wants <tt>paint</tt> calls on
* its AWT <tt>Component</tt> to be delivered. For example,
* after the native counterpart has been able to acquire the
* native handle of the AWT <tt>Component</tt>, it may be able
* to determine when the native handle needs painting without
* waiting for AWT to call <tt>paint</tt> on the
* <tt>Component</tt>. In such a scenario, the native
* counterpart may indicate with <tt>false</tt> that it does not
* need further <tt>paint</tt> deliveries.
*/
private boolean wantsPaint = true;
@Override
public void addNotify()
{
super.addNotify();
wantsPaint = true;
}
@Override
public void paint(Graphics g)
{
synchronized (JAWTRenderer.this)
{
if (handle != 0)
JAWTRenderer.this.paint(handle, this, g);
if (wantsPaint && (handle != 0))
{
wantsPaint
= JAWTRenderer.this.paint(handle, this, g);
}
}
}
@Override
public void removeNotify()
{
wantsPaint = true;
super.removeNotify();
}
};
}
return component;
@ -228,8 +261,17 @@ private static native long open(Component component)
* <tt>paint</tt>.
* @param g the <tt>Graphics</tt> context into which the drawing is to be
* performed
* @return <tt>true</tt> if the native counterpart of a
* <tt>JAWTRenderer</tt> wants to continue receiving the <tt>paint</tt>
* calls on the AWT <tt>Component</tt>; otherwise, false. For example, after
* the native counterpart has been able to acquire the native handle of the
* AWT <tt>Component</tt>, it may be able to determine when the native
* handle needs painting without waiting for AWT to call <tt>paint</tt> on
* the <tt>Component</tt>. In such a scenario, the native counterpart may
* indicate with <tt>false</tt> that it does not need further <tt>paint</tt>
* deliveries.
*/
private static native void paint(
private static native boolean paint(
long handle, Component component, Graphics g);
/**

Loading…
Cancel
Save