• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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