a72171eeda78196e5a7b539097aa2043b3f9eb1c
[platform/upstream/gst-plugins-good.git] / sys / osxvideo / osxvideosink.m
1 /* GStreamer
2  * OSX video sink
3  * Copyright (C) 2004-6 Zaheer Abbas Merali <zaheerabbas at merali dot org>
4  * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
5  * 
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * The development of this code was made possible due to the involvement of
22  * Pioneers of the Inevitable, the creators of the Songbird Music player.
23  * 
24  */
25
26 /**
27  * SECTION:element-osxvideosink
28  *
29  * <refsect2>
30  * <para>
31  * The OSXVideoSink renders video frames to a MacOSX window. The video output
32  * can be directed to a window embedded in an existing NSApp. This can be done
33  * by setting the "embed" property to #TRUE. When the NSView to be embedded is
34  * created an element #GstMessage with a name of 'have-ns-view' will be created
35  * and posted on the bus. The pointer to the NSView to embed will be in the
36  * 'nsview' field of that message. If no embedding is requested, the plugin will
37  * create a standalone window.
38  * </para>
39  * <title>Examples</title>
40  * <para>
41  * Simple timeline to test the sink :
42  * <programlisting>
43  * gst-launch-0.10 -v videotestsrc ! osxvideosink
44  * </programlisting>
45  * </para>
46  * </refsect2>
47  */
48
49 #include "config.h"
50
51 /* Object header */
52 #include "osxvideosink.h"
53 #include <unistd.h>
54 #import "cocoawindow.h"
55
56 /* Debugging category */
57 GST_DEBUG_CATEGORY (gst_debug_osx_video_sink);
58 #define GST_CAT_DEFAULT gst_debug_osx_video_sink
59
60 /* ElementFactory information */
61 static const GstElementDetails gst_osx_video_sink_details =
62 GST_ELEMENT_DETAILS ("OSX Video sink",
63     "Sink/Video",
64     "OSX native videosink",
65     "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
66
67 /* Default template - initiated with class struct to allow gst-register to work
68    without X running */
69 static GstStaticPadTemplate gst_osx_video_sink_sink_template_factory =
70 GST_STATIC_PAD_TEMPLATE ("sink",
71     GST_PAD_SINK,
72     GST_PAD_ALWAYS,
73     GST_STATIC_CAPS ("video/x-raw-yuv, "
74         "framerate = (fraction) [ 0, MAX ], "
75         "width = (int) [ 1, MAX ], "
76         "height = (int) [ 1, MAX ], "
77 #if G_BYTE_ORDER == G_BIG_ENDIAN
78        "format = (fourcc) YUY2")
79 #else
80         "format = (fourcc) UYVY")
81 #endif
82     );
83
84 // much of the following cocoa NSApp code comes from libsdl and libcaca
85 @implementation NSApplication(Gst)
86 - (void)setRunning
87 {
88     _running = 1;
89 }
90 @end
91
92 @implementation GstAppDelegate : NSObject
93 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
94 {
95     // destroy stuff here!
96     GST_DEBUG("Kill me please!");
97     return NSTerminateNow;
98 }
99 @end
100
101
102 enum
103 {
104   ARG_0,
105   ARG_EMBED,
106   ARG_FULLSCREEN
107       /* FILL ME */
108 };
109
110 static GstVideoSinkClass *parent_class = NULL;
111
112
113 /* cocoa event loop - needed if not run in own app */
114 static void
115 cocoa_event_loop (GstOSXVideoSink * vsink)
116 {
117   NSAutoreleasePool *pool;
118
119   GST_DEBUG_OBJECT (vsink, "Entering event loop");
120   
121   pool = [[NSAutoreleasePool alloc] init];
122
123   while ([NSApp isRunning]) {
124     NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask
125                             untilDate:[NSDate distantPast]
126                             inMode:NSDefaultRunLoopMode dequeue:YES ];
127     if ( event == nil ) {
128       g_usleep (2000);
129       break;
130     } else {
131       switch ([event type]) {
132       default: //XXX Feed me please
133         [NSApp sendEvent:event];
134         break;
135       }
136       /* loop */
137     }
138   }
139
140   [pool release];
141 }
142
143 static NSString *
144 GetApplicationName(void)
145 {
146     NSDictionary *dict;
147     NSString *appName = 0;
148
149     /* Determine the application name */
150     dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
151     if (dict)
152         appName = [dict objectForKey: @"CFBundleName"];
153     
154     if (![appName length])
155         appName = [[NSProcessInfo processInfo] processName];
156
157     return appName;
158 }
159
160 static void
161 CreateApplicationMenus(void)
162 {
163     NSString *appName;
164     NSString *title;
165     NSMenu *appleMenu;
166     NSMenu *windowMenu;
167     NSMenuItem *menuItem;
168     
169     /* Create the main menu bar */
170     [NSApp setMainMenu:[[NSMenu alloc] init]];
171
172     /* Create the application menu */
173     appName = GetApplicationName();
174     appleMenu = [[NSMenu alloc] initWithTitle:@""];
175
176         /* Add menu items */
177     title = [@"About " stringByAppendingString:appName];
178     [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
179
180     [appleMenu addItem:[NSMenuItem separatorItem]];
181     
182     title = [@"Hide " stringByAppendingString:appName];
183     [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@/*"h"*/""];
184
185     menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@/*"h"*/""];
186     [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
187
188     [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
189
190     [appleMenu addItem:[NSMenuItem separatorItem]];
191
192     title = [@"Quit " stringByAppendingString:appName];
193     [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@/*"q"*/""];
194     
195     /* Put menu into the menubar */
196     menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
197     [menuItem setSubmenu:appleMenu];
198     [[NSApp mainMenu] addItem:menuItem];
199     [menuItem release];
200
201     /* Tell the application object that this is now the application menu */
202     [NSApp setAppleMenu:appleMenu];
203     [appleMenu release];
204
205
206     /* Create the window menu */
207     windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
208     
209     /* "Minimize" item */
210     menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@/*"m"*/""];
211     [windowMenu addItem:menuItem];
212     [menuItem release];
213     
214     /* Put menu into the menubar */
215     menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
216     [menuItem setSubmenu:windowMenu];
217     [[NSApp mainMenu] addItem:menuItem];
218     [menuItem release];
219     
220     /* Tell the application object that this is now the window menu */
221     [NSApp setWindowsMenu:windowMenu];
222     [windowMenu release];
223 }
224
225 /* This function handles osx window creation */
226 static GstOSXWindow *
227 gst_osx_video_sink_osxwindow_new (GstOSXVideoSink * osxvideosink, gint width,
228     gint height)
229 {
230   NSRect rect;
231   GstOSXWindow *osxwindow = NULL;
232
233   g_return_val_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink), NULL);
234
235   GST_DEBUG_OBJECT (osxvideosink, "Creating new OSX window");
236
237   osxwindow = g_new0 (GstOSXWindow, 1);
238
239   osxwindow->width = width;
240   osxwindow->height = height;
241   osxwindow->internal = TRUE;
242   osxwindow->pool = [[NSAutoreleasePool alloc] init];
243
244   if (osxvideosink->embed == FALSE) {
245     ProcessSerialNumber psn;
246     unsigned int mask =  NSTitledWindowMask             |
247                          NSClosableWindowMask           |
248                          NSResizableWindowMask          |
249                          NSTexturedBackgroundWindowMask |
250                          NSMiniaturizableWindowMask;
251
252     rect.origin.x = 100.0;
253     rect.origin.y = 100.0;
254     rect.size.width = (float) osxwindow->width;
255     rect.size.height = (float) osxwindow->height;
256
257     if (!GetCurrentProcess(&psn)) {
258         TransformProcessType(&psn, kProcessTransformToForegroundApplication);
259         SetFrontProcess(&psn);
260     }
261
262     [NSApplication sharedApplication];
263  
264     osxwindow->win =[[GstOSXVideoSinkWindow alloc]
265                          initWithContentRect: rect
266                          styleMask: mask
267                          backing: NSBackingStoreBuffered
268                          defer: NO
269                          screen: nil];
270     GST_DEBUG("VideoSinkWindow created, %p", osxwindow->win);
271     [osxwindow->win autorelease];
272     [NSApplication sharedApplication];
273     [osxwindow->win makeKeyAndOrderFront:NSApp];
274     osxwindow->gstview =[osxwindow->win gstView];
275     [osxwindow->gstview autorelease];
276     if (osxvideosink->fullscreen)
277       [osxwindow->gstview setFullScreen:YES];
278
279     CreateApplicationMenus();
280
281     [NSApp finishLaunching];
282     [NSApp setDelegate:[[GstAppDelegate alloc] init]];
283
284     [NSApp setRunning];
285     g_static_rec_mutex_init (&osxvideosink->event_task_lock);
286     osxvideosink->event_task = gst_task_create ((GstTaskFunction)cocoa_event_loop,
287                                                 osxvideosink);
288     gst_task_set_lock (osxvideosink->event_task, &osxvideosink->event_task_lock);
289     gst_task_start (osxvideosink->event_task);
290   } else {
291     GstStructure *s;
292     GstMessage *msg;
293     gchar * tmp;
294     /* Needs to be embedded */
295
296     rect.origin.x = 0.0;
297     rect.origin.y = 0.0;
298     rect.size.width = (float) osxwindow->width;
299     rect.size.height = (float) osxwindow->height;
300     osxwindow->gstview =[[GstGLView alloc] initWithFrame:rect];
301     [osxwindow->gstview autorelease];
302     
303     s = gst_structure_new ("have-ns-view",
304                            "nsview", G_TYPE_POINTER, osxwindow->gstview,
305                            nil);
306
307     tmp = gst_structure_to_string (s);
308     GST_DEBUG_OBJECT (osxvideosink, "Sending message %s (with view %p)",
309                       tmp, osxwindow->gstview);
310     g_free (tmp);
311
312     msg = gst_message_new_element (GST_OBJECT (osxvideosink), s);
313     gst_element_post_message (GST_ELEMENT (osxvideosink), msg);
314
315     GST_LOG_OBJECT (osxvideosink, "'have-ns-view' message sent");
316   }
317   return osxwindow;
318 }
319
320 /* This function destroys a GstXWindow */
321 static void
322 gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink,
323     GstOSXWindow * osxwindow)
324 {
325   g_return_if_fail (osxwindow != NULL);
326   g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
327
328   [osxwindow->pool release];
329
330   if (osxvideosink->event_task) {
331     gst_task_join (osxvideosink->event_task);
332     gst_object_unref (osxvideosink->event_task);
333     osxvideosink->event_task = NULL;
334     g_static_rec_mutex_free (&osxvideosink->event_task_lock);
335   }
336
337   g_free (osxwindow);
338 }
339
340 /* This function resizes a GstXWindow */
341 static void
342 gst_osx_video_sink_osxwindow_resize (GstOSXVideoSink * osxvideosink,
343     GstOSXWindow * osxwindow, guint width, guint height)
344 {
345   NSAutoreleasePool *subPool = [[NSAutoreleasePool alloc] init];
346   g_return_if_fail (osxwindow != NULL);
347   g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
348
349   osxwindow->width = width;
350   osxwindow->height = height;
351
352   GST_DEBUG_OBJECT (osxvideosink, "Resizing window to (%d,%d)", width, height);
353   if (osxwindow->win) {
354     /* Call relevant cocoa function to resize window */
355     NSSize size;
356     size.width = width;
357     size.height = height;
358
359     NSLog(@"osxwindow->win = %@", osxwindow->win);
360     GST_DEBUG_OBJECT (osxvideosink, "Calling setContentSize on %p", osxwindow->win); 
361     [osxwindow->win setContentSize:size];
362   }
363   else {
364     /* Directly resize the underlying view */
365     GST_DEBUG_OBJECT (osxvideosink, "Calling setVideoSize on %p", osxwindow->gstview); 
366     [osxwindow->gstview setVideoSize:width :height];
367   }
368   [subPool release];
369 }
370
371 static void
372 gst_osx_video_sink_osxwindow_clear (GstOSXVideoSink * osxvideosink,
373     GstOSXWindow * osxwindow)
374 {
375
376   g_return_if_fail (osxwindow != NULL);
377   g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
378
379 }
380
381
382 /* Element stuff */
383 static gboolean
384 gst_osx_video_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
385 {
386   GstOSXVideoSink *osxvideosink;
387   GstStructure *structure;
388   gboolean res, result = FALSE;
389   gint video_width, video_height;
390
391   osxvideosink = GST_OSX_VIDEO_SINK (bsink);
392
393   GST_DEBUG_OBJECT (osxvideosink, "caps: %" GST_PTR_FORMAT, caps);
394
395   structure = gst_caps_get_structure (caps, 0);
396   res = gst_structure_get_int (structure, "width", &video_width);
397   res &= gst_structure_get_int (structure, "height", &video_height);
398
399   if (!res) {
400     goto beach;
401   }
402
403   GST_DEBUG_OBJECT (osxvideosink, "our format is: %dx%d video",
404       video_width, video_height);
405
406   GST_VIDEO_SINK_WIDTH (osxvideosink) = video_width;
407   GST_VIDEO_SINK_HEIGHT (osxvideosink) = video_height;
408
409   gst_osx_video_sink_osxwindow_resize (osxvideosink, osxvideosink->osxwindow,
410       video_width, video_height);
411   result = TRUE;
412
413 beach:
414   return result;
415
416 }
417
418 static GstStateChangeReturn
419 gst_osx_video_sink_change_state (GstElement * element,
420     GstStateChange transition)
421 {
422   GstOSXVideoSink *osxvideosink;
423
424   osxvideosink = GST_OSX_VIDEO_SINK (element);
425
426   GST_DEBUG_OBJECT (osxvideosink, "%s => %s", 
427                     gst_element_state_get_name(GST_STATE_TRANSITION_CURRENT (transition)),
428                     gst_element_state_get_name(GST_STATE_TRANSITION_NEXT (transition)));
429
430   switch (transition) {
431     case GST_STATE_CHANGE_NULL_TO_READY:
432       /* Creating our window and our image */
433       if (!osxvideosink->osxwindow) {
434         GST_VIDEO_SINK_WIDTH (osxvideosink) = 320;
435         GST_VIDEO_SINK_HEIGHT (osxvideosink) = 240;
436         osxvideosink->osxwindow =
437             gst_osx_video_sink_osxwindow_new (osxvideosink,
438             GST_VIDEO_SINK_WIDTH (osxvideosink),
439             GST_VIDEO_SINK_HEIGHT (osxvideosink));
440         gst_osx_video_sink_osxwindow_clear (osxvideosink,
441             osxvideosink->osxwindow);
442       } else {
443         if (osxvideosink->osxwindow->internal)
444           gst_osx_video_sink_osxwindow_resize (osxvideosink,
445               osxvideosink->osxwindow, GST_VIDEO_SINK_WIDTH (osxvideosink),
446               GST_VIDEO_SINK_HEIGHT (osxvideosink));
447       }
448       break;
449     case GST_STATE_CHANGE_READY_TO_PAUSED:
450       GST_DEBUG ("ready to paused");
451       if (osxvideosink->osxwindow)
452         gst_osx_video_sink_osxwindow_clear (osxvideosink,
453             osxvideosink->osxwindow);
454       osxvideosink->time = 0;
455       break;
456     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
457       break;
458     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
459       break;
460     case GST_STATE_CHANGE_PAUSED_TO_READY:
461       osxvideosink->sw_scaling_failed = FALSE;
462       GST_VIDEO_SINK_WIDTH (osxvideosink) = 0;
463       GST_VIDEO_SINK_HEIGHT (osxvideosink) = 0;
464       break;
465     case GST_STATE_CHANGE_READY_TO_NULL:
466
467       if (osxvideosink->osxwindow) {
468         gst_osx_video_sink_osxwindow_destroy (osxvideosink,
469             osxvideosink->osxwindow);
470         osxvideosink->osxwindow = NULL;
471       }
472       break;
473   }
474
475   return (GST_ELEMENT_CLASS (parent_class))->change_state (element, transition);
476
477 }
478
479 static GstFlowReturn
480 gst_osx_video_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
481 {
482   GstOSXVideoSink *osxvideosink;
483   char *viewdata;
484
485   osxvideosink = GST_OSX_VIDEO_SINK (bsink);
486   viewdata = [osxvideosink->osxwindow->gstview getTextureBuffer];
487
488   GST_DEBUG ("show_frame");
489   memcpy (viewdata, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
490   [osxvideosink->osxwindow->gstview displayTexture];
491
492   return GST_FLOW_OK;
493 }
494
495 /* Buffer management */
496
497
498
499 /* =========================================== */
500 /*                                             */
501 /*              Init & Class init              */
502 /*                                             */
503 /* =========================================== */
504
505 static void
506 gst_osx_video_sink_set_property (GObject * object, guint prop_id,
507     const GValue * value, GParamSpec * pspec)
508 {
509   GstOSXVideoSink *osxvideosink;
510
511   g_return_if_fail (GST_IS_OSX_VIDEO_SINK (object));
512
513   osxvideosink = GST_OSX_VIDEO_SINK (object);
514
515   switch (prop_id) {
516     case ARG_EMBED:
517       osxvideosink->embed = g_value_get_boolean (value);
518       break;
519     case ARG_FULLSCREEN:
520       osxvideosink->fullscreen = g_value_get_boolean (value);
521       break;
522     default:
523       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
524       break;
525   }
526 }
527
528 static void
529 gst_osx_video_sink_get_property (GObject * object, guint prop_id,
530     GValue * value, GParamSpec * pspec)
531 {
532   GstOSXVideoSink *osxvideosink;
533
534   g_return_if_fail (GST_IS_OSX_VIDEO_SINK (object));
535
536   osxvideosink = GST_OSX_VIDEO_SINK (object);
537
538   switch (prop_id) {
539     case ARG_EMBED:
540       g_value_set_boolean (value, osxvideosink->embed);
541       break;
542     case ARG_FULLSCREEN:
543       g_value_set_boolean (value, osxvideosink->fullscreen);
544       break;
545     default:
546       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
547       break;
548   }
549 }
550
551 static void
552 gst_osx_video_sink_init (GstOSXVideoSink * osxvideosink)
553 {
554
555   osxvideosink->osxwindow = NULL;
556
557   osxvideosink->pixel_width = osxvideosink->pixel_height = 1;
558   osxvideosink->sw_scaling_failed = FALSE;
559   osxvideosink->embed = FALSE;
560   osxvideosink->fullscreen = FALSE;
561
562 }
563
564 static void
565 gst_osx_video_sink_base_init (gpointer g_class)
566 {
567   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
568
569   gst_element_class_set_details (element_class, &gst_osx_video_sink_details);
570
571   gst_element_class_add_pad_template (element_class,
572       gst_static_pad_template_get (&gst_osx_video_sink_sink_template_factory));
573 }
574
575 static void
576 gst_osx_video_sink_class_init (GstOSXVideoSinkClass * klass)
577 {
578   GObjectClass *gobject_class;
579   GstElementClass *gstelement_class;
580   GstBaseSinkClass *gstbasesink_class;
581
582   gobject_class = (GObjectClass *) klass;
583   gstelement_class = (GstElementClass *) klass;
584   gstbasesink_class = (GstBaseSinkClass *) klass;
585
586
587   parent_class = g_type_class_ref (GST_TYPE_VIDEO_SINK);
588
589   gobject_class->set_property = gst_osx_video_sink_set_property;
590   gobject_class->get_property = gst_osx_video_sink_get_property;
591
592   gstbasesink_class->set_caps = gst_osx_video_sink_setcaps;
593   gstbasesink_class->preroll = gst_osx_video_sink_show_frame;
594   gstbasesink_class->render = gst_osx_video_sink_show_frame;
595   gstelement_class->change_state = gst_osx_video_sink_change_state;
596
597   /**
598    * GstOSXVideoSink:embed
599    *
600    * Set to #TRUE if you are embedding the video window in an application.
601    *
602    **/
603
604   g_object_class_install_property (gobject_class, ARG_EMBED,
605       g_param_spec_boolean ("embed", "embed", "When enabled, it  "
606           "can be embedded", FALSE, G_PARAM_READWRITE));
607
608   /**
609    * GstOSXVideoSink:fullscreen
610    *
611    * Set to #TRUE to have the video displayed in fullscreen.
612    **/
613
614   g_object_class_install_property (gobject_class, ARG_FULLSCREEN,
615       g_param_spec_boolean ("fullscreen", "fullscreen",
616           "When enabled, the view  " "is fullscreen", FALSE,
617           G_PARAM_READWRITE));
618 }
619
620 /* ============================================================= */
621 /*                                                               */
622 /*                       Public Methods                          */
623 /*                                                               */
624 /* ============================================================= */
625
626 /* =========================================== */
627 /*                                             */
628 /*          Object typing & Creation           */
629 /*                                             */
630 /* =========================================== */
631
632 GType
633 gst_osx_video_sink_get_type (void)
634 {
635   static GType osxvideosink_type = 0;
636
637   if (!osxvideosink_type) {
638     static const GTypeInfo osxvideosink_info = {
639       sizeof (GstOSXVideoSinkClass),
640       gst_osx_video_sink_base_init,
641       NULL,
642       (GClassInitFunc) gst_osx_video_sink_class_init,
643       NULL,
644       NULL,
645       sizeof (GstOSXVideoSink),
646       0,
647       (GInstanceInitFunc) gst_osx_video_sink_init,
648     };
649
650     osxvideosink_type = g_type_register_static (GST_TYPE_VIDEO_SINK,
651         "GstOSXVideoSink", &osxvideosink_info, 0);
652
653   }
654
655   return osxvideosink_type;
656 }
657
658 static gboolean
659 plugin_init (GstPlugin * plugin)
660 {
661
662   if (!gst_element_register (plugin, "osxvideosink",
663           GST_RANK_PRIMARY, GST_TYPE_OSX_VIDEO_SINK))
664     return FALSE;
665
666   GST_DEBUG_CATEGORY_INIT (gst_debug_osx_video_sink, "osxvideosink", 0,
667       "osxvideosink element");
668
669   return TRUE;
670 }
671
672 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
673     GST_VERSION_MINOR,
674     "osxvideo",
675     "OSX native video output plugin",
676     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)