tizen 2.0 init
[framework/multimedia/gst-plugins-good0.10.git] / sys / osxvideo / cocoawindow.m
1 /* GStreamer
2  * Copyright (C) 2004 Zaheer Abbas Merali <zaheerabbas at merali dot org>
3  * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  * 
20  * The development of this code was made possible due to the involvement of Pioneers 
21  * of the Inevitable, the creators of the Songbird Music player
22  *
23  */
24
25 /* inspiration gained from looking at source of osx video out of xine and vlc
26  * and is reflected in the code
27  */
28
29
30 #include <Cocoa/Cocoa.h>
31 #include <gst/gst.h>
32 #import "cocoawindow.h"
33 #import "osxvideosink.h"
34
35 #include <OpenGL/OpenGL.h>
36 #include <OpenGL/gl.h>
37 #include <OpenGL/glext.h>
38
39 /* Debugging category */
40 #include <gst/gstinfo.h>
41
42 @ implementation GstOSXVideoSinkWindow
43
44 /* The object has to be released */
45 - (id) initWithContentRect: (NSRect) rect
46                  styleMask: (unsigned int) styleMask
47                    backing: (NSBackingStoreType) bufferingType 
48                      defer: (BOOL) flag
49                     screen:(NSScreen *) aScreen
50 {
51   self = [super initWithContentRect: rect
52                 styleMask: styleMask
53                 backing: bufferingType 
54                 defer: flag 
55                 screen:aScreen];
56
57   GST_DEBUG ("Initializing GstOSXvideoSinkWindow");
58
59   gstview = [[GstGLView alloc] initWithFrame:rect];
60   
61   if (gstview)
62     [self setContentView:gstview];
63   [self setTitle:@"GStreamer Video Output"];
64
65   return self;
66 }
67
68 - (void) setContentSize:(NSSize) size {
69   width = size.width;
70   height = size.height;
71
72   [gstview setVideoSize: (int) width:(int) height];
73
74   [super setContentSize:size];
75 }
76
77 - (GstGLView *) gstView {
78   return gstview;
79 }
80
81 - (void) awakeFromNib {
82   [self setAcceptsMouseMovedEvents:YES];
83 }
84
85 - (void) sendEvent:(NSEvent *) event {
86   BOOL taken = NO;
87
88   GST_DEBUG ("event %p type:%d", event,(gint)[event type]);
89
90   if ([event type] == NSKeyDown) {
91   }
92   /*taken = [gstview keyDown:event]; */
93
94   if (!taken) {
95     [super sendEvent:event];
96   }
97 }
98
99
100 @end
101
102
103 //
104 // OpenGL implementation
105 //
106
107 @ implementation GstGLView
108
109 - (id) initWithFrame:(NSRect) frame {
110   NSOpenGLPixelFormat *fmt;
111   NSOpenGLPixelFormatAttribute attribs[] = {
112     NSOpenGLPFAAccelerated,
113     NSOpenGLPFANoRecovery,
114     NSOpenGLPFADoubleBuffer,
115     NSOpenGLPFAColorSize, 24,
116     NSOpenGLPFAAlphaSize, 8,
117     NSOpenGLPFADepthSize, 24,
118     NSOpenGLPFAWindow,
119     0
120   };
121
122   fmt = [[NSOpenGLPixelFormat alloc]
123           initWithAttributes:attribs];
124
125   if (!fmt) {
126     GST_WARNING ("Cannot create NSOpenGLPixelFormat");
127     return nil;
128   }
129
130   self = [super initWithFrame: frame pixelFormat:fmt];
131   [fmt release];
132
133    actualContext = [self openGLContext];
134    [actualContext makeCurrentContext];
135    [actualContext update];
136
137   /* Black background */
138   glClearColor (0.0, 0.0, 0.0, 0.0);
139
140   pi_texture = 0;
141   data = nil;
142   width = frame.size.width;
143   height = frame.size.height;
144
145   GST_LOG ("Width: %d Height: %d", width, height);
146
147   [self initTextures];
148   return self;
149 }
150
151 - (void) reshape {
152   NSRect bounds;
153
154   GST_LOG ("reshaping");
155
156   if (!initDone) {
157     return;
158   }
159
160   [actualContext makeCurrentContext];
161
162   bounds = [self bounds];
163
164   glViewport (0, 0, (GLint) bounds.size.width, (GLint) bounds.size.height);
165
166 }
167
168 - (void) initTextures {
169
170   [actualContext makeCurrentContext];
171
172   /* Free previous texture if any */
173   if (pi_texture) {
174     glDeleteTextures (1, (GLuint *)&pi_texture);
175   }
176
177   if (data) {
178     data = g_realloc (data, width * height * sizeof(short)); // short or 3byte?
179   } else {
180     data = g_malloc0(width * height * sizeof(short));
181   }
182   /* Create textures */
183   glGenTextures (1, (GLuint *)&pi_texture);
184
185   glEnable (GL_TEXTURE_RECTANGLE_EXT);
186   glEnable (GL_UNPACK_CLIENT_STORAGE_APPLE);
187
188   glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
189   glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
190   
191   glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
192
193   /* Use VRAM texturing */
194   glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
195                    GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
196
197   /* Tell the driver not to make a copy of the texture but to use
198      our buffer */
199   glPixelStorei (GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
200
201   /* Linear interpolation */
202   glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
203   glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
204
205   /* I have no idea what this exactly does, but it seems to be
206      necessary for scaling */
207   glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
208                    GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
209   glTexParameteri (GL_TEXTURE_RECTANGLE_EXT,
210                    GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
211   // glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); WHY ??
212
213   glTexImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,
214                 width, height, 0, 
215                 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data);
216
217
218   initDone = 1;
219 }
220
221 - (void) reloadTexture {
222   if (!initDone) {
223     return;
224   }
225
226   GST_LOG ("Reloading Texture");
227
228   [actualContext makeCurrentContext];
229
230   glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture);
231   glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
232
233   /* glTexSubImage2D is faster than glTexImage2D
234      http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/
235      TextureRange/MainOpenGLView.m.htm */
236   glTexSubImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0,
237                    width, height,
238                    GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data);    //FIXME
239 }
240
241 - (void) cleanUp {
242   initDone = 0;
243 }
244
245 - (void) drawQuad {
246   f_x = 1.0;
247   f_y = 1.0;
248
249   glBegin (GL_QUADS);
250   /* Top left */
251   glTexCoord2f (0.0, 0.0);
252   glVertex2f (-f_x, f_y);
253   /* Bottom left */
254   glTexCoord2f (0.0, (float) height);
255   glVertex2f (-f_x, -f_y);
256   /* Bottom right */
257   glTexCoord2f ((float) width, (float) height);
258   glVertex2f (f_x, -f_y);
259   /* Top right */
260   glTexCoord2f ((float) width, 0.0);
261   glVertex2f (f_x, f_y);
262   glEnd ();
263 }
264
265 - (void) drawRect:(NSRect) rect {
266   GLint params[] = { 1 };
267
268   [actualContext makeCurrentContext];
269
270   CGLSetParameter (CGLGetCurrentContext (), kCGLCPSwapInterval, params);
271
272   /* Black background */
273   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
274
275   if (!initDone) {
276     [actualContext flushBuffer];
277     return;
278   }
279
280   /* Draw */
281   glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); // FIXME
282   [self drawQuad];
283   /* Draw */
284   [actualContext flushBuffer];
285 }
286
287 - (void) displayTexture {
288   if ([self lockFocusIfCanDraw]) {
289
290     [self drawRect:[self bounds]];
291     [self reloadTexture];
292
293     [self unlockFocus];
294
295   }
296
297 }
298
299 - (char *) getTextureBuffer {
300   return data;
301 }
302
303 - (void) setFullScreen:(BOOL) flag {
304   if (!fullscreen && flag) {
305     // go to full screen
306     /* Create the new pixel format */
307     NSOpenGLPixelFormat *fmt;
308     NSOpenGLPixelFormatAttribute attribs[] = {
309       NSOpenGLPFAAccelerated,
310       NSOpenGLPFANoRecovery,
311       NSOpenGLPFADoubleBuffer,
312       NSOpenGLPFAColorSize, 24,
313       NSOpenGLPFAAlphaSize, 8,
314       NSOpenGLPFADepthSize, 24,
315       NSOpenGLPFAFullScreen,
316       NSOpenGLPFAScreenMask,
317       CGDisplayIDToOpenGLDisplayMask (kCGDirectMainDisplay),
318       0
319     };
320
321     fmt = [[NSOpenGLPixelFormat alloc]
322             initWithAttributes:attribs];
323
324     if (!fmt) {
325       GST_WARNING ("Cannot create NSOpenGLPixelFormat");
326       return;
327     }
328
329     /* Create the new OpenGL context */
330     fullScreenContext = [[NSOpenGLContext alloc]
331                           initWithFormat: fmt shareContext:nil];
332     if (!fullScreenContext) {
333       GST_WARNING ("Failed to create new NSOpenGLContext");
334       return;
335     }
336
337     actualContext = fullScreenContext;
338
339     /* Capture display, switch to fullscreen */
340     if (CGCaptureAllDisplays () != CGDisplayNoErr) {
341       GST_WARNING ("CGCaptureAllDisplays() failed");
342       return;
343     }
344     [fullScreenContext setFullScreen];
345     [fullScreenContext makeCurrentContext];
346
347     fullscreen = YES;
348
349     [self initTextures];
350     [self setNeedsDisplay:YES];
351
352   } else if (fullscreen && !flag) {
353     // fullscreen now and needs to go back to normal
354     initDone = NO;
355     
356     actualContext = [self openGLContext];
357
358     [NSOpenGLContext clearCurrentContext];
359     [fullScreenContext clearDrawable];
360     [fullScreenContext release];
361     fullScreenContext = nil;
362
363     CGReleaseAllDisplays ();
364
365     [self reshape];
366     [self initTextures];
367
368     [self setNeedsDisplay:YES];
369
370     fullscreen = NO;
371     initDone = YES;
372   }
373 }
374
375 - (void) setVideoSize: (int) w:(int) h {
376   GST_LOG ("width:%d, height:%d", w, h);
377
378   width = w;
379   height = h;
380
381 //  if (data) g_free(data);
382
383 //  data = g_malloc0 (2 * w * h);
384   [self initTextures];
385 }
386
387 - (void) haveSuperviewReal:(NSMutableArray *)closure {
388         BOOL haveSuperview = [self superview] != nil;
389         [closure addObject:[NSNumber numberWithBool:haveSuperview]];
390 }
391
392 - (BOOL) haveSuperview {
393         NSMutableArray *closure = [NSMutableArray arrayWithCapacity:1];
394         [self performSelectorOnMainThread:@selector(haveSuperviewReal:)
395                         withObject:(id)closure waitUntilDone:YES];
396
397         return [[closure objectAtIndex:0] boolValue];
398 }
399
400 - (void) addToSuperviewReal:(NSView *)superview {
401         NSRect bounds;
402         [superview addSubview:self];
403         bounds = [superview bounds];
404         [self setFrame:bounds];
405         [self setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
406 }
407
408 - (void) addToSuperview: (NSView *)superview {
409         [self performSelectorOnMainThread:@selector(addToSuperviewReal:)
410                         withObject:superview waitUntilDone:YES];
411 }
412
413 - (void) removeFromSuperview: (id)unused
414 {
415         [self removeFromSuperview];
416 }
417
418 - (void) dealloc {
419   GST_LOG ("dealloc called");
420   if (data) g_free(data);
421
422   if (fullScreenContext) {
423     [NSOpenGLContext clearCurrentContext];
424     [fullScreenContext clearDrawable];
425     [fullScreenContext release];
426     if (actualContext == fullScreenContext) actualContext = nil;
427     fullScreenContext = nil;
428   }
429
430   [super dealloc];
431 }
432 @end