4 by Nicolas Plourde <nicolasplourde@gmail.com>
6 Copyright (c) Nicolas Plourde - April 2004
8 YUV support Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
10 MPlayer Mac OSX Quartz video out module.
12 todo: -screen overlay output
13 -fit osd in black bar when available
22 #include <Carbon/Carbon.h>
23 #include <QuickTime/QuickTime.h>
27 #include "fastmemcpy.h"
28 #include "video_out.h"
29 #include "video_out_internal.h"
36 #include "input/input.h"
37 #include "input/mouse.h"
39 #include "vo_quartz.h"
41 static const vo_info_t info
=
45 "Nicolas Plourde <nicolasplourde@hotmail.com>, Romain Dolbeau <romain@dolbeau.org>",
49 const LIBVO_EXTERN(quartz
)
51 static uint32_t image_depth
;
52 static uint32_t image_format
;
53 static uint32_t image_size
;
54 static uint32_t image_buffer_size
;
55 static char *image_data
;
57 static ImageSequence seqId
;
58 static CodecType image_qtcodec
;
59 static PlanarPixmapInfoYUV420
*P
= NULL
;
62 ImageDescriptionHandle desc
;
63 Handle extension_colr
;
64 Handle extension_fiel
;
65 Handle extension_clap
;
66 Handle extension_pasp
;
68 static MatrixRecord matrix
;
69 static int EnterMoviesDone
= 0;
70 static int get_image_done
= 0;
72 static int vo_quartz_fs
; // we are in fullscreen
73 extern float monitor_aspect
;
74 extern float movie_aspect
;
75 static float old_movie_aspect
;
77 static int winLevel
= 1;
80 kCGDesktopWindowLevelKey
,
81 kCGNormalWindowLevelKey
,
82 kCGScreenSaverWindowLevelKey
85 static int int_pause
= 0;
86 static float winAlpha
= 1;
87 static int mouseHide
= FALSE
;
89 static int device_width
;
90 static int device_height
;
93 static short fs_res_x
=0;
94 static short fs_res_y
=0;
96 static WindowRef theWindow
= NULL
;
97 static WindowGroupRef winGroup
= NULL
;
98 static CGContextRef context
;
100 static GDHandle deviceHdl
;
102 static CGDataProviderRef dataProviderRef
;
103 static CGImageRef image
;
105 static Rect imgRect
; // size of the original image (unscaled)
106 static Rect dstRect
; // size of the displayed image (after scaling)
107 static Rect winRect
; // size of the window containg the displayed image (include padding)
108 static Rect oldWinRect
; // size of the window containg the displayed image (include padding) when NOT in FS mode
109 static Rect deviceRect
; // size of the display device
110 static Rect oldWinBounds
;
112 static MenuRef windMenu
;
113 static MenuRef movMenu
;
114 static MenuRef aspectMenu
;
120 kNormalScreenCmd
= 3,
121 kDoubleScreenCmd
= 4,
130 #include "osdep/keycodes.h"
132 //PROTOTYPE/////////////////////////////////////////////////////////////////
133 static OSStatus
KeyEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
134 static OSStatus
MouseEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
135 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
136 void window_resized();
138 void window_fullscreen();
139 void window_panscan();
141 static inline int convert_key(UInt32 key
, UInt32 charcode
)
146 case QZ_RETURN
: return KEY_ENTER
;
147 case QZ_ESCAPE
: return KEY_ESC
;
148 case QZ_BACKSPACE
: return KEY_BACKSPACE
;
149 case QZ_LALT
: return KEY_BACKSPACE
;
150 case QZ_LCTRL
: return KEY_BACKSPACE
;
151 case QZ_LSHIFT
: return KEY_BACKSPACE
;
152 case QZ_F1
: return KEY_F
+1;
153 case QZ_F2
: return KEY_F
+2;
154 case QZ_F3
: return KEY_F
+3;
155 case QZ_F4
: return KEY_F
+4;
156 case QZ_F5
: return KEY_F
+5;
157 case QZ_F6
: return KEY_F
+6;
158 case QZ_F7
: return KEY_F
+7;
159 case QZ_F8
: return KEY_F
+8;
160 case QZ_F9
: return KEY_F
+9;
161 case QZ_F10
: return KEY_F
+10;
162 case QZ_F11
: return KEY_F
+11;
163 case QZ_F12
: return KEY_F
+12;
164 case QZ_INSERT
: return KEY_INSERT
;
165 case QZ_DELETE
: return KEY_DELETE
;
166 case QZ_HOME
: return KEY_HOME
;
167 case QZ_END
: return KEY_END
;
168 case QZ_KP_PLUS
: return '+';
169 case QZ_KP_MINUS
: return '-';
170 case QZ_TAB
: return KEY_TAB
;
171 case QZ_PAGEUP
: return KEY_PAGE_UP
;
172 case QZ_PAGEDOWN
: return KEY_PAGE_DOWN
;
173 case QZ_UP
: return KEY_UP
;
174 case QZ_DOWN
: return KEY_DOWN
;
175 case QZ_LEFT
: return KEY_LEFT
;
176 case QZ_RIGHT
: return KEY_RIGHT
;
177 case QZ_KP_MULTIPLY
: return '*';
178 case QZ_KP_DIVIDE
: return '/';
179 case QZ_KP_ENTER
: return KEY_KPENTER
;
180 case QZ_KP_PERIOD
: return KEY_KPDEC
;
181 case QZ_KP0
: return KEY_KP0
;
182 case QZ_KP1
: return KEY_KP1
;
183 case QZ_KP2
: return KEY_KP2
;
184 case QZ_KP3
: return KEY_KP3
;
185 case QZ_KP4
: return KEY_KP4
;
186 case QZ_KP5
: return KEY_KP5
;
187 case QZ_KP6
: return KEY_KP6
;
188 case QZ_KP7
: return KEY_KP7
;
189 case QZ_KP8
: return KEY_KP8
;
190 case QZ_KP9
: return KEY_KP9
;
191 default: return charcode
;
195 static void draw_alpha(int x0
, int y0
, int w
, int h
, unsigned char *src
, unsigned char *srca
, int stride
)
197 switch (image_format
)
200 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,image_data
+4*(y0
*imgRect
.right
+x0
),4*imgRect
.right
);
205 vo_draw_alpha_yv12(w
,h
,src
,srca
,stride
, ((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x0
+ y0
* imgRect
.right
, imgRect
.right
);
208 vo_draw_alpha_uyvy(w
,h
,src
,srca
,stride
,((char*)P
) + (x0
+ y0
* imgRect
.right
) * 2,imgRect
.right
*2);
211 vo_draw_alpha_yuy2(w
,h
,src
,srca
,stride
,((char*)P
) + (x0
+ y0
* imgRect
.right
) * 2,imgRect
.right
*2);
216 //default keyboard event handler
217 static OSStatus
KeyEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
219 OSStatus result
= noErr
;
220 UInt32
class = GetEventClass (event
);
221 UInt32 kind
= GetEventKind (event
);
223 result
= CallNextEventHandler(nextHandler
, event
);
225 if(class == kEventClassKeyboard
)
229 UInt32 macKeyModifiers
;
231 GetEventParameter(event
, kEventParamKeyMacCharCodes
, typeChar
, NULL
, sizeof(macCharCodes
), NULL
, &macCharCodes
);
232 GetEventParameter(event
, kEventParamKeyCode
, typeUInt32
, NULL
, sizeof(macKeyCode
), NULL
, &macKeyCode
);
233 GetEventParameter(event
, kEventParamKeyModifiers
, typeUInt32
, NULL
, sizeof(macKeyModifiers
), NULL
, &macKeyModifiers
);
235 if(macKeyModifiers
!= 256)
237 if (kind
== kEventRawKeyRepeat
|| kind
== kEventRawKeyDown
)
239 int key
= convert_key(macKeyCode
, macCharCodes
);
241 mplayer_put_key(key
);
244 else if(macKeyModifiers
== 256)
248 case '[': SetWindowAlpha(theWindow
, winAlpha
-=0.05); break;
249 case ']': SetWindowAlpha(theWindow
, winAlpha
+=0.05); break;
253 result
= eventNotHandledErr
;
259 //default mouse event handler
260 static OSStatus
MouseEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
262 OSStatus result
= noErr
;
263 UInt32
class = GetEventClass (event
);
264 UInt32 kind
= GetEventKind (event
);
266 result
= CallNextEventHandler(nextHandler
, event
);
268 if(class == kEventClassMouse
)
274 GetEventParameter(event
, kEventParamMouseLocation
, typeQDPoint
, 0, sizeof(Point
), 0, &mousePos
);
275 GetEventParameter(event
, kEventParamWindowMouseLocation
, typeQDPoint
, 0, sizeof(Point
), 0, &winMousePos
);
279 case kEventMouseMoved
:
283 CGDisplayShowCursor(kCGDirectMainDisplay
);
289 case kEventMouseWheelMoved
:
294 GetEventParameter(event
, kEventParamMouseWheelDelta
, typeSInt32
, 0, sizeof(int), 0, &wheel
);
296 part
= FindWindow(mousePos
,&tmpWin
);
298 if(part
== inContent
)
301 mplayer_put_key(MOUSE_BTN3
);
303 mplayer_put_key(MOUSE_BTN4
);
308 case kEventMouseDown
:
311 EventMouseButton button
;
315 GetWindowPortBounds(theWindow
, &bounds
);
316 GetEventParameter(event
, kEventParamMouseButton
, typeMouseButton
, 0, sizeof(EventMouseButton
), 0, &button
);
318 part
= FindWindow(mousePos
,&tmpWin
);
319 if(kind
== kEventMouseUp
)
321 if (part
!= inContent
)
325 case kEventMouseButtonPrimary
:
326 mplayer_put_key(MOUSE_BTN0
);
328 case kEventMouseButtonSecondary
:
329 mplayer_put_key(MOUSE_BTN2
);
331 case kEventMouseButtonTertiary
:
332 mplayer_put_key(MOUSE_BTN1
);
335 default:result
= eventNotHandledErr
;break;
339 if( (winMousePos
.h
> (bounds
.right
- 15)) && (winMousePos
.v
> (bounds
.bottom
)) )
343 GrowWindow(theWindow
, mousePos
, NULL
);
346 else if(part
== inMenuBar
)
348 MenuSelect(mousePos
);
351 else if(part
== inContent
)
355 case kEventMouseButtonPrimary
:
356 mplayer_put_key(MOUSE_BTN0
| MP_KEY_DOWN
);
358 case kEventMouseButtonSecondary
:
359 mplayer_put_key(MOUSE_BTN2
| MP_KEY_DOWN
);
361 case kEventMouseButtonTertiary
:
362 mplayer_put_key(MOUSE_BTN1
| MP_KEY_DOWN
);
365 default:result
= eventNotHandledErr
;break;
371 case kEventMouseDragged
:
374 default:result
= eventNotHandledErr
;break;
381 //default window event handler
382 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
384 OSStatus result
= noErr
;
387 UInt32
class = GetEventClass (event
);
388 UInt32 kind
= GetEventKind (event
);
390 result
= CallNextEventHandler(nextHandler
, event
);
392 aspect(&d_width
,&d_height
,A_NOZOOM
);
394 if(class == kEventClassCommand
)
396 HICommand theHICommand
;
397 GetEventParameter( event
, kEventParamDirectObject
, typeHICommand
, NULL
, sizeof( HICommand
), NULL
, &theHICommand
);
399 switch ( theHICommand
.commandID
)
402 mplayer_put_key(KEY_CLOSE_WIN
);
408 vo_fs
= (!(vo_fs
)); window_fullscreen();
411 SizeWindow(theWindow
, (d_width
/2), ((d_width
/movie_aspect
)/2), 1);
415 case kNormalScreenCmd
:
418 vo_fs
= (!(vo_fs
)); window_fullscreen();
421 SizeWindow(theWindow
, d_width
, (d_width
/movie_aspect
), 1);
425 case kDoubleScreenCmd
:
428 vo_fs
= (!(vo_fs
)); window_fullscreen();
431 SizeWindow(theWindow
, (d_width
*2), ((d_width
/movie_aspect
)*2), 1);
436 vo_fs
= (!(vo_fs
)); window_fullscreen();
440 vo_keepaspect
= (!(vo_keepaspect
));
441 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
446 movie_aspect
= old_movie_aspect
;
449 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
455 movie_aspect
= 4.0f
/3.0f
;
458 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
464 movie_aspect
= 16.0f
/9.0f
;
467 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
473 vo_panscan
= (!(vo_panscan
));
474 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
480 result
= eventNotHandledErr
;
484 else if(class == kEventClassWindow
)
487 Rect rectPort
= {0,0,0,0};
489 GetEventParameter(event
, kEventParamDirectObject
, typeWindowRef
, NULL
, sizeof(WindowRef
), NULL
, &window
);
493 GetPortBounds(GetWindowPort(window
), &rectPort
);
498 case kEventWindowClosed
:
500 mplayer_put_key(KEY_CLOSE_WIN
);
504 case kEventWindowZoomed
:
505 case kEventWindowBoundsChanged
:
512 result
= eventNotHandledErr
;
520 static void quartz_CreateWindow(uint32_t d_width
, uint32_t d_height
, WindowAttributes windowAttrs
)
522 CFStringRef titleKey
;
523 CFStringRef windowTitle
;
527 CFStringRef movMenuTitle
;
528 CFStringRef aspMenuTitle
;
530 const EventTypeSpec win_events
[] = {
531 { kEventClassWindow
, kEventWindowClosed
},
532 { kEventClassWindow
, kEventWindowBoundsChanged
},
533 { kEventClassCommand
, kEventCommandProcess
}
536 const EventTypeSpec key_events
[] = {
537 { kEventClassKeyboard
, kEventRawKeyDown
},
538 { kEventClassKeyboard
, kEventRawKeyRepeat
}
541 const EventTypeSpec mouse_events
[] = {
542 { kEventClassMouse
, kEventMouseMoved
},
543 { kEventClassMouse
, kEventMouseWheelMoved
},
544 { kEventClassMouse
, kEventMouseDown
},
545 { kEventClassMouse
, kEventMouseUp
},
546 { kEventClassMouse
, kEventMouseDragged
}
549 SetRect(&winRect
, 0, 0, d_width
, d_height
);
550 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
551 SetRect(&dstRect
, 0, 0, d_width
, d_height
);
557 CreateStandardWindowMenu(0, &windMenu
);
558 InsertMenu(windMenu
, 0);
561 CreateNewMenu (1004, 0, &movMenu
);
562 movMenuTitle
= CFSTR("Movie");
563 SetMenuTitleWithCFString(movMenu
, movMenuTitle
);
565 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Half Size"), 0, kHalfScreenCmd
, &index
);
566 SetMenuItemCommandKey(movMenu
, index
, 0, '0');
568 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Normal Size"), 0, kNormalScreenCmd
, &index
);
569 SetMenuItemCommandKey(movMenu
, index
, 0, '1');
571 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Double Size"), 0, kDoubleScreenCmd
, &index
);
572 SetMenuItemCommandKey(movMenu
, index
, 0, '2');
574 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Full Size"), 0, kFullScreenCmd
, &index
);
575 SetMenuItemCommandKey(movMenu
, index
, 0, 'F');
577 AppendMenuItemTextWithCFString(movMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
579 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Aspect Ratio"), 0, 0, &index
);
581 ////Create Aspect Ratio Sub Menu
582 CreateNewMenu (0, 0, &aspectMenu
);
583 aspMenuTitle
= CFSTR("Aspect Ratio");
584 SetMenuTitleWithCFString(aspectMenu
, aspMenuTitle
);
585 SetMenuItemHierarchicalMenu(movMenu
, 6, aspectMenu
);
587 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Keep"), 0, kKeepAspectCmd
, &index
);
588 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
589 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Pan-Scan"), 0, kPanScanCmd
, &index
);
590 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
591 AppendMenuItemTextWithCFString(aspectMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
592 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Original"), 0, kAspectOrgCmd
, &index
);
593 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("4:3"), 0, kAspectFullCmd
, &index
);
594 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("16:9"), 0, kAspectWideCmd
, &index
);
596 InsertMenu(movMenu
, GetMenuID(windMenu
)); //insert before Window menu
601 CreateNewWindow(kDocumentWindowClass
, windowAttrs
, &winRect
, &theWindow
);
603 CreateWindowGroup(0, &winGroup
);
604 SetWindowGroup(theWindow
, winGroup
);
607 titleKey
= CFSTR("MPlayer - The Movie Player");
608 windowTitle
= CFCopyLocalizedString(titleKey
, NULL
);
609 result
= SetWindowTitleWithCFString(theWindow
, windowTitle
);
611 CFRelease(windowTitle
);
613 //Install event handler
614 InstallApplicationEventHandler (NewEventHandlerUPP (KeyEventHandler
), GetEventTypeCount(key_events
), key_events
, NULL
, NULL
);
615 InstallApplicationEventHandler (NewEventHandlerUPP (MouseEventHandler
), GetEventTypeCount(mouse_events
), mouse_events
, NULL
, NULL
);
616 InstallWindowEventHandler (theWindow
, NewEventHandlerUPP (WindowEventHandler
), GetEventTypeCount(win_events
), win_events
, theWindow
, NULL
);
619 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
)
621 WindowAttributes windowAttrs
;
626 //Get Main device info///////////////////////////////////////////////////
629 deviceHdl
= GetMainDevice();
631 for(i
=0; i
<device_id
; i
++)
633 deviceHdl
= GetNextDevice(deviceHdl
);
635 if(deviceHdl
== NULL
)
637 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id
);
638 deviceHdl
= GetMainDevice();
644 deviceRect
= (*deviceHdl
)->gdRect
;
645 device_width
= deviceRect
.right
-deviceRect
.left
;
646 device_height
= deviceRect
.bottom
-deviceRect
.top
;
648 monitor_aspect
= (float)device_width
/(float)device_height
;
650 //misc mplayer setup/////////////////////////////////////////////////////
651 SetRect(&imgRect
, 0, 0, width
, height
);
652 switch (image_format
)
665 image_size
= ((imgRect
.right
*imgRect
.bottom
*image_depth
)+7)/8;
667 vo_fs
= flags
& VOFLAG_FULLSCREEN
;
671 aspect_save_orig(width
,height
);
672 aspect_save_prescale(d_width
,d_height
);
673 aspect_save_screenres(device_width
, device_height
);
675 aspect(&d_width
,&d_height
,A_NOZOOM
);
677 movie_aspect
= (float)d_width
/(float)d_height
;
678 old_movie_aspect
= movie_aspect
;
683 image_data
= malloc(image_size
);
685 //Create player window//////////////////////////////////////////////////
686 windowAttrs
= kWindowStandardDocumentAttributes
687 | kWindowStandardHandlerAttribute
688 | kWindowLiveResizeAttribute
;
690 windowAttrs
&= (~kWindowResizableAttribute
);
692 if (theWindow
== NULL
)
694 quartz_CreateWindow(d_width
, d_height
, windowAttrs
);
696 if (theWindow
== NULL
)
698 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Couldn't create window !!!!!\n");
701 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
702 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
703 CGContextFillRect(context
, tmpBounds
);
707 HideWindow(theWindow
);
708 ChangeWindowAttributes(theWindow
, ~windowAttrs
, windowAttrs
);
709 SetRect(&winRect
, 0, 0, d_width
, d_height
);
710 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
711 SizeWindow (theWindow
, d_width
, d_height
, 1);
714 switch (image_format
)
718 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
720 dataProviderRef
= CGDataProviderCreateWithData (0, image_data
, imgRect
.right
* imgRect
.bottom
* 4, 0);
722 image
= CGImageCreate (imgRect
.right
,
726 ((imgRect
.right
*32)+7)/8,
727 CGColorSpaceCreateDeviceRGB(),
728 kCGImageAlphaNoneSkipFirst
,
729 dataProviderRef
, 0, 1, kCGRenderingIntentDefault
);
741 if (!EnterMoviesDone
)
743 qterr
= EnterMovies();
751 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: EnterMovies (%d)\n", qterr
);
756 SetIdentityMatrix(&matrix
);
758 if ((d_width
!= width
) || (d_height
!= height
))
760 ScaleMatrix(&matrix
, FixDiv(Long2Fix(d_width
),Long2Fix(width
)), FixDiv(Long2Fix(d_height
),Long2Fix(height
)), 0, 0);
763 yuv_qt_stuff
.desc
= (ImageDescriptionHandle
)NewHandleClear( sizeof(ImageDescription
) );
765 yuv_qt_stuff
.extension_colr
= NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension
));
766 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->colorParamType
= kVideoColorInfoImageDescriptionExtensionType
;
767 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->primaries
= 2;
768 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->transferFunction
= 2;
769 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->matrix
= 2;
771 yuv_qt_stuff
.extension_fiel
= NewHandleClear(sizeof(FieldInfoImageDescriptionExtension
));
772 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldCount
= 1;
773 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldOrderings
= 0;
775 yuv_qt_stuff
.extension_clap
= NewHandleClear(sizeof(CleanApertureImageDescriptionExtension
));
776 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthN
= imgRect
.right
;
777 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthD
= 1;
778 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightN
= imgRect
.bottom
;
779 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightD
= 1;
780 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffN
= 0;
781 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffD
= 1;
782 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffN
= 0;
783 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffD
= 1;
785 yuv_qt_stuff
.extension_pasp
= NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension
));
786 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->hSpacing
= 1;
787 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->vSpacing
= 1;
789 (*yuv_qt_stuff
.desc
)->idSize
= sizeof(ImageDescription
);
790 (*yuv_qt_stuff
.desc
)->cType
= image_qtcodec
;
791 (*yuv_qt_stuff
.desc
)->version
= 2;
792 (*yuv_qt_stuff
.desc
)->revisionLevel
= 0;
793 (*yuv_qt_stuff
.desc
)->vendor
= 'mpla';
794 (*yuv_qt_stuff
.desc
)->width
= imgRect
.right
;
795 (*yuv_qt_stuff
.desc
)->height
= imgRect
.bottom
;
796 (*yuv_qt_stuff
.desc
)->hRes
= Long2Fix(72);
797 (*yuv_qt_stuff
.desc
)->vRes
= Long2Fix(72);
798 (*yuv_qt_stuff
.desc
)->temporalQuality
= 0;
799 (*yuv_qt_stuff
.desc
)->spatialQuality
= codecLosslessQuality
;
800 (*yuv_qt_stuff
.desc
)->frameCount
= 1;
801 (*yuv_qt_stuff
.desc
)->dataSize
= 0;
802 (*yuv_qt_stuff
.desc
)->depth
= 24;
803 (*yuv_qt_stuff
.desc
)->clutID
= -1;
805 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_colr
, kColorInfoImageDescriptionExtension
);
808 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr
);
811 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_fiel
, kFieldInfoImageDescriptionExtension
);
814 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr
);
817 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_clap
, kCleanApertureImageDescriptionExtension
);
820 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr
);
823 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_pasp
, kCleanApertureImageDescriptionExtension
);
826 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr
);
828 if (P
!= NULL
) { // second or subsequent movie
831 P
= calloc(sizeof(PlanarPixmapInfoYUV420
) + image_size
, 1);
832 switch (image_format
)
837 P
->componentInfoY
.offset
= be2me_32(sizeof(PlanarPixmapInfoYUV420
));
838 P
->componentInfoCb
.offset
= be2me_32(be2me_32(P
->componentInfoY
.offset
) + image_size
/ 2);
839 P
->componentInfoCr
.offset
= be2me_32(be2me_32(P
->componentInfoCb
.offset
) + image_size
/ 4);
840 P
->componentInfoY
.rowBytes
= be2me_32(imgRect
.right
);
841 P
->componentInfoCb
.rowBytes
= be2me_32(imgRect
.right
/ 2);
842 P
->componentInfoCr
.rowBytes
= be2me_32(imgRect
.right
/ 2);
843 image_buffer_size
= image_size
+ sizeof(PlanarPixmapInfoYUV420
);
847 image_buffer_size
= image_size
;
851 qterr
= DecompressSequenceBeginS(&seqId
,
855 GetWindowPort(theWindow
),
858 ((d_width
!= width
) || (d_height
!= height
)) ?
863 codecLosslessQuality
,
868 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr
);
876 RepositionWindow(theWindow
, NULL
, kWindowCenterOnMainScreen
);
877 ShowWindow (theWindow
);
889 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
898 static void check_events(void)
901 EventTargetRef theTarget
;
905 theTarget
= GetEventDispatcherTarget();
906 theErr
= ReceiveNextEvent(0, 0, kEventDurationNoWait
,true, &theEvent
);
907 if(theErr
== noErr
&& theEvent
!= NULL
)
909 SendEventToEventTarget (theEvent
, theTarget
);
910 ReleaseEvent(theEvent
);
914 static void draw_osd(void)
916 vo_draw_text(imgRect
.right
,imgRect
.bottom
,draw_alpha
);
919 static void flip_page(void)
922 static int lastTime
= 0;
924 if(theWindow
== NULL
)
927 switch (image_format
)
931 CGContextDrawImage (context
, bounds
, image
);
943 CodecFlags flags
= 0;
944 qterr
= DecompressSequenceFrameWhen(seqId
,
947 0, //codecFlagUseImageBuffer,
953 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr
, flags
);
962 CGContextBeginPath(context
);
963 CGContextSetAllowsAntialiasing(context
, false);
964 //CGContextSaveGState(context);
967 CGContextSetRGBStrokeColor (context
, 0.2, 0.2, 0.2, 0.5);
968 CGContextMoveToPoint( context
, winRect
.right
-1, 1); CGContextAddLineToPoint( context
, winRect
.right
-1, 1);
969 CGContextMoveToPoint( context
, winRect
.right
-1, 5); CGContextAddLineToPoint( context
, winRect
.right
-5, 1);
970 CGContextMoveToPoint( context
, winRect
.right
-1, 9); CGContextAddLineToPoint( context
, winRect
.right
-9, 1);
971 CGContextStrokePath( context
);
974 CGContextSetRGBStrokeColor (context
, 0.4, 0.4, 0.4, 0.5);
975 CGContextMoveToPoint( context
, winRect
.right
-1, 2); CGContextAddLineToPoint( context
, winRect
.right
-2, 1);
976 CGContextMoveToPoint( context
, winRect
.right
-1, 6); CGContextAddLineToPoint( context
, winRect
.right
-6, 1);
977 CGContextMoveToPoint( context
, winRect
.right
-1, 10); CGContextAddLineToPoint( context
, winRect
.right
-10, 1);
978 CGContextStrokePath( context
);
981 CGContextSetRGBStrokeColor (context
, 0.6, 0.6, 0.6, 0.5);
982 CGContextMoveToPoint( context
, winRect
.right
-1, 3); CGContextAddLineToPoint( context
, winRect
.right
-3, 1);
983 CGContextMoveToPoint( context
, winRect
.right
-1, 7); CGContextAddLineToPoint( context
, winRect
.right
-7, 1);
984 CGContextMoveToPoint( context
, winRect
.right
-1, 11); CGContextAddLineToPoint( context
, winRect
.right
-11, 1);
985 CGContextStrokePath( context
);
987 //CGContextRestoreGState( context );
988 CGContextFlush (context
);
991 //auto hide mouse cursor and futur on-screen control?
992 if(vo_quartz_fs
&& !mouseHide
)
994 int curTime
= TickCount()/60;
995 static int lastTime
= 0;
997 if( ((curTime
- lastTime
) >= 5) || (lastTime
== 0) )
999 CGDisplayHideCursor(kCGDirectMainDisplay
);
1005 //update activity every 30 seconds to prevent
1006 //screensaver from starting up.
1007 curTime
= TickCount()/60;
1009 if( ((curTime
- lastTime
) >= 30) || (lastTime
== 0) )
1011 UpdateSystemActivity(UsrActivity
);
1016 static int draw_slice(uint8_t *src
[], int stride
[], int w
,int h
,int x
,int y
)
1018 switch (image_format
)
1022 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1023 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1025 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1026 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1030 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1031 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1033 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1034 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1040 static int draw_frame(uint8_t *src
[])
1042 switch (image_format
)
1045 fast_memcpy(image_data
,src
[0],image_size
);
1050 memcpy_pic(((char*)P
), src
[0], imgRect
.right
* 2, imgRect
.bottom
, imgRect
.right
* 2, imgRect
.right
* 2);
1056 static int query_format(uint32_t format
)
1058 image_format
= format
;
1061 if (format
== IMGFMT_RGB32
)
1063 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1066 if ((format
== IMGFMT_YV12
) || (format
== IMGFMT_IYUV
) || (format
== IMGFMT_I420
))
1068 image_qtcodec
= kMpegYUV420CodecType
; //kYUV420CodecType ?;
1069 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1072 if (format
== IMGFMT_YUY2
)
1074 image_qtcodec
= kComponentVideoUnsigned
;
1075 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1078 if (format
== IMGFMT_UYVY
)
1080 image_qtcodec
= k422YpCbCr8CodecType
;
1081 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1087 static void uninit(void)
1091 switch (image_format
)
1099 if (EnterMoviesDone
)
1101 qterr
= CDSequenceEnd(seqId
);
1104 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: CDSequenceEnd (%d)\n", qterr
);
1116 static int preinit(const char *arg
)
1122 char *parse_pos
= (char *)&arg
[0];
1123 while (parse_pos
[0] && !parse_err
)
1125 if (strncmp (parse_pos
, "device_id=", 10) == 0)
1127 parse_pos
= &parse_pos
[10];
1128 device_id
= strtol(parse_pos
, &parse_pos
, 0);
1130 if (strncmp (parse_pos
, "fs_res=", 7) == 0)
1132 parse_pos
= &parse_pos
[7];
1133 fs_res_x
= strtol(parse_pos
, &parse_pos
, 0);
1134 parse_pos
= &parse_pos
[1];
1135 fs_res_y
= strtol(parse_pos
, &parse_pos
, 0);
1137 if (parse_pos
[0] == ':') parse_pos
= &parse_pos
[1];
1138 else if (parse_pos
[0]) parse_err
= 1;
1142 #if !defined (MACOSX_FINDER_SUPPORT) || !defined (HAVE_SDL)
1143 //this chunk of code is heavily based off SDL_macosx.m from SDL
1144 //it uses an Apple private function to request foreground operation
1146 void CPSEnableForegroundOperation(ProcessSerialNumber
* psn
);
1147 ProcessSerialNumber myProc
, frProc
;
1150 if (GetFrontProcess(&frProc
) == noErr
)
1152 if (GetCurrentProcess(&myProc
) == noErr
)
1154 if (SameProcess(&frProc
, &myProc
, &sameProc
) == noErr
&& !sameProc
)
1156 CPSEnableForegroundOperation(&myProc
);
1158 SetFrontProcess(&myProc
);
1167 static uint32_t draw_yuv_image(mp_image_t
*mpi
)
1169 // ATM we're only called for planar IMGFMT
1170 // drawing is done directly in P
1171 // and displaying is in flip_page.
1172 return get_image_done
? VO_TRUE
: VO_FALSE
;
1175 static uint32_t get_yuv_image(mp_image_t
*mpi
)
1177 if(mpi
->type
!=MP_IMGTYPE_EXPORT
) return VO_FALSE
;
1179 if(mpi
->imgfmt
!=image_format
) return VO_FALSE
;
1181 if(mpi
->flags
&MP_IMGFLAG_PLANAR
)
1183 if (mpi
->num_planes
!= 3)
1185 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi
->num_planes
);
1189 mpi
->planes
[0]=((char*)P
) + be2me_32(P
->componentInfoY
.offset
);
1190 mpi
->stride
[0]=imgRect
.right
;
1191 mpi
->width
=imgRect
.right
;
1193 if(mpi
->flags
&MP_IMGFLAG_SWAPPED
)
1196 mpi
->planes
[1]=((char*)P
) + be2me_32(P
->componentInfoCb
.offset
);
1197 mpi
->planes
[2]=((char*)P
) + be2me_32(P
->componentInfoCr
.offset
);
1198 mpi
->stride
[1]=imgRect
.right
/2;
1199 mpi
->stride
[2]=imgRect
.right
/2;
1204 mpi
->planes
[1]=((char*)P
) + be2me_32(P
->componentInfoCr
.offset
);
1205 mpi
->planes
[2]=((char*)P
) + be2me_32(P
->componentInfoCb
.offset
);
1206 mpi
->stride
[1]=imgRect
.right
/2;
1207 mpi
->stride
[2]=imgRect
.right
/2;
1210 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1217 if (mpi
->num_planes
!= 1)
1219 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi
->num_planes
);
1223 mpi
->planes
[0] = (char*)P
;
1224 mpi
->stride
[0] = imgRect
.right
* 2;
1225 mpi
->width
=imgRect
.right
;
1226 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1233 static int control(uint32_t request
, void *data
)
1237 case VOCTRL_PAUSE
: return (int_pause
=1);
1238 case VOCTRL_RESUME
: return (int_pause
=0);
1239 case VOCTRL_FULLSCREEN
: vo_fs
= (!(vo_fs
)); window_fullscreen(); return VO_TRUE
;
1240 case VOCTRL_ONTOP
: vo_ontop
= (!(vo_ontop
)); window_ontop(); return VO_TRUE
;
1241 case VOCTRL_QUERY_FORMAT
: return query_format(*((uint32_t*)data
));
1242 case VOCTRL_GET_PANSCAN
: return VO_TRUE
;
1243 case VOCTRL_SET_PANSCAN
: window_panscan(); return VO_TRUE
;
1245 case VOCTRL_GET_IMAGE
:
1246 switch (image_format
)
1253 return get_yuv_image(data
);
1258 case VOCTRL_DRAW_IMAGE
:
1259 switch (image_format
)
1266 return draw_yuv_image(data
);
1275 void window_resized()
1287 GetPortBounds( GetWindowPort(theWindow
), &winRect
);
1291 aspect( &d_width
, &d_height
, A_NOZOOM
);
1292 d_height
= ((float)d_width
/movie_aspect
);
1294 aspectX
= (float)((float)winRect
.right
/(float)d_width
);
1295 aspectY
= (float)((float)(winRect
.bottom
)/(float)d_height
);
1297 if((d_height
*aspectX
)>(winRect
.bottom
))
1299 padding
= (winRect
.right
- d_width
*aspectY
)/2;
1300 SetRect(&dstRect
, padding
, 0, d_width
*aspectY
+padding
, d_height
*aspectY
);
1304 padding
= ((winRect
.bottom
) - d_height
*aspectX
)/2;
1305 SetRect(&dstRect
, 0, padding
, (d_width
*aspectX
), d_height
*aspectX
+padding
);
1310 SetRect(&dstRect
, 0, 0, winRect
.right
, winRect
.bottom
);
1313 switch (image_format
)
1317 bounds
= CGRectMake(dstRect
.left
, dstRect
.top
, dstRect
.right
-dstRect
.left
, dstRect
.bottom
-dstRect
.top
);
1318 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
1327 long scale_X
= FixDiv(Long2Fix(dstRect
.right
- dstRect
.left
),Long2Fix(imgRect
.right
));
1328 long scale_Y
= FixDiv(Long2Fix(dstRect
.bottom
- dstRect
.top
),Long2Fix(imgRect
.bottom
));
1330 SetIdentityMatrix(&matrix
);
1331 if (((dstRect
.right
- dstRect
.left
) != imgRect
.right
) || ((dstRect
.bottom
- dstRect
.right
) != imgRect
.bottom
))
1333 ScaleMatrix(&matrix
, scale_X
, scale_Y
, 0, 0);
1337 TranslateMatrix(&matrix
, Long2Fix(dstRect
.left
), Long2Fix(dstRect
.top
));
1341 SetDSequenceMatrix(seqId
, &matrix
);
1349 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
1350 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
1351 CGContextFillRect(context
, tmpBounds
);
1358 //Cycle between level
1363 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
1366 void window_fullscreen()
1368 static Ptr restoreState
= NULL
;
1377 SetSystemUIMode( kUIModeAllHidden
, kUIOptionAutoShowMenuBar
);
1378 CGDisplayHideCursor(kCGDirectMainDisplay
);
1382 if(fs_res_x
!= 0 || fs_res_y
!= 0)
1384 BeginFullScreen( &restoreState
, deviceHdl
, &fs_res_x
, &fs_res_y
, NULL
, NULL
, 0);
1386 //Get Main device info///////////////////////////////////////////////////
1387 deviceRect
= (*deviceHdl
)->gdRect
;
1389 device_width
= deviceRect
.right
;
1390 device_height
= deviceRect
.bottom
;
1394 //save old window size
1397 GetWindowPortBounds(theWindow
, &oldWinRect
);
1398 GetWindowBounds(theWindow
, kWindowContentRgn
, &oldWinBounds
);
1403 ChangeWindowAttributes(theWindow
, kWindowNoShadowAttribute
, 0);
1404 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1405 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);
1409 else //go back to windowed mode
1412 if(restoreState
!= NULL
)
1414 EndFullScreen(restoreState
, 0);
1416 //Get Main device info///////////////////////////////////////////////////
1417 deviceRect
= (*deviceHdl
)->gdRect
;
1419 device_width
= deviceRect
.right
;
1420 device_height
= deviceRect
.bottom
;
1421 restoreState
= NULL
;
1423 SetSystemUIMode( kUIModeNormal
, 0);
1426 CGDisplayShowCursor(kCGDirectMainDisplay
);
1429 //revert window to previous setting
1430 ChangeWindowAttributes(theWindow
, 0, kWindowNoShadowAttribute
);
1431 SizeWindow(theWindow
, oldWinRect
.right
, oldWinRect
.bottom
,1);
1432 MoveWindow(theWindow
, oldWinBounds
.left
, oldWinBounds
.top
, 1);
1437 void window_panscan()
1442 CheckMenuItem (aspectMenu
, 2, 1);
1444 CheckMenuItem (aspectMenu
, 2, 0);
1448 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1449 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);