configure.ac: Check for an Objective C compiler

Original commit message from CVS:
* configure.ac:
Check for an Objective C compiler
* sys/Makefile.am:
* sys/osxvideo/Makefile.am:
* sys/osxvideo/cocoawindow.h:
* sys/osxvideo/cocoawindow.m:
* sys/osxvideo/osxvideosink.h:
* sys/osxvideo/osxvideosink.m:
Port of osxvideo plugin to 0.10. Do NOT consider 100% stable !
Fixes #402470
This commit is contained in:
Edward Hervey 2007-01-30 17:19:33 +00:00
parent 3838fe023e
commit 385bba644f
8 changed files with 1198 additions and 2 deletions

View file

@ -1,3 +1,16 @@
2007-01-30 Edward Hervey <edward@fluendo.com>
* configure.ac:
Check for an Objective C compiler
* sys/Makefile.am:
* sys/osxvideo/Makefile.am:
* sys/osxvideo/cocoawindow.h:
* sys/osxvideo/cocoawindow.m:
* sys/osxvideo/osxvideosink.h:
* sys/osxvideo/osxvideosink.m:
Port of osxvideo plugin to 0.10. Do NOT consider 100% stable !
Fixes #402470
2007-01-28 Tim-Philipp Müller <tim at centricular dot net>
* gst/videocrop/gstvideocrop.c:

View file

@ -131,6 +131,8 @@ AC_PROG_CXX
dnl determine if c++ is available on this system
AC_CHECK_PROG(HAVE_CXX, $CXX, yes, no)
AS_PROG_OBJC
AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
@ -360,6 +362,24 @@ int main ()
AC_SUBST(HAVE_DIRECTSOUND)
])
dnl *** OS X video ***
translit(dnm, m, l) AM_CONDITIONAL(USE_OSX_VIDEO, true)
HAVE_OSX_VIDEO="no"
GST_CHECK_FEATURE(OSX_VIDEO, [OSX video], osxvideosink, [
AC_CHECK_HEADER(OpenGL/gl.h, HAVE_OSX_VIDEO="yes", HAVE_OSX_VIDEO="no")
])
dnl in case header OpenGL/gl.h is found on other platforms
case "$host" in
*-*darwin*)
dnl do nothing
;;
*)
HAVE_OSX_VIDEO="no"
;;
esac
dnl *** ext plug-ins ***
dnl keep this list sorted alphabetically !
@ -961,6 +981,7 @@ sys/glsink/Makefile
sys/dvb/Makefile
sys/directdraw/Makefile
sys/directsound/Makefile
sys/osxvideo/Makefile
examples/Makefile
examples/directfb/Makefile
ext/amrwb/Makefile

View file

@ -46,6 +46,12 @@ else
DIRECTSOUND_DIR=
endif
SUBDIRS = $(GL_DIR) $(DVB_DIR) $(DIRECTDRAW_DIR) $(DIRECTSOUND_DIR)
if USE_OSX_VIDEO
OSX_VIDEO_DIR=osxvideo
else
OSX_VIDEO_DIR=
endif
DIST_SUBDIRS = glsink dvb directdraw directsound
SUBDIRS = $(GL_DIR) $(DVB_DIR) $(DIRECTDRAW_DIR) $(DIRECTSOUND_DIR) $(OSX_VIDEO_DIR)
DIST_SUBDIRS = glsink dvb directdraw directsound osxvideo

17
sys/osxvideo/Makefile.am Normal file
View file

@ -0,0 +1,17 @@
# FIXME: clean up this crap
OBJC=gcc
plugin_LTLIBRARIES = libgstosxvideosink.la
libgstosxvideosink_la_SOURCES = osxvideosink.m cocoawindow.m
libgstosxvideosink_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS)
libgstosxvideosink_la_LIBADD = \
$(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
-lgstinterfaces-$(GST_MAJORMINOR)
libgstosxvideosink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework -Wl,Cocoa -Wl,-framework -Wl,QuickTime -Wl,-framework -Wl,OpenGL
AM_OBJCFLAGS=$(CFLAGS) $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS)
noinst_HEADERS = osxvideosink.h cocoawindow.h

