1/* 2 * GStreamer 3 * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public 16 * License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21#if !defined(MAC_OS_X_VERSION_MAX_ALLOWED) || MAC_OS_X_VERSION_MAX_ALLOWED >= 1014 22# define GL_SILENCE_DEPRECATION 23#endif 24 25#include <Cocoa/Cocoa.h> 26#include <gst/gst.h> 27#include <gst/video/videooverlay.h> 28 29#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 30#define NSEventMaskAny NSAnyEventMask 31#define NSWindowStyleMaskTitled NSTitledWindowMask 32#define NSWindowStyleMaskClosable NSClosableWindowMask 33#define NSWindowStyleMaskResizable NSResizableWindowMask 34#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask 35#endif 36 37/* ============================================================= */ 38/* */ 39/* MainWindow */ 40/* */ 41/* ============================================================= */ 42 43@interface MainWindow: NSWindow <NSApplicationDelegate> { 44 GMainLoop *m_loop; 45 GstElement *m_pipeline; 46 gboolean m_isClosed; 47} 48- (id) initWithContentRect:(NSRect) contentRect Loop:(GMainLoop*)loop Pipeline:(GstElement*)pipeline; 49- (GMainLoop*) loop; 50- (GstElement*) pipeline; 51- (gboolean) isClosed; 52@end 53 54@implementation MainWindow 55 56- (id) initWithContentRect:(NSRect)contentRect Loop:(GMainLoop*)loop Pipeline:(GstElement*)pipeline 57{ 58 m_loop = loop; 59 m_pipeline = pipeline; 60 m_isClosed = FALSE; 61 62 self = [super initWithContentRect: contentRect 63 styleMask: (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | 64 NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable) 65 backing: NSBackingStoreBuffered defer: NO screen: nil]; 66 67 [self setReleasedWhenClosed:NO]; 68 [[NSApplication sharedApplication] setDelegate:self]; 69 70 [self setTitle:@"gst-plugins-gl implements videooverlay interface"]; 71 72 return self; 73} 74 75- (GMainLoop*) loop { 76 return m_loop; 77} 78 79- (GstElement*) pipeline { 80 return m_pipeline; 81} 82 83- (gboolean) isClosed { 84 return m_isClosed; 85} 86 87- (void) customClose { 88 m_isClosed = TRUE; 89} 90 91- (BOOL) windowShouldClose:(id)sender { 92 gst_element_send_event (m_pipeline, gst_event_new_eos ()); 93 return YES; 94} 95 96- (void) applicationDidFinishLaunching: (NSNotification *) not { 97 [self makeMainWindow]; 98 [self center]; 99 [self orderFront:self]; 100} 101 102- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app { 103 return NO; 104} 105 106@end 107 108 109/* ============================================================= */ 110/* */ 111/* gstreamer callbacks */ 112/* */ 113/* ============================================================= */ 114 115 116static GstBusSyncReply create_window (GstBus* bus, GstMessage* message, MainWindow* window) 117{ 118 // ignore anything but 'prepare-window-handle' element messages 119 if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) 120 return GST_BUS_PASS; 121 122 if (!gst_is_video_overlay_prepare_window_handle_message (message)) 123 return GST_BUS_PASS; 124 125 g_print ("setting window handle %lud\n", (gulong) window); 126 127 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message)), (guintptr) [window contentView]); 128 129 gst_message_unref (message); 130 131 return GST_BUS_DROP; 132} 133 134 135static void end_stream_cb(GstBus* bus, GstMessage* message, MainWindow* window) 136{ 137 g_print ("end of stream\n"); 138 139 gst_element_set_state ([window pipeline], GST_STATE_NULL); 140 gst_object_unref ([window pipeline]); 141 g_main_loop_quit ([window loop]); 142 143 [window performSelectorOnMainThread:@selector(customClose) withObject:nil waitUntilDone:YES]; 144} 145 146static gpointer thread_func (MainWindow* window) 147{ 148 g_main_loop_run ([window loop]); 149 150 return NULL; 151} 152 153 154/* ============================================================= */ 155/* */ 156/* application */ 157/* */ 158/* ============================================================= */ 159 160int main(int argc, char **argv) 161{ 162 int width = 640; 163 int height = 480; 164 165 GMainLoop *loop = NULL; 166 GstElement *pipeline = NULL; 167 168 GstElement *videosrc = NULL; 169 GstElement *videosink = NULL; 170 GstCaps *caps=NULL; 171 gboolean ok=FALSE; 172 GstBus *bus=NULL; 173 GThread *loop_thread=NULL; 174 NSRect rect; 175 MainWindow *window=nil; 176 177 [NSApplication sharedApplication]; 178 179 g_print("app created\n"); 180 181 gst_init (&argc, &argv); 182 183 loop = g_main_loop_new (NULL, FALSE); 184 pipeline = gst_pipeline_new ("pipeline"); 185 186 videosrc = gst_element_factory_make ("videotestsrc", "videotestsrc"); 187 videosink = gst_element_factory_make ("glimagesink", "glimagesink"); 188 189 g_object_set(G_OBJECT(videosrc), "num-buffers", 500, NULL); 190 191 gst_bin_add_many (GST_BIN (pipeline), videosrc, videosink, NULL); 192 193 caps = gst_caps_new_simple("video/x-raw", 194 "width", G_TYPE_INT, width, 195 "height", G_TYPE_INT, height, 196 "framerate", GST_TYPE_FRACTION, 25, 1, 197 "format", G_TYPE_STRING, "I420", 198 NULL); 199 200 ok = gst_element_link_filtered(videosrc, videosink, caps); 201 gst_caps_unref(caps); 202 if (!ok) 203 g_warning("could not link videosrc to videosink\n"); 204 205 rect.origin.x = 0; rect.origin.y = 0; 206 rect.size.width = width; rect.size.height = height; 207 208 window = [[MainWindow alloc] initWithContentRect:rect Loop:loop Pipeline:pipeline]; 209 210 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); 211 gst_bus_add_signal_watch (bus); 212 /* NOTE: window is not bridge_retained because its lifetime is just this function */ 213 g_signal_connect(bus, "message::error", G_CALLBACK(end_stream_cb), (__bridge gpointer)window); 214 g_signal_connect(bus, "message::warning", G_CALLBACK(end_stream_cb), (__bridge gpointer)window); 215 g_signal_connect(bus, "message::eos", G_CALLBACK(end_stream_cb), (__bridge gpointer)window); 216 gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, (__bridge gpointer)window, NULL); 217 gst_object_unref (bus); 218 219 loop_thread = g_thread_new (NULL, 220 (GThreadFunc) thread_func, (__bridge gpointer)window); 221 222 gst_element_set_state (pipeline, GST_STATE_PLAYING); 223 224 [window orderFront:window]; 225 226 while (![window isClosed]) { 227 NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny 228 untilDate:[NSDate dateWithTimeIntervalSinceNow:1] 229 inMode:NSDefaultRunLoopMode dequeue:YES]; 230 if (event) 231 [NSApp sendEvent:event]; 232 } 233 234 g_thread_join (loop_thread); 235 236 return 0; 237} 238