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#include <Cocoa/Cocoa.h> 22#include <gst/gst.h> 23#include <gst/video/videooverlay.h> 24 25#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 26#define NSEventMaskAny NSAnyEventMask 27#define NSWindowStyleMaskTitled NSTitledWindowMask 28#define NSWindowStyleMaskClosable NSClosableWindowMask 29#define NSWindowStyleMaskResizable NSResizableWindowMask 30#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask 31#endif 32 33/* ============================================================= */ 34/* */ 35/* MainWindow */ 36/* */ 37/* ============================================================= */ 38 39@interface MainWindow: NSWindow <NSApplicationDelegate> { 40 GMainLoop *m_loop; 41 GstElement *m_pipeline; 42 gboolean m_isClosed; 43} 44- (id) initWithContentRect:(NSRect) contentRect Loop:(GMainLoop*)loop Pipeline:(GstElement*)pipeline; 45- (GMainLoop*) loop; 46- (GstElement*) pipeline; 47- (gboolean) isClosed; 48@end 49 50@implementation MainWindow 51 52- (id) initWithContentRect:(NSRect)contentRect Loop:(GMainLoop*)loop Pipeline:(GstElement*)pipeline 53{ 54 m_loop = loop; 55 m_pipeline = pipeline; 56 m_isClosed = FALSE; 57 58 self = [super initWithContentRect: contentRect 59 styleMask: (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | 60 NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable) 61 backing: NSBackingStoreBuffered defer: NO screen: nil]; 62 63 [self setReleasedWhenClosed:NO]; 64 [[NSApplication sharedApplication] setDelegate:self]; 65 66 [self setTitle:@"gst-plugins-gl implements videooverlay interface"]; 67 68 return self; 69} 70 71- (GMainLoop*) loop { 72 return m_loop; 73} 74 75- (GstElement*) pipeline { 76 return m_pipeline; 77} 78 79- (gboolean) isClosed { 80 return m_isClosed; 81} 82 83- (void) customClose { 84 m_isClosed = TRUE; 85} 86 87- (BOOL) windowShouldClose:(id)sender { 88 gst_element_send_event (m_pipeline, gst_event_new_eos ()); 89 return YES; 90} 91 92- (void) applicationDidFinishLaunching: (NSNotification *) not { 93 [self makeMainWindow]; 94 [self center]; 95 [self orderFront:self]; 96} 97 98- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app { 99 return NO; 100} 101 102@end 103 104 105/* ============================================================= */ 106/* */ 107/* gstreamer callbacks */ 108/* */ 109/* ============================================================= */ 110 111 112static GstBusSyncReply create_window (GstBus* bus, GstMessage* message, MainWindow* window) 113{ 114 // ignore anything but 'prepare-window-handle' element messages 115 if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) 116 return GST_BUS_PASS; 117 118 if (!gst_is_video_overlay_prepare_window_handle_message (message)) 119 return GST_BUS_PASS; 120 121 g_print ("setting window handle %lud\n", (gulong) window); 122 123 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message)), (guintptr) [window contentView]); 124 125 gst_message_unref (message); 126 127 return GST_BUS_DROP; 128} 129 130 131static void end_stream_cb(GstBus* bus, GstMessage* message, MainWindow* window) 132{ 133 g_print ("end of stream\n"); 134 135 gst_element_set_state ([window pipeline], GST_STATE_NULL); 136 gst_object_unref ([window pipeline]); 137 g_main_loop_quit ([window loop]); 138 139 [window performSelectorOnMainThread:@selector(customClose) withObject:nil waitUntilDone:YES]; 140} 141 142static gpointer thread_func (MainWindow* window) 143{ 144 g_main_loop_run ([window loop]); 145 146 return NULL; 147} 148 149 150/* ============================================================= */ 151/* */ 152/* application */ 153/* */ 154/* ============================================================= */ 155 156int main(int argc, char **argv) 157{ 158 int width = 640; 159 int height = 480; 160 161 GMainLoop *loop = NULL; 162 GstElement *pipeline = NULL; 163 164 GstElement *videosrc = NULL; 165 GstElement *videosink = NULL; 166 GstCaps *caps=NULL; 167 gboolean ok=FALSE; 168 GstBus *bus=NULL; 169 GThread *loop_thread=NULL; 170 NSRect rect; 171 MainWindow *window=nil; 172 173 [NSApplication sharedApplication]; 174 175 g_print("app created\n"); 176 177 gst_init (&argc, &argv); 178 179 loop = g_main_loop_new (NULL, FALSE); 180 pipeline = gst_pipeline_new ("pipeline"); 181 182 videosrc = gst_element_factory_make ("videotestsrc", "videotestsrc"); 183 videosink = gst_element_factory_make ("glimagesink", "glimagesink"); 184 185 g_object_set(G_OBJECT(videosrc), "num-buffers", 500, NULL); 186 187 gst_bin_add_many (GST_BIN (pipeline), videosrc, videosink, NULL); 188 189 caps = gst_caps_new_simple("video/x-raw", 190 "width", G_TYPE_INT, width, 191 "height", G_TYPE_INT, height, 192 "framerate", GST_TYPE_FRACTION, 25, 1, 193 "format", G_TYPE_STRING, "I420", 194 NULL); 195 196 ok = gst_element_link_filtered(videosrc, videosink, caps); 197 gst_caps_unref(caps); 198 if (!ok) 199 g_warning("could not link videosrc to videosink\n"); 200 201 rect.origin.x = 0; rect.origin.y = 0; 202 rect.size.width = width; rect.size.height = height; 203 204 window = [[MainWindow alloc] initWithContentRect:rect Loop:loop Pipeline:pipeline]; 205 206 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); 207 gst_bus_add_signal_watch (bus); 208 /* NOTE: window is not bridge_retained because its lifetime is just this function */ 209 g_signal_connect(bus, "message::error", G_CALLBACK(end_stream_cb), (__bridge gpointer)window); 210 g_signal_connect(bus, "message::warning", G_CALLBACK(end_stream_cb), (__bridge gpointer)window); 211 g_signal_connect(bus, "message::eos", G_CALLBACK(end_stream_cb), (__bridge gpointer)window); 212 gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, (__bridge gpointer)window, NULL); 213 gst_object_unref (bus); 214 215 loop_thread = g_thread_new (NULL, 216 (GThreadFunc) thread_func, (__bridge gpointer)window); 217 218 gst_element_set_state (pipeline, GST_STATE_PLAYING); 219 220 [window orderFront:window]; 221 222 while (![window isClosed]) { 223 NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny 224 untilDate:[NSDate dateWithTimeIntervalSinceNow:1] 225 inMode:NSDefaultRunLoopMode dequeue:YES]; 226 if (event) 227 [NSApp sendEvent:event]; 228 } 229 230 g_thread_join (loop_thread); 231 232 return 0; 233} 234