View file

@ -0,0 +1,79 @@
/* 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
*/
#import <Cocoa/Cocoa.h>
#import <QuickTime/QuickTime.h>
#import <glib.h>
struct _GstOSXImage;
@interface GstGLView : NSOpenGLView
{
int i_effect;
unsigned long pi_texture;
float f_x;
float f_y;
int initDone;
char* data;
int width, height;
BOOL fullscreen;
NSOpenGLContext* fullScreenContext;
}
- (void) drawQuad;
- (void) drawRect: (NSRect) rect;
- (id) initWithFrame: (NSRect) frame;
- (void) initTextures;
- (void) reloadTexture;
- (void) cleanUp;
- (void) displayTexture;
- (char*) getTextureBuffer;
- (void) setFullScreen: (BOOL) flag;
- (void) reshape;
- (void) setVideoSize: (int) w: (int) h;
@end
@interface GstView : NSQuickDrawView {
int width, height;
gboolean isPortSet;
void* port;
/* Quicktime Sequence */
ImageSequence qtseqid;
ImageDescriptionHandle imgdesc;
struct _GstOSXImage* curimg;
}
- (void) drawRect: (NSRect) rect;
- (id) initWithFrame: (NSRect) frame;
- (void) setVideoSize: (int) w: (int) h;
- (void) setVideoImage: (GstBuffer*) img;
@end
@interface GstOSXVideoSinkWindow: NSWindow {
int width, height;
GstGLView *gstview;
}
- (void) setContentSize: (NSSize) size;
- (GstGLView *) gstView;
- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag screen:(NSScreen *)aScreen;
@end

475
sys/osxvideo/cocoawindow.m Normal file
View file

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

111
sys/osxvideo/osxvideosink.h Normal file
View file

@ -0,0 +1,111 @@
/* GStreamer
* Copyright (C) 2004-6 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.
*/
#ifndef __GST_OSX_VIDEO_SINK_H__
#define __GST_OSX_VIDEO_SINK_H__
#include <gst/video/gstvideosink.h>
#include <string.h>
#include <math.h>
#include <Cocoa/Cocoa.h>
#include <QuickTime/QuickTime.h>
#import "cocoawindow.h"
GST_DEBUG_CATEGORY_EXTERN (gst_debug_osx_video_sink);
#define GST_CAT_DEFAULT gst_debug_osx_video_sink
G_BEGIN_DECLS
#define GST_TYPE_OSX_VIDEO_SINK \
(gst_osx_video_sink_get_type())
#define GST_OSX_VIDEO_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OSX_VIDEO_SINK, GstOSXVideoSink))
#define GST_OSX_VIDEO_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OSX_VIDEO_SINK, GstOSXVideoSinkClass))
#define GST_IS_OSX_VIDEO_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OSX_VIDEO_SINK))
#define GST_IS_OSX_VIDEO_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OSX_VIDEO_SINK))
typedef struct _GstOSXWindow GstOSXWindow;
typedef struct _GstOSXVideoSink GstOSXVideoSink;
typedef struct _GstOSXVideoSinkClass GstOSXVideoSinkClass;
#define GST_TYPE_OSXVIDEOBUFFER (gst_osxvideobuffer_get_type())
#define GST_IS_OSXVIDEOBUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OSXVIDEOBUFFER))
#define GST_OSXVIDEOBUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OSXVIDEOBUFFER, GstOSXVideoBuffer))
typedef struct _GstOSXVideoBuffer GstOSXVideoBuffer;
struct _GstOSXVideoBuffer {
GstBuffer buffer; /* We extend GstBuffer */
CVOpenGLTextureRef texture;
gint width;
gint height;
gboolean locked;
GstOSXVideoSink *osxvideosink;
};
/* OSXWindow stuff */
struct _GstOSXWindow {
gint width, height;
gboolean internal;
GstOSXVideoSinkWindow* win;
GstGLView* gstview;
};
struct _GstOSXVideoSink {
/* Our element stuff */
GstVideoSink videosink;
GMutex *pool_lock;
GSList *buffer_pool;
GstOSXWindow *osxwindow;
gint fps_n;
gint fps_d;
/* Unused */
gint pixel_width, pixel_height;
GstClockTime time;
gboolean embed;
gboolean fullscreen;
gboolean sw_scaling_failed;
};
struct _GstOSXVideoSinkClass {
GstVideoSinkClass parent_class;
};
GType gst_osx_video_sink_get_type(void);
G_END_DECLS
#endif /* __GST_OSX_VIDEO_SINK_H__ */

