sync with ffmpeg
[mplayer/glamo.git] / libvo / vo_quartz.c
blob23b3e951a7eefa7a6447feabc76f91b30274afbe
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 /**
20 \author Nicolas Plourde <nicolasplourde@gmail.com>
22 Copyright (c) Nicolas Plourde - April 2004
24 YUV support Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
26 \brief MPlayer Mac OSX Quartz video out module.
28 \todo: -screen overlay output
29 -fit osd in black bar when available
30 -fix RGB32
31 -(add sugestion here)
34 //SYS
35 #include <stdio.h>
37 //OSX
38 #include <Carbon/Carbon.h>
39 #include <QuickTime/QuickTime.h>
41 //MPLAYER
42 #include "config.h"
43 #include "fastmemcpy.h"
44 #include "video_out.h"
45 #include "video_out_internal.h"
46 #include "aspect.h"
47 #include "mp_msg.h"
48 #include "m_option.h"
49 #include "mp_fifo.h"
50 #include "mpbswap.h"
51 #include "sub.h"
53 #include "input/input.h"
54 #include "input/mouse.h"
56 #include "vo_quartz.h"
58 static const vo_info_t info =
60 "Mac OSX (Quartz)",
61 "quartz",
62 "Nicolas Plourde <nicolasplourde@hotmail.com>, Romain Dolbeau <romain@dolbeau.org>",
66 const LIBVO_EXTERN(quartz)
68 static uint32_t image_depth;
69 static uint32_t image_format;
70 static uint32_t image_size;
71 static uint32_t image_buffer_size;
72 static char *image_data;
74 static ImageSequence seqId;
75 static CodecType image_qtcodec;
76 static PlanarPixmapInfoYUV420 *P = NULL;
77 static struct
79 ImageDescriptionHandle desc;
80 Handle extension_colr;
81 Handle extension_fiel;
82 Handle extension_clap;
83 Handle extension_pasp;
84 } yuv_qt_stuff;
85 static MatrixRecord matrix;
86 static int EnterMoviesDone = 0;
87 static int get_image_done = 0;
89 static int vo_quartz_fs; // we are in fullscreen
90 extern float monitor_aspect;
91 extern float movie_aspect;
92 static float old_movie_aspect;
94 static int winLevel = 1;
95 int levelList[] =
97 kCGDesktopWindowLevelKey,
98 kCGNormalWindowLevelKey,
99 kCGScreenSaverWindowLevelKey
102 static int int_pause = 0;
103 static float winAlpha = 1;
104 static int mouseHide = FALSE;
106 static int device_id = 0;
108 static short fs_res_x = 0;
109 static short fs_res_y = 0;
111 static WindowRef theWindow = NULL;
112 static WindowGroupRef winGroup = NULL;
113 static CGRect bounds;
114 static CGDirectDisplayID displayId = 0;
115 static CFDictionaryRef originalMode = NULL;
117 static CGDataProviderRef dataProviderRef = NULL;
118 static CGImageRef image = NULL;
120 static Rect imgRect; // size of the original image (unscaled)
121 static Rect dstRect; // size of the displayed image (after scaling)
122 static Rect winRect; // size of the window containg the displayed image (include padding)
123 static Rect oldWinRect; // size of the window containg the displayed image (include padding) when NOT in FS mode
124 static CGRect displayRect; // size of the display device
125 static Rect oldWinBounds;
127 static MenuRef windMenu;
128 static MenuRef movMenu;
129 static MenuRef aspectMenu;
131 static int lastScreensaverUpdate = 0;
132 static int lastMouseHide = 0;
134 enum
136 kQuitCmd = 1,
137 kHalfScreenCmd = 2,
138 kNormalScreenCmd = 3,
139 kDoubleScreenCmd = 4,
140 kFullScreenCmd = 5,
141 kKeepAspectCmd = 6,
142 kAspectOrgCmd = 7,
143 kAspectFullCmd = 8,
144 kAspectWideCmd = 9,
145 kPanScanCmd = 10
148 #include "osdep/keycodes.h"
150 //PROTOTYPE/////////////////////////////////////////////////////////////////
151 static OSStatus KeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
152 static OSStatus MouseEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
153 static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
154 void window_resized(void);
155 void window_ontop(void);
156 void window_fullscreen(void);
157 void window_panscan(void);
159 static inline int convert_key(UInt32 key, UInt32 charcode)
161 switch (key)
163 case QZ_IBOOK_ENTER:
164 case QZ_RETURN: return KEY_ENTER;
165 case QZ_ESCAPE: return KEY_ESC;
166 case QZ_BACKSPACE: return KEY_BACKSPACE;
167 case QZ_LALT: return KEY_BACKSPACE;
168 case QZ_LCTRL: return KEY_BACKSPACE;
169 case QZ_LSHIFT: return KEY_BACKSPACE;
170 case QZ_F1: return KEY_F + 1;
171 case QZ_F2: return KEY_F + 2;
172 case QZ_F3: return KEY_F + 3;
173 case QZ_F4: return KEY_F + 4;
174 case QZ_F5: return KEY_F + 5;
175 case QZ_F6: return KEY_F + 6;
176 case QZ_F7: return KEY_F + 7;
177 case QZ_F8: return KEY_F + 8;
178 case QZ_F9: return KEY_F + 9;
179 case QZ_F10: return KEY_F + 10;
180 case QZ_F11: return KEY_F + 11;
181 case QZ_F12: return KEY_F + 12;
182 case QZ_INSERT: return KEY_INSERT;
183 case QZ_DELETE: return KEY_DELETE;
184 case QZ_HOME: return KEY_HOME;
185 case QZ_END: return KEY_END;
186 case QZ_KP_PLUS: return '+';
187 case QZ_KP_MINUS: return '-';
188 case QZ_TAB: return KEY_TAB;
189 case QZ_PAGEUP: return KEY_PAGE_UP;
190 case QZ_PAGEDOWN: return KEY_PAGE_DOWN;
191 case QZ_UP: return KEY_UP;
192 case QZ_DOWN: return KEY_DOWN;
193 case QZ_LEFT: return KEY_LEFT;
194 case QZ_RIGHT: return KEY_RIGHT;
195 case QZ_KP_MULTIPLY: return '*';
196 case QZ_KP_DIVIDE: return '/';
197 case QZ_KP_ENTER: return KEY_KPENTER;
198 case QZ_KP_PERIOD: return KEY_KPDEC;
199 case QZ_KP0: return KEY_KP0;
200 case QZ_KP1: return KEY_KP1;
201 case QZ_KP2: return KEY_KP2;
202 case QZ_KP3: return KEY_KP3;
203 case QZ_KP4: return KEY_KP4;
204 case QZ_KP5: return KEY_KP5;
205 case QZ_KP6: return KEY_KP6;
206 case QZ_KP7: return KEY_KP7;
207 case QZ_KP8: return KEY_KP8;
208 case QZ_KP9: return KEY_KP9;
209 default: return charcode;
213 static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
215 switch (image_format)
217 case IMGFMT_RGB32:
218 vo_draw_alpha_rgb32(w, h, src, srca, stride, image_data + 4 * (y0 * imgRect.right + x0), 4 * imgRect.right);
219 break;
220 case IMGFMT_YV12:
221 case IMGFMT_IYUV:
222 case IMGFMT_I420:
223 vo_draw_alpha_yv12(w, h, src, srca, stride, ((char *)P) + be2me_32(P->componentInfoY.offset) + x0 + y0 * imgRect.right, imgRect.right);
224 break;
225 case IMGFMT_UYVY:
226 vo_draw_alpha_uyvy(w, h, src, srca, stride, ((char *)P) + (x0 + y0 * imgRect.right) * 2, imgRect.right * 2);
227 break;
228 case IMGFMT_YUY2:
229 vo_draw_alpha_yuy2(w, h, src, srca, stride, ((char *)P) + (x0 + y0 * imgRect.right) * 2, imgRect.right * 2);
230 break;
234 //default keyboard event handler
235 static OSStatus KeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
237 OSStatus result = noErr;
238 UInt32 class = GetEventClass(event);
239 UInt32 kind = GetEventKind(event);
241 result = CallNextEventHandler(nextHandler, event);
243 if (class == kEventClassKeyboard)
245 char macCharCodes;
246 UInt32 macKeyCode;
247 UInt32 macKeyModifiers;
249 GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(macCharCodes), NULL, &macCharCodes);
250 GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(macKeyCode), NULL, &macKeyCode);
251 GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(macKeyModifiers), NULL, &macKeyModifiers);
253 if (macKeyModifiers != 256)
255 if (kind == kEventRawKeyRepeat || kind == kEventRawKeyDown)
257 int key = convert_key(macKeyCode, macCharCodes);
259 if (key != -1)
260 mplayer_put_key(key);
263 else if (macKeyModifiers == 256)
265 switch (macCharCodes)
267 case '[': SetWindowAlpha(theWindow, winAlpha -= 0.05); break;
268 case ']': SetWindowAlpha(theWindow, winAlpha += 0.05); break;
271 else
272 result = eventNotHandledErr;
275 return result;
278 //default mouse event handler
279 static OSStatus MouseEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
281 OSStatus result = noErr;
282 UInt32 class = GetEventClass(event);
283 UInt32 kind = GetEventKind(event);
285 result = CallNextEventHandler(nextHandler, event);
287 if (class == kEventClassMouse)
289 WindowPtr tmpWin;
290 Point mousePos;
291 Point winMousePos;
293 GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(Point), 0, &mousePos);
294 GetEventParameter(event, kEventParamWindowMouseLocation, typeQDPoint, 0, sizeof(Point), 0, &winMousePos);
296 switch (kind)
298 case kEventMouseMoved:
300 if (vo_quartz_fs)
302 CGDisplayShowCursor(displayId);
303 mouseHide = FALSE;
306 break;
308 case kEventMouseWheelMoved:
310 int wheel;
311 short part;
313 GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0, sizeof(int), 0, &wheel);
315 part = FindWindow(mousePos, &tmpWin);
317 if (part == inContent)
319 if (wheel > 0)
320 mplayer_put_key(MOUSE_BTN3);
321 else
322 mplayer_put_key(MOUSE_BTN4);
325 break;
327 case kEventMouseDown:
328 case kEventMouseUp:
330 EventMouseButton button;
331 short part;
332 Rect bounds;
334 GetWindowPortBounds(theWindow, &bounds);
335 GetEventParameter(event, kEventParamMouseButton, typeMouseButton, 0, sizeof(EventMouseButton), 0, &button);
337 part = FindWindow(mousePos, &tmpWin);
338 if (kind == kEventMouseUp)
340 if (part != inContent)
341 break;
342 switch (button)
344 case kEventMouseButtonPrimary:
345 mplayer_put_key(MOUSE_BTN0);
346 break;
347 case kEventMouseButtonSecondary:
348 mplayer_put_key(MOUSE_BTN2);
349 break;
350 case kEventMouseButtonTertiary:
351 mplayer_put_key(MOUSE_BTN1);
352 break;
354 default:
355 result = eventNotHandledErr;
356 break;
358 break;
360 if ((winMousePos.h > (bounds.right - 15)) && (winMousePos.v > (bounds.bottom)))
362 if (!vo_quartz_fs)
364 Rect newSize;
366 ResizeWindow(theWindow, mousePos, NULL, &newSize);
369 else if (part == inMenuBar)
371 MenuSelect(mousePos);
372 HiliteMenu(0);
374 else if (part == inContent)
376 switch (button)
378 case kEventMouseButtonPrimary:
379 mplayer_put_key(MOUSE_BTN0 | MP_KEY_DOWN);
380 break;
381 case kEventMouseButtonSecondary:
382 mplayer_put_key(MOUSE_BTN2 | MP_KEY_DOWN);
383 break;
384 case kEventMouseButtonTertiary:
385 mplayer_put_key(MOUSE_BTN1 | MP_KEY_DOWN);
386 break;
388 default:
389 result = eventNotHandledErr;
390 break;
394 break;
396 case kEventMouseDragged:
397 break;
399 default:
400 result = eventNotHandledErr;
401 break;
405 return result;
408 //default window event handler
409 static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
411 OSStatus result = noErr;
412 uint32_t d_width;
413 uint32_t d_height;
414 UInt32 class = GetEventClass(event);
415 UInt32 kind = GetEventKind(event);
417 result = CallNextEventHandler(nextHandler, event);
419 aspect(&d_width, &d_height, A_NOZOOM);
421 if (class == kEventClassCommand)
423 HICommand theHICommand;
425 GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &theHICommand);
427 switch (theHICommand.commandID)
429 case kHICommandQuit:
430 mplayer_put_key(KEY_CLOSE_WIN);
431 break;
433 case kHalfScreenCmd:
434 if (vo_quartz_fs)
436 vo_fs = (!(vo_fs));
437 window_fullscreen();
440 SizeWindow(theWindow, (d_width / 2), ((d_width / movie_aspect) / 2), 1);
441 window_resized();
442 break;
444 case kNormalScreenCmd:
445 if (vo_quartz_fs)
447 vo_fs = (!(vo_fs));
448 window_fullscreen();
451 SizeWindow(theWindow, d_width, (d_width / movie_aspect), 1);
452 window_resized();
453 break;
455 case kDoubleScreenCmd:
456 if (vo_quartz_fs)
458 vo_fs = (!(vo_fs));
459 window_fullscreen();
462 SizeWindow(theWindow, (d_width * 2), ((d_width / movie_aspect) * 2), 1);
463 window_resized();
464 break;
466 case kFullScreenCmd:
467 vo_fs = (!(vo_fs));
468 window_fullscreen();
469 break;
471 case kKeepAspectCmd:
472 vo_keepaspect = (!(vo_keepaspect));
473 CheckMenuItem(aspectMenu, 1, vo_keepaspect);
474 window_resized();
475 break;
477 case kAspectOrgCmd:
478 movie_aspect = old_movie_aspect;
479 if (!vo_quartz_fs)
481 SizeWindow(theWindow, dstRect.right, (dstRect.right / movie_aspect), 1);
483 window_resized();
484 break;
486 case kAspectFullCmd:
487 movie_aspect = 4.0f / 3.0f;
488 if (!vo_quartz_fs)
490 SizeWindow(theWindow, dstRect.right, (dstRect.right / movie_aspect), 1);
492 window_resized();
493 break;
495 case kAspectWideCmd:
496 movie_aspect = 16.0f / 9.0f;
497 if (!vo_quartz_fs)
499 SizeWindow(theWindow, dstRect.right, (dstRect.right / movie_aspect), 1);
501 window_resized();
502 break;
504 case kPanScanCmd:
505 vo_panscan = (!(vo_panscan));
506 CheckMenuItem(aspectMenu, 2, vo_panscan);
507 window_panscan();
508 window_resized();
509 break;
511 default:
512 result = eventNotHandledErr;
513 break;
516 else if (class == kEventClassWindow)
518 WindowRef window;
519 Rect rectWindow = { 0, 0, 0, 0 };
521 GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window);
523 if (window)
525 GetWindowBounds(window, kWindowGlobalPortRgn, &rectWindow);
528 switch (kind)
530 case kEventWindowClosed:
531 theWindow = NULL;
532 mplayer_put_key(KEY_CLOSE_WIN);
533 break;
535 // resize window
536 case kEventWindowZoomed:
537 case kEventWindowBoundsChanged:
538 window_resized();
539 flip_page();
540 window_resized();
541 break;
543 default:
544 result = eventNotHandledErr;
545 break;
549 return result;
552 static void quartz_CreateWindow(uint32_t d_width, uint32_t d_height, WindowAttributes windowAttrs)
554 CFStringRef titleKey;
555 CFStringRef windowTitle;
556 OSStatus result;
558 MenuItemIndex index;
559 CFStringRef movMenuTitle;
560 CFStringRef aspMenuTitle;
562 const EventTypeSpec win_events[] = {
563 {kEventClassWindow, kEventWindowClosed},
564 {kEventClassWindow, kEventWindowBoundsChanged},
565 {kEventClassCommand, kEventCommandProcess}
568 const EventTypeSpec key_events[] = {
569 {kEventClassKeyboard, kEventRawKeyDown},
570 {kEventClassKeyboard, kEventRawKeyRepeat}
573 const EventTypeSpec mouse_events[] = {
574 {kEventClassMouse, kEventMouseMoved},
575 {kEventClassMouse, kEventMouseWheelMoved},
576 {kEventClassMouse, kEventMouseDown},
577 {kEventClassMouse, kEventMouseUp},
578 {kEventClassMouse, kEventMouseDragged}
581 SetRect(&winRect, 0, 0, d_width, d_height);
582 SetRect(&oldWinRect, 0, 0, d_width, d_height);
583 SetRect(&dstRect, 0, 0, d_width, d_height);
585 // Clear Menu Bar
586 ClearMenuBar();
588 // Create Window Menu
589 CreateStandardWindowMenu(0, &windMenu);
590 InsertMenu(windMenu, 0);
592 // Create Movie Menu
593 CreateNewMenu(1004, 0, &movMenu);
594 movMenuTitle = CFSTR("Movie");
595 SetMenuTitleWithCFString(movMenu, movMenuTitle);
597 AppendMenuItemTextWithCFString(movMenu, CFSTR("Half Size"), 0, kHalfScreenCmd, &index);
598 SetMenuItemCommandKey(movMenu, index, 0, '0');
600 AppendMenuItemTextWithCFString(movMenu, CFSTR("Normal Size"), 0, kNormalScreenCmd, &index);
601 SetMenuItemCommandKey(movMenu, index, 0, '1');
603 AppendMenuItemTextWithCFString(movMenu, CFSTR("Double Size"), 0, kDoubleScreenCmd, &index);
604 SetMenuItemCommandKey(movMenu, index, 0, '2');
606 AppendMenuItemTextWithCFString(movMenu, CFSTR("Full Size"), 0, kFullScreenCmd, &index);
607 SetMenuItemCommandKey(movMenu, index, 0, 'F');
609 AppendMenuItemTextWithCFString(movMenu, NULL, kMenuItemAttrSeparator, 0, &index);
611 AppendMenuItemTextWithCFString(movMenu, CFSTR("Aspect Ratio"), 0, 0, &index);
613 //// Create Aspect Ratio Sub Menu
614 CreateNewMenu(0, 0, &aspectMenu);
615 aspMenuTitle = CFSTR("Aspect Ratio");
616 SetMenuTitleWithCFString(aspectMenu, aspMenuTitle);
617 SetMenuItemHierarchicalMenu(movMenu, 6, aspectMenu);
619 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Keep"), 0, kKeepAspectCmd, &index);
620 CheckMenuItem(aspectMenu, 1, vo_keepaspect);
621 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Pan-Scan"), 0, kPanScanCmd, &index);
622 CheckMenuItem(aspectMenu, 2, vo_panscan);
623 AppendMenuItemTextWithCFString(aspectMenu, NULL, kMenuItemAttrSeparator, 0, &index);
624 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Original"), 0, kAspectOrgCmd, &index);
625 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("4:3"), 0, kAspectFullCmd, &index);
626 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("16:9"), 0, kAspectWideCmd, &index);
628 InsertMenu(movMenu, GetMenuID(windMenu)); //insert before Window menu
630 DrawMenuBar();
632 // create window
633 CreateNewWindow(kDocumentWindowClass, windowAttrs, &winRect, &theWindow);
635 CreateWindowGroup(0, &winGroup);
636 SetWindowGroup(theWindow, winGroup);
638 // Set window title
639 titleKey = CFSTR("MPlayer - The Movie Player");
640 windowTitle = CFCopyLocalizedString(titleKey, NULL);
641 result = SetWindowTitleWithCFString(theWindow, windowTitle);
642 CFRelease(titleKey);
643 CFRelease(windowTitle);
645 // Install event handler
646 InstallApplicationEventHandler(NewEventHandlerUPP(KeyEventHandler), GetEventTypeCount(key_events), key_events, NULL, NULL);
647 InstallApplicationEventHandler(NewEventHandlerUPP(MouseEventHandler), GetEventTypeCount(mouse_events), mouse_events, NULL, NULL);
648 InstallWindowEventHandler(theWindow, NewEventHandlerUPP(WindowEventHandler), GetEventTypeCount(win_events), win_events, theWindow, NULL);
651 static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
653 WindowAttributes windowAttrs;
654 OSErr qterr;
655 CGRect tmpBounds;
656 CGDisplayCount displayCount;
657 CGDirectDisplayID *displays;
659 // Get Main device info///////////////////////////////////////////////////
661 // Display IDs might not be consecutive, get the list of all devices up to # device_id
662 displayCount = device_id + 1;
663 displays = malloc(sizeof(CGDirectDisplayID) * displayCount);
664 if (kCGErrorSuccess != CGGetActiveDisplayList(displayCount, displays, &displayCount) || displayCount < device_id + 1) {
665 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id);
666 displayId = kCGDirectMainDisplay;
667 device_id = 0;
669 else
671 displayId = displays[device_id];
673 free(displays);
675 displayRect = CGDisplayBounds(displayId);
677 monitor_aspect = (float)displayRect.size.width / (float)displayRect.size.height;
679 // misc mplayer setup/////////////////////////////////////////////////////
680 SetRect(&imgRect, 0, 0, width, height);
681 switch (image_format)
683 case IMGFMT_RGB32:
684 image_depth = 32;
685 break;
686 case IMGFMT_YV12:
687 case IMGFMT_IYUV:
688 case IMGFMT_I420:
689 case IMGFMT_UYVY:
690 case IMGFMT_YUY2:
691 image_depth = 16;
692 break;
694 image_size = ((imgRect.right * imgRect.bottom * image_depth) + 7) / 8;
696 vo_fs = flags & VOFLAG_FULLSCREEN;
698 // get movie aspect
699 panscan_init();
700 aspect_save_orig(width, height);
701 aspect_save_prescale(d_width, d_height);
702 aspect_save_screenres(displayRect.size.width, displayRect.size.height);
704 aspect(&d_width, &d_height, A_NOZOOM);
706 movie_aspect = (float)d_width / (float)d_height;
707 old_movie_aspect = movie_aspect;
709 if (image_data)
710 free(image_data);
712 image_data = malloc(image_size);
714 // Create player window//////////////////////////////////////////////////
715 windowAttrs = kWindowStandardDocumentAttributes
716 | kWindowStandardHandlerAttribute
717 | kWindowLiveResizeAttribute;
719 windowAttrs &= (~kWindowResizableAttribute);
721 if (theWindow == NULL)
723 CGContextRef context;
725 quartz_CreateWindow(d_width, d_height, windowAttrs);
727 if (theWindow == NULL)
729 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: Couldn't create window !!!!!\n");
730 return -1;
732 tmpBounds = CGRectMake(0, 0, winRect.right, winRect.bottom);
733 QDBeginCGContext(GetWindowPort(theWindow), &context);
734 CGContextFillRect(context, tmpBounds);
735 QDEndCGContext(GetWindowPort(theWindow), &context);
737 else
739 HideWindow(theWindow);
740 ChangeWindowAttributes(theWindow, ~windowAttrs, windowAttrs);
741 SetRect(&winRect, 0, 0, d_width, d_height);
742 SetRect(&oldWinRect, 0, 0, d_width, d_height);
743 SizeWindow(theWindow, d_width, d_height, 1);
746 switch (image_format)
748 case IMGFMT_RGB32:
750 CGContextRef context;
752 QDBeginCGContext(GetWindowPort(theWindow), &context);
754 dataProviderRef = CGDataProviderCreateWithData(0, image_data, imgRect.right * imgRect.bottom * 4, 0);
756 image = CGImageCreate(imgRect.right,
757 imgRect.bottom,
759 image_depth,
760 ((imgRect.right * 32) + 7) / 8,
761 CGColorSpaceCreateDeviceRGB(),
762 kCGImageAlphaNoneSkipFirst,
763 dataProviderRef, 0, 1, kCGRenderingIntentDefault);
765 QDEndCGContext(GetWindowPort(theWindow), &context);
766 break;
769 case IMGFMT_YV12:
770 case IMGFMT_IYUV:
771 case IMGFMT_I420:
772 case IMGFMT_UYVY:
773 case IMGFMT_YUY2:
775 get_image_done = 0;
777 if (!EnterMoviesDone)
779 qterr = EnterMovies();
780 EnterMoviesDone = 1;
782 else
783 qterr = 0;
785 if (qterr)
787 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: EnterMovies (%d)\n", qterr);
788 return -1;
792 SetIdentityMatrix(&matrix);
794 if ((d_width != width) || (d_height != height))
796 ScaleMatrix(&matrix, FixDiv(Long2Fix(d_width), Long2Fix(width)), FixDiv(Long2Fix(d_height), Long2Fix(height)), 0, 0);
799 yuv_qt_stuff.desc = (ImageDescriptionHandle) NewHandleClear(sizeof(ImageDescription));
801 yuv_qt_stuff.extension_colr = NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension));
802 ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->colorParamType = kVideoColorInfoImageDescriptionExtensionType;
803 ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->primaries = 2;
804 ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->transferFunction = 2;
805 ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->matrix = 2;
807 yuv_qt_stuff.extension_fiel = NewHandleClear(sizeof(FieldInfoImageDescriptionExtension));
808 ((FieldInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_fiel))->fieldCount = 1;
809 ((FieldInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_fiel))->fieldOrderings = 0;
811 yuv_qt_stuff.extension_clap = NewHandleClear(sizeof(CleanApertureImageDescriptionExtension));
812 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureWidthN = imgRect.right;
813 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureWidthD = 1;
814 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureHeightN = imgRect.bottom;
815 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureHeightD = 1;
816 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->horizOffN = 0;
817 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->horizOffD = 1;
818 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->vertOffN = 0;
819 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->vertOffD = 1;
821 yuv_qt_stuff.extension_pasp = NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension));
822 ((PixelAspectRatioImageDescriptionExtension *) (*yuv_qt_stuff.extension_pasp))->hSpacing = 1;
823 ((PixelAspectRatioImageDescriptionExtension *) (*yuv_qt_stuff.extension_pasp))->vSpacing = 1;
825 (*yuv_qt_stuff.desc)->idSize = sizeof(ImageDescription);
826 (*yuv_qt_stuff.desc)->cType = image_qtcodec;
827 (*yuv_qt_stuff.desc)->version = 2;
828 (*yuv_qt_stuff.desc)->revisionLevel = 0;
829 (*yuv_qt_stuff.desc)->vendor = 'mpla';
830 (*yuv_qt_stuff.desc)->width = imgRect.right;
831 (*yuv_qt_stuff.desc)->height = imgRect.bottom;
832 (*yuv_qt_stuff.desc)->hRes = Long2Fix(72);
833 (*yuv_qt_stuff.desc)->vRes = Long2Fix(72);
834 (*yuv_qt_stuff.desc)->temporalQuality = 0;
835 (*yuv_qt_stuff.desc)->spatialQuality = codecLosslessQuality;
836 (*yuv_qt_stuff.desc)->frameCount = 1;
837 (*yuv_qt_stuff.desc)->dataSize = 0;
838 (*yuv_qt_stuff.desc)->depth = 24;
839 (*yuv_qt_stuff.desc)->clutID = -1;
841 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_colr, kColorInfoImageDescriptionExtension);
842 if (qterr)
844 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr);
847 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_fiel, kFieldInfoImageDescriptionExtension);
848 if (qterr)
850 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr);
853 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_clap, kCleanApertureImageDescriptionExtension);
854 if (qterr)
856 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr);
859 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_pasp, kCleanApertureImageDescriptionExtension);
860 if (qterr)
862 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr);
864 if (P != NULL) { // second or subsequent movie
865 free(P);
867 P = calloc(sizeof(PlanarPixmapInfoYUV420) + image_size, 1);
868 switch (image_format)
870 case IMGFMT_YV12:
871 case IMGFMT_IYUV:
872 case IMGFMT_I420:
873 P->componentInfoY.offset = be2me_32(sizeof(PlanarPixmapInfoYUV420));
874 P->componentInfoCb.offset = be2me_32(be2me_32(P->componentInfoY.offset) + image_size / 2);
875 P->componentInfoCr.offset = be2me_32(be2me_32(P->componentInfoCb.offset) + image_size / 4);
876 P->componentInfoY.rowBytes = be2me_32(imgRect.right);
877 P->componentInfoCb.rowBytes = be2me_32(imgRect.right / 2);
878 P->componentInfoCr.rowBytes = be2me_32(imgRect.right / 2);
879 image_buffer_size = image_size + sizeof(PlanarPixmapInfoYUV420);
880 break;
881 case IMGFMT_UYVY:
882 case IMGFMT_YUY2:
883 image_buffer_size = image_size;
884 break;
887 qterr = DecompressSequenceBeginS(&seqId,
888 yuv_qt_stuff.desc,
889 (char *)P,
890 image_buffer_size,
891 GetWindowPort(theWindow),
892 NULL,
893 NULL,
894 ((d_width != width) || (d_height != height)) ?
895 &matrix : NULL,
896 srcCopy,
897 NULL,
899 codecLosslessQuality,
900 bestSpeedCodec);
902 if (qterr)
904 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr);
905 return -1;
908 break;
911 // Show window
912 RepositionWindow(theWindow, NULL, kWindowCenterOnMainScreen);
913 ShowWindow(theWindow);
915 if (vo_fs)
916 window_fullscreen();
918 if (vo_ontop)
919 window_ontop();
921 if (vo_rootwin)
923 vo_fs = TRUE;
924 winLevel = 0;
925 SetWindowGroupLevel(winGroup, CGWindowLevelForKey(levelList[winLevel]));
926 window_fullscreen();
929 window_resized();
931 return 0;
934 static void check_events(void)
936 EventRef theEvent;
937 EventTargetRef theTarget;
938 OSStatus theErr;
940 // Get event
941 theTarget = GetEventDispatcherTarget();
942 theErr = ReceiveNextEvent(0, 0, kEventDurationNoWait, true, &theEvent);
943 if (theErr == noErr && theEvent != NULL)
945 SendEventToEventTarget(theEvent, theTarget);
946 ReleaseEvent(theEvent);
950 static void draw_osd(void)
952 vo_draw_text(imgRect.right, imgRect.bottom, draw_alpha);
955 static void flip_page(void)
957 int curTime;
959 if (theWindow == NULL)
960 return;
962 switch (image_format)
964 case IMGFMT_RGB32:
966 CGContextRef context;
968 QDBeginCGContext(GetWindowPort(theWindow), &context);
969 CGContextDrawImage(context, bounds, image);
970 QDEndCGContext(GetWindowPort(theWindow), &context);
972 break;
974 case IMGFMT_YV12:
975 case IMGFMT_IYUV:
976 case IMGFMT_I420:
977 case IMGFMT_UYVY:
978 case IMGFMT_YUY2:
979 if (EnterMoviesDone)
981 OSErr qterr;
982 CodecFlags flags = 0;
984 qterr = DecompressSequenceFrameWhen(seqId,
985 (char *)P,
986 image_buffer_size,
987 0, //codecFlagUseImageBuffer,
988 &flags,
989 NULL,
990 NULL);
991 if (qterr)
993 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr, flags);
996 break;
999 if (!vo_quartz_fs)
1001 CGContextRef context;
1003 QDBeginCGContext(GetWindowPort(theWindow), &context);
1004 // render resize box
1005 CGContextBeginPath(context);
1006 CGContextSetAllowsAntialiasing(context, false);
1007 //CGContextSaveGState(context);
1009 // line white
1010 CGContextSetRGBStrokeColor(context, 0.2, 0.2, 0.2, 0.5);
1011 CGContextMoveToPoint(context, winRect.right - 1, 1); CGContextAddLineToPoint(context, winRect.right - 1, 1);
1012 CGContextMoveToPoint(context, winRect.right - 1, 5); CGContextAddLineToPoint(context, winRect.right - 5, 1);
1013 CGContextMoveToPoint(context, winRect.right - 1, 9); CGContextAddLineToPoint(context, winRect.right - 9, 1);
1014 CGContextStrokePath(context);
1016 // line gray
1017 CGContextSetRGBStrokeColor(context, 0.4, 0.4, 0.4, 0.5);
1018 CGContextMoveToPoint(context, winRect.right - 1, 2); CGContextAddLineToPoint(context, winRect.right - 2, 1);
1019 CGContextMoveToPoint(context, winRect.right - 1, 6); CGContextAddLineToPoint(context, winRect.right - 6, 1);
1020 CGContextMoveToPoint(context, winRect.right - 1, 10); CGContextAddLineToPoint(context, winRect.right - 10, 1);
1021 CGContextStrokePath(context);
1023 // line black
1024 CGContextSetRGBStrokeColor(context, 0.6, 0.6, 0.6, 0.5);
1025 CGContextMoveToPoint(context, winRect.right - 1, 3); CGContextAddLineToPoint(context, winRect.right - 3, 1);
1026 CGContextMoveToPoint(context, winRect.right - 1, 7); CGContextAddLineToPoint(context, winRect.right - 7, 1);
1027 CGContextMoveToPoint(context, winRect.right - 1, 11); CGContextAddLineToPoint(context, winRect.right - 11, 1);
1028 CGContextStrokePath(context);
1030 // CGContextRestoreGState( context );
1031 CGContextFlush(context);
1032 QDEndCGContext(GetWindowPort(theWindow), &context);
1035 curTime = TickCount() / 60;
1037 // auto hide mouse cursor (and future on-screen control?)
1038 if (vo_quartz_fs && !mouseHide)
1040 if (((curTime - lastMouseHide) >= 5) || (lastMouseHide == 0))
1042 CGDisplayHideCursor(displayId);
1043 mouseHide = TRUE;
1044 lastMouseHide = curTime;
1047 // update activity every 30 seconds to prevent
1048 // screensaver from starting up.
1049 if (((curTime - lastScreensaverUpdate) >= 30) || (lastScreensaverUpdate == 0))
1051 UpdateSystemActivity(UsrActivity);
1052 lastScreensaverUpdate = curTime;
1056 static int draw_slice(uint8_t * src[], int stride[], int w, int h, int x, int y)
1058 switch (image_format)
1060 case IMGFMT_YV12:
1061 case IMGFMT_I420:
1062 memcpy_pic(((char *)P) + be2me_32(P->componentInfoY.offset) + x + imgRect.right * y, src[0], w, h, imgRect.right, stride[0]);
1063 x=x/2;y=y/2;w=w/2;h=h/2;
1065 memcpy_pic(((char *)P) + be2me_32(P->componentInfoCb.offset) + x + imgRect.right / 2 * y, src[1], w, h, imgRect.right / 2, stride[1]);
1066 memcpy_pic(((char *)P) + be2me_32(P->componentInfoCr.offset) + x + imgRect.right / 2 * y, src[2], w, h, imgRect.right / 2, stride[2]);
1067 return 0;
1069 case IMGFMT_IYUV:
1070 memcpy_pic(((char *)P) + be2me_32(P->componentInfoY.offset) + x + imgRect.right * y, src[0], w, h, imgRect.right, stride[0]);
1071 x=x/2;y=y/2;w=w/2;h=h/2;
1073 memcpy_pic(((char *)P) + be2me_32(P->componentInfoCr.offset) + x + imgRect.right / 2 * y, src[1], w, h, imgRect.right / 2, stride[1]);
1074 memcpy_pic(((char *)P) + be2me_32(P->componentInfoCb.offset) + x + imgRect.right / 2 * y, src[2], w, h, imgRect.right / 2, stride[2]);
1075 return 0;
1077 return -1;
1080 static int draw_frame(uint8_t * src[])
1082 switch (image_format)
1084 case IMGFMT_RGB32:
1085 fast_memcpy(image_data, src[0], image_size);
1086 return 0;
1088 case IMGFMT_UYVY:
1089 case IMGFMT_YUY2:
1090 memcpy_pic(((char *)P), src[0], imgRect.right * 2, imgRect.bottom, imgRect.right * 2, imgRect.right * 2);
1091 return 0;
1093 return -1;
1096 static int query_format(uint32_t format)
1098 image_format = format;
1099 image_qtcodec = 0;
1101 if (format == IMGFMT_RGB32)
1103 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1106 if ((format == IMGFMT_YV12) || (format == IMGFMT_IYUV) || (format == IMGFMT_I420))
1108 image_qtcodec = kMpegYUV420CodecType; //kYUV420CodecType ?;
1109 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE;
1112 if (format == IMGFMT_YUY2)
1114 image_qtcodec = kComponentVideoUnsigned;
1115 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1118 if (format == IMGFMT_UYVY)
1120 image_qtcodec = k422YpCbCr8CodecType;
1121 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1124 return 0;
1127 static void uninit(void)
1129 OSErr qterr;
1131 switch (image_format)
1133 case IMGFMT_YV12:
1134 case IMGFMT_IYUV:
1135 case IMGFMT_I420:
1136 case IMGFMT_UYVY:
1137 case IMGFMT_YUY2:
1139 if (EnterMoviesDone)
1141 qterr = CDSequenceEnd(seqId);
1142 if (qterr)
1144 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: CDSequenceEnd (%d)\n", qterr);
1147 break;
1149 default:
1150 break;
1153 ShowMenuBar();
1156 static int preinit(const char *arg)
1158 int parse_err = 0;
1160 if(arg)
1162 char *parse_pos = (char *)&arg[0];
1164 while (parse_pos[0] && !parse_err)
1166 if (strncmp(parse_pos, "device_id=", 10) == 0)
1168 parse_pos = &parse_pos[10];
1169 device_id = strtol(parse_pos, &parse_pos, 0);
1171 if (strncmp(parse_pos, "fs_res=", 7) == 0)
1173 parse_pos = &parse_pos[7];
1174 fs_res_x = strtol(parse_pos, &parse_pos, 0);
1175 parse_pos = &parse_pos[1];
1176 fs_res_y = strtol(parse_pos, &parse_pos, 0);
1178 if (parse_pos[0] == ':')
1179 parse_pos = &parse_pos[1];
1180 else if (parse_pos[0])
1181 parse_err = 1;
1185 #if !defined (CONFIG_MACOSX_FINDER) || !defined (CONFIG_SDL)
1186 // this chunk of code is heavily based off SDL_macosx.m from SDL
1187 // the CPSEnableForegroundOperation that was here before is private and shouldn't be used
1188 // replaced by a call to the 10.3+ TransformProcessType
1190 ProcessSerialNumber myProc, frProc;
1191 Boolean sameProc;
1193 if (GetFrontProcess(&frProc) == noErr)
1195 if (GetCurrentProcess(&myProc) == noErr)
1197 if (SameProcess(&frProc, &myProc, &sameProc) == noErr && !sameProc)
1199 TransformProcessType(&myProc, kProcessTransformToForegroundApplication);
1201 SetFrontProcess(&myProc);
1205 #endif
1207 return 0;
1210 static uint32_t draw_yuv_image(mp_image_t * mpi)
1212 // ATM we're only called for planar IMGFMT
1213 // drawing is done directly in P
1214 // and displaying is in flip_page.
1215 return get_image_done ? VO_TRUE : VO_FALSE;
1218 static uint32_t get_yuv_image(mp_image_t * mpi)
1220 if (mpi->type != MP_IMGTYPE_EXPORT) return VO_FALSE;
1222 if (mpi->imgfmt != image_format) return VO_FALSE;
1224 if (mpi->flags & MP_IMGFLAG_PLANAR)
1226 if (mpi->num_planes != 3)
1228 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi->num_planes);
1229 return VO_FALSE;
1232 mpi->planes[0] = ((char *)P) + be2me_32(P->componentInfoY.offset);
1233 mpi->stride[0] = imgRect.right;
1234 mpi->width = imgRect.right;
1236 if (mpi->flags & MP_IMGFLAG_SWAPPED)
1238 // I420
1239 mpi->planes[1] = ((char *)P) + be2me_32(P->componentInfoCb.offset);
1240 mpi->planes[2] = ((char *)P) + be2me_32(P->componentInfoCr.offset);
1241 mpi->stride[1] = imgRect.right / 2;
1242 mpi->stride[2] = imgRect.right / 2;
1244 else
1246 // YV12
1247 mpi->planes[1] = ((char *)P) + be2me_32(P->componentInfoCr.offset);
1248 mpi->planes[2] = ((char *)P) + be2me_32(P->componentInfoCb.offset);
1249 mpi->stride[1] = imgRect.right / 2;
1250 mpi->stride[2] = imgRect.right / 2;
1253 mpi->flags |= MP_IMGFLAG_DIRECT;
1254 get_image_done = 1;
1255 return VO_TRUE;
1257 else
1259 // doesn't work yet
1260 if (mpi->num_planes != 1)
1262 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi->num_planes);
1263 return VO_FALSE;
1266 mpi->planes[0] = (char *)P;
1267 mpi->stride[0] = imgRect.right * 2;
1268 mpi->width = imgRect.right;
1269 mpi->flags |= MP_IMGFLAG_DIRECT;
1270 get_image_done = 1;
1271 return VO_TRUE;
1273 return VO_FALSE;
1276 static int control(uint32_t request, void *data, ...)
1278 switch (request)
1280 case VOCTRL_PAUSE: return int_pause = 1;
1281 case VOCTRL_RESUME: return int_pause = 0;
1282 case VOCTRL_FULLSCREEN: vo_fs = (!(vo_fs)); window_fullscreen(); return VO_TRUE;
1283 case VOCTRL_ONTOP: vo_ontop = (!(vo_ontop)); window_ontop(); return VO_TRUE;
1284 case VOCTRL_QUERY_FORMAT: return query_format(*((uint32_t *) data));
1285 case VOCTRL_GET_PANSCAN: return VO_TRUE;
1286 case VOCTRL_SET_PANSCAN: window_panscan(); return VO_TRUE;
1288 case VOCTRL_GET_IMAGE:
1289 switch (image_format)
1291 case IMGFMT_YV12:
1292 case IMGFMT_IYUV:
1293 case IMGFMT_I420:
1294 case IMGFMT_UYVY:
1295 case IMGFMT_YUY2:
1296 return get_yuv_image(data);
1297 break;
1298 default:
1299 break;
1301 case VOCTRL_DRAW_IMAGE:
1302 switch (image_format)
1304 case IMGFMT_YV12:
1305 case IMGFMT_IYUV:
1306 case IMGFMT_I420:
1307 case IMGFMT_UYVY:
1308 case IMGFMT_YUY2:
1309 return draw_yuv_image(data);
1310 break;
1311 default:
1312 break;
1315 return VO_NOTIMPL;
1318 void window_resized(void)
1320 float aspectX;
1321 float aspectY;
1323 int padding = 0;
1325 uint32_t d_width;
1326 uint32_t d_height;
1328 CGRect tmpBounds;
1330 CGContextRef context;
1332 GetWindowPortBounds(theWindow, &winRect);
1334 if (vo_keepaspect)
1336 aspect(&d_width, &d_height, A_NOZOOM);
1337 d_height = ((float)d_width / movie_aspect);
1339 aspectX = (float)((float)winRect.right / (float)d_width);
1340 aspectY = (float)((float)(winRect.bottom) / (float)d_height);
1342 if ((d_height * aspectX) > (winRect.bottom))
1344 padding = (winRect.right - d_width * aspectY) / 2;
1345 SetRect(&dstRect, padding, 0, d_width * aspectY + padding, d_height * aspectY);
1347 else
1349 padding = ((winRect.bottom) - d_height * aspectX) / 2;
1350 SetRect(&dstRect, 0, padding, (d_width * aspectX), d_height * aspectX + padding);
1353 else
1355 SetRect(&dstRect, 0, 0, winRect.right, winRect.bottom);
1358 switch (image_format)
1360 case IMGFMT_RGB32:
1362 bounds = CGRectMake(dstRect.left, dstRect.top, dstRect.right - dstRect.left, dstRect.bottom - dstRect.top);
1363 break;
1365 case IMGFMT_YV12:
1366 case IMGFMT_IYUV:
1367 case IMGFMT_I420:
1368 case IMGFMT_UYVY:
1369 case IMGFMT_YUY2:
1371 long scale_X = FixDiv(Long2Fix(dstRect.right - dstRect.left), Long2Fix(imgRect.right));
1372 long scale_Y = FixDiv(Long2Fix(dstRect.bottom - dstRect.top), Long2Fix(imgRect.bottom));
1374 SetIdentityMatrix(&matrix);
1375 if (((dstRect.right - dstRect.left) != imgRect.right) || ((dstRect.bottom - dstRect.right) != imgRect.bottom))
1377 ScaleMatrix(&matrix, scale_X, scale_Y, 0, 0);
1379 if (padding > 0)
1381 TranslateMatrix(&matrix, Long2Fix(dstRect.left), Long2Fix(dstRect.top));
1385 SetDSequenceMatrix(seqId, &matrix);
1386 break;
1388 default:
1389 break;
1392 // Clear Background
1393 tmpBounds = CGRectMake(0, 0, winRect.right, winRect.bottom);
1394 QDBeginCGContext(GetWindowPort(theWindow), &context);
1395 CGContextFillRect(context, tmpBounds);
1396 QDEndCGContext(GetWindowPort(theWindow), &context);
1399 void window_ontop(void)
1401 if (!vo_quartz_fs)
1403 // Cycle between level
1404 winLevel++;
1405 if (winLevel > 2)
1406 winLevel = 1;
1408 SetWindowGroupLevel(winGroup, CGWindowLevelForKey(levelList[winLevel]));
1411 void window_fullscreen(void)
1413 // go fullscreen
1414 if (vo_fs)
1416 if (winLevel != 0)
1418 if (displayId == kCGDirectMainDisplay)
1420 SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1421 CGDisplayHideCursor(displayId);
1422 mouseHide = TRUE;
1425 if (fs_res_x != 0 || fs_res_y != 0)
1427 CFDictionaryRef mode;
1428 size_t desiredBitDepth = 32;
1429 boolean_t exactMatch;
1431 originalMode = CGDisplayCurrentMode(displayId);
1433 mode = CGDisplayBestModeForParameters(displayId, desiredBitDepth, fs_res_x, fs_res_y, &exactMatch);
1435 if (mode != NULL)
1437 if (!exactMatch)
1439 // Warn if the mode doesn't match exactly
1440 mp_msg(MSGT_VO, MSGL_WARN, "Quartz warning: did not get exact mode match (got %dx%d) \n", (int)CFDictionaryGetValue(mode, kCGDisplayWidth), (int)CFDictionaryGetValue(mode, kCGDisplayHeight));
1443 CGDisplayCapture(displayId);
1444 CGDisplaySwitchToMode(displayId, mode);
1446 else
1448 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: can't switch to fullscreen \n");
1451 // Get Main device info///////////////////////////////////////////////////
1452 displayRect = CGDisplayBounds(displayId);
1455 // save old window size
1456 if (!vo_quartz_fs)
1458 GetWindowPortBounds(theWindow, &oldWinRect);
1459 GetWindowBounds(theWindow, kWindowContentRgn, &oldWinBounds);
1461 // go fullscreen
1462 panscan_calc();
1463 ChangeWindowAttributes(theWindow, kWindowNoShadowAttribute, 0);
1464 MoveWindow(theWindow, displayRect.origin.x - (vo_panscan_x >> 1), displayRect.origin.y - (vo_panscan_y >> 1), 1);
1465 SizeWindow(theWindow, displayRect.size.width + vo_panscan_x, displayRect.size.height + vo_panscan_y, 1);
1467 vo_quartz_fs = 1;
1469 else //go back to windowed mode
1471 vo_quartz_fs = 0;
1472 if (originalMode != NULL)
1474 CGDisplaySwitchToMode(displayId, originalMode);
1475 CGDisplayRelease(displayId);
1477 // Get Main device info///////////////////////////////////////////////////
1478 displayRect = CGDisplayBounds(displayId);
1480 originalMode = NULL;
1482 SetSystemUIMode(kUIModeNormal, 0);
1484 // show mouse cursor
1485 CGDisplayShowCursor(displayId);
1486 mouseHide = FALSE;
1488 // revert window to previous setting
1489 ChangeWindowAttributes(theWindow, 0, kWindowNoShadowAttribute);
1490 SizeWindow(theWindow, oldWinRect.right, oldWinRect.bottom, 1);
1491 MoveWindow(theWindow, oldWinBounds.left, oldWinBounds.top, 1);
1493 window_resized();
1496 void window_panscan(void)
1498 panscan_calc();
1500 if (vo_panscan > 0)
1501 CheckMenuItem(aspectMenu, 2, 1);
1502 else
1503 CheckMenuItem(aspectMenu, 2, 0);
1505 if (vo_quartz_fs)
1507 MoveWindow(theWindow, displayRect.origin.x - (vo_panscan_x >> 1), displayRect.origin.y - (vo_panscan_y >> 1), 1);
1508 SizeWindow(theWindow, displayRect.size.width + vo_panscan_x, displayRect.size.height + vo_panscan_y, 1);