474
sys/osxvideo/osxvideosink.m Normal file
View file

@ -0,0 +1,474 @@
/* GStreamer
* OSX video sink
* Copyright (C) 2004-6 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.
*/
#include "config.h"
/* Object header */
#include "osxvideosink.h"
#import "cocoawindow.h"
/* Debugging category */
GST_DEBUG_CATEGORY (gst_debug_osx_video_sink);
#define GST_CAT_DEFAULT gst_debug_osx_video_sink
/* ElementFactory information */
static const GstElementDetails gst_osx_video_sink_details =
GST_ELEMENT_DETAILS ("OSX Video sink",
"Sink/Video",
"OSX native videosink",
"Zaheer Abbas Merali <zaheerabbas at merali dot org>");
/* Default template - initiated with class struct to allow gst-register to work
without X running */
static GstStaticPadTemplate gst_osx_video_sink_sink_template_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-yuv, "
"framerate = (fraction) [ 0, MAX ], "
"width = (int) [ 1, MAX ], "
"height = (int) [ 1, MAX ], "
"format = (fourcc) UYVY")
);
enum
{
ARG_0,
ARG_EMBED,
ARG_FULLSCREEN
/* FILL ME */
};
static GstVideoSinkClass *parent_class = NULL;
/* cocoa event loop - needed if not run in own app */
gpointer
cocoa_event_loop (GstOSXVideoSink * vsink)
{
GST_DEBUG_OBJECT (vsink, "About to start cocoa event loop");
[NSApp run];
GST_DEBUG_OBJECT (vsink, "Cocoa event loop ended");
return NULL;
}
/* This function handles osx window creation */
static GstOSXWindow *
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);
osxwindow = g_new0 (GstOSXWindow, 1);
osxwindow->width = width;
osxwindow->height = height;
osxwindow->internal = TRUE;
if (osxvideosink->embed == FALSE) {
NSAutoreleasePool *pool;
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];
[NSApplication sharedApplication];
osxwindow->win =[[GstOSXVideoSinkWindow alloc] initWithContentRect: rect styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask backing: NSBackingStoreBuffered defer: NO screen:nil];
[osxwindow->win makeKeyAndOrderFront:NSApp];
osxwindow->gstview =[osxwindow->win gstView];
if (osxvideosink->fullscreen)
[osxwindow->gstview setFullScreen:YES];
[pool release];
/* Start Cocoa event loop */
g_thread_create ((GThreadFunc) cocoa_event_loop, osxvideosink, FALSE, NULL);
} else {
/* Needs to be embedded */
rect.origin.x = 0.0;
rect.origin.y = 0.0;
rect.size.width = (float) osxwindow->width;
rect.size.height = (float) osxwindow->height;
osxwindow->gstview =[[GstGLView alloc] initWithFrame:rect];
/* send signal
FIXME: need to send a bus message */
/*g_signal_emit (G_OBJECT(osxvideosink),
gst_osx_video_sink_signals[SIGNAL_VIEW_CREATED], 0,
osxwindow->gstview); */
}
return osxwindow;
}
/* This function destroys a GstXWindow */
static void
gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink,
GstOSXWindow * osxwindow)
{
g_return_if_fail (osxwindow != NULL);
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
g_free (osxwindow);
}
/* This function resizes a GstXWindow */
static void
gst_osx_video_sink_osxwindow_resize (GstOSXVideoSink * osxvideosink,
GstOSXWindow * osxwindow, guint width, guint height)
{
NSSize size;
g_return_if_fail (osxwindow != NULL);
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
//SizeWindow (osxwindow->win, width, height, 1);
osxwindow->width = width;
osxwindow->height = height;
size.width = width;
size.height = height;
/* Call relevant cocoa function to resize window */
[osxwindow->win setContentSize:size];
}
static void
gst_osx_video_sink_osxwindow_clear (GstOSXVideoSink * osxvideosink,
GstOSXWindow * osxwindow)
{
g_return_if_fail (osxwindow != NULL);
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
}
/* Element stuff */
static gboolean
gst_osx_video_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
{
GstOSXVideoSink *osxvideosink;
GstStructure *structure;
gboolean res, result = FALSE;
gint video_width, video_height;
const GValue *framerate;
osxvideosink = GST_OSX_VIDEO_SINK (bsink);
GST_DEBUG_OBJECT (osxvideosink, "caps: %" GST_PTR_FORMAT, caps);
structure = gst_caps_get_structure (caps, 0);
res = gst_structure_get_int (structure, "width", &video_width);
res &= gst_structure_get_int (structure, "height", &video_height);
framerate = gst_structure_get_value (structure, "framerate");
res &= (framerate != NULL);
if (!res) {
goto beach;
}
osxvideosink->fps_n = gst_value_get_fraction_numerator (framerate);
osxvideosink->fps_d = gst_value_get_fraction_denominator (framerate);
GST_DEBUG_OBJECT (osxvideosink, "our format is: %dx%d video at %d/%d fps",
video_width, video_height, osxvideosink->fps_n, osxvideosink->fps_d);
GST_VIDEO_SINK_WIDTH (osxvideosink) = video_width;
GST_VIDEO_SINK_HEIGHT (osxvideosink) = video_height;
gst_osx_video_sink_osxwindow_resize (osxvideosink, osxvideosink->osxwindow,
video_width, video_height);
result = TRUE;
beach:
return result;
}
static GstStateChangeReturn
gst_osx_video_sink_change_state (GstElement * element,
GstStateChange transition)
{
GstOSXVideoSink *osxvideosink;
osxvideosink = GST_OSX_VIDEO_SINK (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
/* Creating our window and our image */
if (!osxvideosink->osxwindow) {
GST_VIDEO_SINK_WIDTH (osxvideosink) = 320;
GST_VIDEO_SINK_HEIGHT (osxvideosink) = 240;
osxvideosink->osxwindow =
gst_osx_video_sink_osxwindow_new (osxvideosink,
GST_VIDEO_SINK_WIDTH (osxvideosink),
GST_VIDEO_SINK_HEIGHT (osxvideosink));
gst_osx_video_sink_osxwindow_clear (osxvideosink,
osxvideosink->osxwindow);
} else {
if (osxvideosink->osxwindow->internal)
gst_osx_video_sink_osxwindow_resize (osxvideosink,
osxvideosink->osxwindow, GST_VIDEO_SINK_WIDTH (osxvideosink),
GST_VIDEO_SINK_HEIGHT (osxvideosink));
}
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
GST_DEBUG ("ready to paused");
if (osxvideosink->osxwindow)
gst_osx_video_sink_osxwindow_clear (osxvideosink,
osxvideosink->osxwindow);
osxvideosink->time = 0;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
osxvideosink->fps_n = 0;
osxvideosink->fps_d = 0;
osxvideosink->sw_scaling_failed = FALSE;
GST_VIDEO_SINK_WIDTH (osxvideosink) = 0;
GST_VIDEO_SINK_HEIGHT (osxvideosink) = 0;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
if (osxvideosink->osxwindow) {
gst_osx_video_sink_osxwindow_destroy (osxvideosink,
osxvideosink->osxwindow);
osxvideosink->osxwindow = NULL;
}
break;
}
return (GST_ELEMENT_CLASS (parent_class))->change_state (element, transition);
}
static GstFlowReturn
gst_osx_video_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
{
GstOSXVideoSink *osxvideosink;
osxvideosink = GST_OSX_VIDEO_SINK (bsink);
char *viewdata =[osxvideosink->osxwindow->gstview getTextureBuffer];
GST_DEBUG ("show_frame");
memcpy (viewdata, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
[osxvideosink->osxwindow->gstview displayTexture];
return GST_FLOW_OK;
}
/* Buffer management */
/* =========================================== */
/* */
/* Init & Class init */
/* */
/* =========================================== */
static void
gst_osx_video_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstOSXVideoSink *osxvideosink;
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (object));
osxvideosink = GST_OSX_VIDEO_SINK (object);
switch (prop_id) {
case ARG_EMBED:
osxvideosink->embed = g_value_get_boolean (value);
break;
case ARG_FULLSCREEN:
osxvideosink->fullscreen = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_osx_video_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstOSXVideoSink *osxvideosink;
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (object));
osxvideosink = GST_OSX_VIDEO_SINK (object);
switch (prop_id) {
case ARG_EMBED:
g_value_set_boolean (value, osxvideosink->embed);
break;
case ARG_FULLSCREEN:
g_value_set_boolean (value, osxvideosink->fullscreen);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_osx_video_sink_dispose (GObject * object)
{
GstOSXVideoSink *osxvideosink;
osxvideosink = GST_OSX_VIDEO_SINK (object);
g_mutex_free (osxvideosink->pool_lock);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_osx_video_sink_init (GstOSXVideoSink * osxvideosink)
{
osxvideosink->osxwindow = NULL;
osxvideosink->fps_n = 0;
osxvideosink->fps_d = 0;
osxvideosink->pixel_width = osxvideosink->pixel_height = 1;
osxvideosink->sw_scaling_failed = FALSE;
osxvideosink->embed = FALSE;
osxvideosink->fullscreen = FALSE;
}
static void
gst_osx_video_sink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (element_class, &gst_osx_video_sink_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_osx_video_sink_sink_template_factory));
}
static void
gst_osx_video_sink_class_init (GstOSXVideoSinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
parent_class = g_type_class_ref (GST_TYPE_VIDEO_SINK);
gobject_class->dispose = gst_osx_video_sink_dispose;
gobject_class->set_property = gst_osx_video_sink_set_property;
gobject_class->get_property = gst_osx_video_sink_get_property;
//gstbasesink_class->get_times = gst_osx_video_sink_get_times;
gstbasesink_class->set_caps = gst_osx_video_sink_setcaps;
gstbasesink_class->preroll = gst_osx_video_sink_show_frame;
gstbasesink_class->render = gst_osx_video_sink_show_frame;
gstelement_class->change_state = gst_osx_video_sink_change_state;
g_object_class_install_property (gobject_class, ARG_EMBED,
g_param_spec_boolean ("embed", "embed", "When enabled, it "
"can be embedded", FALSE, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_FULLSCREEN,
g_param_spec_boolean ("fullscreen", "fullscreen",
"When enabled, the view " "is fullscreen", FALSE,
G_PARAM_READWRITE));
}
/* ============================================================= */
/* */
/* Public Methods */
/* */
/* ============================================================= */
/* =========================================== */
/* */
/* Object typing & Creation */
/* */
/* =========================================== */
GType
gst_osx_video_sink_get_type (void)
{
static GType osxvideosink_type = 0;
if (!osxvideosink_type) {
static const GTypeInfo osxvideosink_info = {
sizeof (GstOSXVideoSinkClass),
gst_osx_video_sink_base_init,
NULL,
(GClassInitFunc) gst_osx_video_sink_class_init,
NULL,
NULL,
sizeof (GstOSXVideoSink),
0,
(GInstanceInitFunc) gst_osx_video_sink_init,
};
osxvideosink_type = g_type_register_static (GST_TYPE_VIDEO_SINK,
"GstOSXVideoSink", &osxvideosink_info, 0);
}
return osxvideosink_type;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "osxvideosink",
GST_RANK_PRIMARY, GST_TYPE_OSX_VIDEO_SINK))
return FALSE;
GST_DEBUG_CATEGORY_INIT (gst_debug_osx_video_sink, "osxvideosink", 0,
"osxvideosink element");
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"osxvideo",
"OSX native video output plugin",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)