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 static float old_movie_aspect
;
75 static int winLevel
= 1;
78 kCGDesktopWindowLevelKey
,
79 kCGNormalWindowLevelKey
,
80 kCGScreenSaverWindowLevelKey
83 static int int_pause
= 0;
84 static float winAlpha
= 1;
85 static int mouseHide
= FALSE
;
87 static int device_width
;
88 static int device_height
;
91 static short fs_res_x
=0;
92 static short fs_res_y
=0;
94 static WindowRef theWindow
= NULL
;
95 static WindowGroupRef winGroup
= NULL
;
96 static CGContextRef context
;
98 static GDHandle deviceHdl
;
100 static CGDataProviderRef dataProviderRef
;
101 static CGImageRef image
;
103 static Rect imgRect
; // size of the original image (unscaled)
104 static Rect dstRect
; // size of the displayed image (after scaling)
105 static Rect winRect
; // size of the window containg the displayed image (include padding)
106 static Rect oldWinRect
; // size of the window containg the displayed image (include padding) when NOT in FS mode
107 static Rect deviceRect
; // size of the display device
108 static Rect oldWinBounds
;
110 static MenuRef windMenu
;
111 static MenuRef movMenu
;
112 static MenuRef aspectMenu
;
118 kNormalScreenCmd
= 3,
119 kDoubleScreenCmd
= 4,
128 #include "osdep/keycodes.h"
130 //PROTOTYPE/////////////////////////////////////////////////////////////////
131 static OSStatus
KeyEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
132 static OSStatus
MouseEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
133 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
134 void window_resized();
136 void window_fullscreen();
137 void window_panscan();
139 static inline int convert_key(UInt32 key
, UInt32 charcode
)
144 case QZ_RETURN
: return KEY_ENTER
;
145 case QZ_ESCAPE
: return KEY_ESC
;
146 case QZ_BACKSPACE
: return KEY_BACKSPACE
;
147 case QZ_LALT
: return KEY_BACKSPACE
;
148 case QZ_LCTRL
: return KEY_BACKSPACE
;
149 case QZ_LSHIFT
: return KEY_BACKSPACE
;
150 case QZ_F1
: return KEY_F
+1;
151 case QZ_F2
: return KEY_F
+2;
152 case QZ_F3
: return KEY_F
+3;
153 case QZ_F4
: return KEY_F
+4;
154 case QZ_F5
: return KEY_F
+5;
155 case QZ_F6
: return KEY_F
+6;
156 case QZ_F7
: return KEY_F
+7;
157 case QZ_F8
: return KEY_F
+8;
158 case QZ_F9
: return KEY_F
+9;
159 case QZ_F10
: return KEY_F
+10;
160 case QZ_F11
: return KEY_F
+11;
161 case QZ_F12
: return KEY_F
+12;
162 case QZ_INSERT
: return KEY_INSERT
;
163 case QZ_DELETE
: return KEY_DELETE
;
164 case QZ_HOME
: return KEY_HOME
;
165 case QZ_END
: return KEY_END
;
166 case QZ_KP_PLUS
: return '+';
167 case QZ_KP_MINUS
: return '-';
168 case QZ_TAB
: return KEY_TAB
;
169 case QZ_PAGEUP
: return KEY_PAGE_UP
;
170 case QZ_PAGEDOWN
: return KEY_PAGE_DOWN
;
171 case QZ_UP
: return KEY_UP
;
172 case QZ_DOWN
: return KEY_DOWN
;
173 case QZ_LEFT
: return KEY_LEFT
;
174 case QZ_RIGHT
: return KEY_RIGHT
;
175 case QZ_KP_MULTIPLY
: return '*';
176 case QZ_KP_DIVIDE
: return '/';
177 case QZ_KP_ENTER
: return KEY_KPENTER
;
178 case QZ_KP_PERIOD
: return KEY_KPDEC
;
179 case QZ_KP0
: return KEY_KP0
;
180 case QZ_KP1
: return KEY_KP1
;
181 case QZ_KP2
: return KEY_KP2
;
182 case QZ_KP3
: return KEY_KP3
;
183 case QZ_KP4
: return KEY_KP4
;
184 case QZ_KP5
: return KEY_KP5
;
185 case QZ_KP6
: return KEY_KP6
;
186 case QZ_KP7
: return KEY_KP7
;
187 case QZ_KP8
: return KEY_KP8
;
188 case QZ_KP9
: return KEY_KP9
;
189 default: return charcode
;
193 static void draw_alpha(int x0
, int y0
, int w
, int h
, unsigned char *src
, unsigned char *srca
, int stride
)
195 switch (image_format
)
198 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,image_data
+4*(y0
*imgRect
.right
+x0
),4*imgRect
.right
);
203 vo_draw_alpha_yv12(w
,h
,src
,srca
,stride
, ((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x0
+ y0
* imgRect
.right
, imgRect
.right
);
206 vo_draw_alpha_uyvy(w
,h
,src
,srca
,stride
,((char*)P
) + (x0
+ y0
* imgRect
.right
) * 2,imgRect
.right
*2);
209 vo_draw_alpha_yuy2(w
,h
,src
,srca
,stride
,((char*)P
) + (x0
+ y0
* imgRect
.right
) * 2,imgRect
.right
*2);
214 //default keyboard event handler
215 static OSStatus
KeyEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
217 OSStatus result
= noErr
;
218 UInt32
class = GetEventClass (event
);
219 UInt32 kind
= GetEventKind (event
);
221 result
= CallNextEventHandler(nextHandler
, event
);
223 if(class == kEventClassKeyboard
)
227 UInt32 macKeyModifiers
;
229 GetEventParameter(event
, kEventParamKeyMacCharCodes
, typeChar
, NULL
, sizeof(macCharCodes
), NULL
, &macCharCodes
);
230 GetEventParameter(event
, kEventParamKeyCode
, typeUInt32
, NULL
, sizeof(macKeyCode
), NULL
, &macKeyCode
);
231 GetEventParameter(event
, kEventParamKeyModifiers
, typeUInt32
, NULL
, sizeof(macKeyModifiers
), NULL
, &macKeyModifiers
);
233 if(macKeyModifiers
!= 256)
235 if (kind
== kEventRawKeyRepeat
|| kind
== kEventRawKeyDown
)
237 int key
= convert_key(macKeyCode
, macCharCodes
);
239 mplayer_put_key(key
);
242 else if(macKeyModifiers
== 256)
246 case '[': SetWindowAlpha(theWindow
, winAlpha
-=0.05); break;
247 case ']': SetWindowAlpha(theWindow
, winAlpha
+=0.05); break;
251 result
= eventNotHandledErr
;
257 //default mouse event handler
258 static OSStatus
MouseEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
260 OSStatus result
= noErr
;
261 UInt32
class = GetEventClass (event
);
262 UInt32 kind
= GetEventKind (event
);
264 result
= CallNextEventHandler(nextHandler
, event
);
266 if(class == kEventClassMouse
)
272 GetEventParameter(event
, kEventParamMouseLocation
, typeQDPoint
, 0, sizeof(Point
), 0, &mousePos
);
273 GetEventParameter(event
, kEventParamWindowMouseLocation
, typeQDPoint
, 0, sizeof(Point
), 0, &winMousePos
);
277 case kEventMouseMoved
:
281 CGDisplayShowCursor(kCGDirectMainDisplay
);
287 case kEventMouseWheelMoved
:
292 GetEventParameter(event
, kEventParamMouseWheelDelta
, typeSInt32
, 0, sizeof(int), 0, &wheel
);
294 part
= FindWindow(mousePos
,&tmpWin
);
296 if(part
== inContent
)
299 mplayer_put_key(MOUSE_BTN3
);
301 mplayer_put_key(MOUSE_BTN4
);
306 case kEventMouseDown
:
309 EventMouseButton button
;
313 GetWindowPortBounds(theWindow
, &bounds
);
314 GetEventParameter(event
, kEventParamMouseButton
, typeMouseButton
, 0, sizeof(EventMouseButton
), 0, &button
);
316 part
= FindWindow(mousePos
,&tmpWin
);
317 if(kind
== kEventMouseUp
)
319 if (part
!= inContent
)
323 case kEventMouseButtonPrimary
:
324 mplayer_put_key(MOUSE_BTN0
);
326 case kEventMouseButtonSecondary
:
327 mplayer_put_key(MOUSE_BTN2
);
329 case kEventMouseButtonTertiary
:
330 mplayer_put_key(MOUSE_BTN1
);
333 default:result
= eventNotHandledErr
;break;
337 if( (winMousePos
.h
> (bounds
.right
- 15)) && (winMousePos
.v
> (bounds
.bottom
)) )
341 GrowWindow(theWindow
, mousePos
, NULL
);
344 else if(part
== inMenuBar
)
346 MenuSelect(mousePos
);
349 else if(part
== inContent
)
353 case kEventMouseButtonPrimary
:
354 mplayer_put_key(MOUSE_BTN0
| MP_KEY_DOWN
);
356 case kEventMouseButtonSecondary
:
357 mplayer_put_key(MOUSE_BTN2
| MP_KEY_DOWN
);
359 case kEventMouseButtonTertiary
:
360 mplayer_put_key(MOUSE_BTN1
| MP_KEY_DOWN
);
363 default:result
= eventNotHandledErr
;break;
369 case kEventMouseDragged
:
372 default:result
= eventNotHandledErr
;break;
379 //default window event handler
380 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
382 OSStatus result
= noErr
;
385 UInt32
class = GetEventClass (event
);
386 UInt32 kind
= GetEventKind (event
);
388 result
= CallNextEventHandler(nextHandler
, event
);
390 aspect(&d_width
,&d_height
,A_NOZOOM
);
392 if(class == kEventClassCommand
)
394 HICommand theHICommand
;
395 GetEventParameter( event
, kEventParamDirectObject
, typeHICommand
, NULL
, sizeof( HICommand
), NULL
, &theHICommand
);
397 switch ( theHICommand
.commandID
)
400 mplayer_put_key(KEY_CLOSE_WIN
);
406 vo_fs
= (!(vo_fs
)); window_fullscreen();
409 SizeWindow(theWindow
, (d_width
/2), ((d_width
/movie_aspect
)/2), 1);
413 case kNormalScreenCmd
:
416 vo_fs
= (!(vo_fs
)); window_fullscreen();
419 SizeWindow(theWindow
, d_width
, (d_width
/movie_aspect
), 1);
423 case kDoubleScreenCmd
:
426 vo_fs
= (!(vo_fs
)); window_fullscreen();
429 SizeWindow(theWindow
, (d_width
*2), ((d_width
/movie_aspect
)*2), 1);
434 vo_fs
= (!(vo_fs
)); window_fullscreen();
438 vo_keepaspect
= (!(vo_keepaspect
));
439 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
444 movie_aspect
= old_movie_aspect
;
447 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
453 movie_aspect
= 4.0f
/3.0f
;
456 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
462 movie_aspect
= 16.0f
/9.0f
;
465 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
471 vo_panscan
= (!(vo_panscan
));
472 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
478 result
= eventNotHandledErr
;
482 else if(class == kEventClassWindow
)
485 Rect rectPort
= {0,0,0,0};
487 GetEventParameter(event
, kEventParamDirectObject
, typeWindowRef
, NULL
, sizeof(WindowRef
), NULL
, &window
);
491 GetPortBounds(GetWindowPort(window
), &rectPort
);
496 case kEventWindowClosed
:
498 mplayer_put_key(KEY_CLOSE_WIN
);
502 case kEventWindowZoomed
:
503 case kEventWindowBoundsChanged
:
510 result
= eventNotHandledErr
;
518 static void quartz_CreateWindow(uint32_t d_width
, uint32_t d_height
, WindowAttributes windowAttrs
)
520 CFStringRef titleKey
;
521 CFStringRef windowTitle
;
525 CFStringRef movMenuTitle
;
526 CFStringRef aspMenuTitle
;
528 const EventTypeSpec win_events
[] = {
529 { kEventClassWindow
, kEventWindowClosed
},
530 { kEventClassWindow
, kEventWindowBoundsChanged
},
531 { kEventClassCommand
, kEventCommandProcess
}
534 const EventTypeSpec key_events
[] = {
535 { kEventClassKeyboard
, kEventRawKeyDown
},
536 { kEventClassKeyboard
, kEventRawKeyRepeat
}
539 const EventTypeSpec mouse_events
[] = {
540 { kEventClassMouse
, kEventMouseMoved
},
541 { kEventClassMouse
, kEventMouseWheelMoved
},
542 { kEventClassMouse
, kEventMouseDown
},
543 { kEventClassMouse
, kEventMouseUp
},
544 { kEventClassMouse
, kEventMouseDragged
}
547 SetRect(&winRect
, 0, 0, d_width
, d_height
);
548 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
549 SetRect(&dstRect
, 0, 0, d_width
, d_height
);
555 CreateStandardWindowMenu(0, &windMenu
);
556 InsertMenu(windMenu
, 0);
559 CreateNewMenu (1004, 0, &movMenu
);
560 movMenuTitle
= CFSTR("Movie");
561 SetMenuTitleWithCFString(movMenu
, movMenuTitle
);
563 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Half Size"), 0, kHalfScreenCmd
, &index
);
564 SetMenuItemCommandKey(movMenu
, index
, 0, '0');
566 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Normal Size"), 0, kNormalScreenCmd
, &index
);
567 SetMenuItemCommandKey(movMenu
, index
, 0, '1');
569 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Double Size"), 0, kDoubleScreenCmd
, &index
);
570 SetMenuItemCommandKey(movMenu
, index
, 0, '2');
572 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Full Size"), 0, kFullScreenCmd
, &index
);
573 SetMenuItemCommandKey(movMenu
, index
, 0, 'F');
575 AppendMenuItemTextWithCFString(movMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
577 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Aspect Ratio"), 0, 0, &index
);
579 ////Create Aspect Ratio Sub Menu
580 CreateNewMenu (0, 0, &aspectMenu
);
581 aspMenuTitle
= CFSTR("Aspect Ratio");
582 SetMenuTitleWithCFString(aspectMenu
, aspMenuTitle
);
583 SetMenuItemHierarchicalMenu(movMenu
, 6, aspectMenu
);
585 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Keep"), 0, kKeepAspectCmd
, &index
);
586 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
587 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Pan-Scan"), 0, kPanScanCmd
, &index
);
588 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
589 AppendMenuItemTextWithCFString(aspectMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
590 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Original"), 0, kAspectOrgCmd
, &index
);
591 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("4:3"), 0, kAspectFullCmd
, &index
);
592 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("16:9"), 0, kAspectWideCmd
, &index
);
594 InsertMenu(movMenu
, GetMenuID(windMenu
)); //insert before Window menu
599 CreateNewWindow(kDocumentWindowClass
, windowAttrs
, &winRect
, &theWindow
);
601 CreateWindowGroup(0, &winGroup
);
602 SetWindowGroup(theWindow
, winGroup
);
605 titleKey
= CFSTR("MPlayer - The Movie Player");
606 windowTitle
= CFCopyLocalizedString(titleKey
, NULL
);
607 result
= SetWindowTitleWithCFString(theWindow
, windowTitle
);
609 CFRelease(windowTitle
);
611 //Install event handler
612 InstallApplicationEventHandler (NewEventHandlerUPP (KeyEventHandler
), GetEventTypeCount(key_events
), key_events
, NULL
, NULL
);
613 InstallApplicationEventHandler (NewEventHandlerUPP (MouseEventHandler
), GetEventTypeCount(mouse_events
), mouse_events
, NULL
, NULL
);
614 InstallWindowEventHandler (theWindow
, NewEventHandlerUPP (WindowEventHandler
), GetEventTypeCount(win_events
), win_events
, theWindow
, NULL
);
617 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
)
619 WindowAttributes windowAttrs
;
624 //Get Main device info///////////////////////////////////////////////////
627 deviceHdl
= GetMainDevice();
629 for(i
=0; i
<device_id
; i
++)
631 deviceHdl
= GetNextDevice(deviceHdl
);
633 if(deviceHdl
== NULL
)
635 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id
);
636 deviceHdl
= GetMainDevice();
642 deviceRect
= (*deviceHdl
)->gdRect
;
643 device_width
= deviceRect
.right
-deviceRect
.left
;
644 device_height
= deviceRect
.bottom
-deviceRect
.top
;
646 monitor_aspect
= (float)device_width
/(float)device_height
;
648 //misc mplayer setup/////////////////////////////////////////////////////
649 SetRect(&imgRect
, 0, 0, width
, height
);
650 switch (image_format
)
663 image_size
= ((imgRect
.right
*imgRect
.bottom
*image_depth
)+7)/8;
665 vo_fs
= flags
& VOFLAG_FULLSCREEN
;
669 aspect_save_orig(width
,height
);
670 aspect_save_prescale(d_width
,d_height
);
671 aspect_save_screenres(device_width
, device_height
);
673 aspect(&d_width
,&d_height
,A_NOZOOM
);
675 movie_aspect
= (float)d_width
/(float)d_height
;
676 old_movie_aspect
= movie_aspect
;
681 image_data
= malloc(image_size
);
683 //Create player window//////////////////////////////////////////////////
684 windowAttrs
= kWindowStandardDocumentAttributes
685 | kWindowStandardHandlerAttribute
686 | kWindowLiveResizeAttribute
;
688 windowAttrs
&= (~kWindowResizableAttribute
);
690 if (theWindow
== NULL
)
692 quartz_CreateWindow(d_width
, d_height
, windowAttrs
);
694 if (theWindow
== NULL
)
696 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Couldn't create window !!!!!\n");
699 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
700 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
701 CGContextFillRect(context
, tmpBounds
);
705 HideWindow(theWindow
);
706 ChangeWindowAttributes(theWindow
, ~windowAttrs
, windowAttrs
);
707 SetRect(&winRect
, 0, 0, d_width
, d_height
);
708 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
709 SizeWindow (theWindow
, d_width
, d_height
, 1);
712 switch (image_format
)
716 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
718 dataProviderRef
= CGDataProviderCreateWithData (0, image_data
, imgRect
.right
* imgRect
.bottom
* 4, 0);
720 image
= CGImageCreate (imgRect
.right
,
724 ((imgRect
.right
*32)+7)/8,
725 CGColorSpaceCreateDeviceRGB(),
726 kCGImageAlphaNoneSkipFirst
,
727 dataProviderRef
, 0, 1, kCGRenderingIntentDefault
);
739 if (!EnterMoviesDone
)
741 qterr
= EnterMovies();
749 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: EnterMovies (%d)\n", qterr
);
754 SetIdentityMatrix(&matrix
);
756 if ((d_width
!= width
) || (d_height
!= height
))
758 ScaleMatrix(&matrix
, FixDiv(Long2Fix(d_width
),Long2Fix(width
)), FixDiv(Long2Fix(d_height
),Long2Fix(height
)), 0, 0);
761 yuv_qt_stuff
.desc
= (ImageDescriptionHandle
)NewHandleClear( sizeof(ImageDescription
) );
763 yuv_qt_stuff
.extension_colr
= NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension
));
764 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->colorParamType
= kVideoColorInfoImageDescriptionExtensionType
;
765 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->primaries
= 2;
766 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->transferFunction
= 2;
767 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->matrix
= 2;
769 yuv_qt_stuff
.extension_fiel
= NewHandleClear(sizeof(FieldInfoImageDescriptionExtension
));
770 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldCount
= 1;
771 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldOrderings
= 0;
773 yuv_qt_stuff
.extension_clap
= NewHandleClear(sizeof(CleanApertureImageDescriptionExtension
));
774 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthN
= imgRect
.right
;
775 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthD
= 1;
776 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightN
= imgRect
.bottom
;
777 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightD
= 1;
778 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffN
= 0;
779 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffD
= 1;
780 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffN
= 0;
781 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffD
= 1;
783 yuv_qt_stuff
.extension_pasp
= NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension
));
784 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->hSpacing
= 1;
785 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->vSpacing
= 1;
787 (*yuv_qt_stuff
.desc
)->idSize
= sizeof(ImageDescription
);
788 (*yuv_qt_stuff
.desc
)->cType
= image_qtcodec
;
789 (*yuv_qt_stuff
.desc
)->version
= 2;
790 (*yuv_qt_stuff
.desc
)->revisionLevel
= 0;
791 (*yuv_qt_stuff
.desc
)->vendor
= 'mpla';
792 (*yuv_qt_stuff
.desc
)->width
= imgRect
.right
;
793 (*yuv_qt_stuff
.desc
)->height
= imgRect
.bottom
;
794 (*yuv_qt_stuff
.desc
)->hRes
= Long2Fix(72);
795 (*yuv_qt_stuff
.desc
)->vRes
= Long2Fix(72);
796 (*yuv_qt_stuff
.desc
)->temporalQuality
= 0;
797 (*yuv_qt_stuff
.desc
)->spatialQuality
= codecLosslessQuality
;
798 (*yuv_qt_stuff
.desc
)->frameCount
= 1;
799 (*yuv_qt_stuff
.desc
)->dataSize
= 0;
800 (*yuv_qt_stuff
.desc
)->depth
= 24;
801 (*yuv_qt_stuff
.desc
)->clutID
= -1;
803 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_colr
, kColorInfoImageDescriptionExtension
);
806 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr
);
809 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_fiel
, kFieldInfoImageDescriptionExtension
);
812 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr
);
815 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_clap
, kCleanApertureImageDescriptionExtension
);
818 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr
);
821 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_pasp
, kCleanApertureImageDescriptionExtension
);
824 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr
);
826 if (P
!= NULL
) { // second or subsequent movie
829 P
= calloc(sizeof(PlanarPixmapInfoYUV420
) + image_size
, 1);
830 switch (image_format
)
835 P
->componentInfoY
.offset
= be2me_32(sizeof(PlanarPixmapInfoYUV420
));
836 P
->componentInfoCb
.offset
= be2me_32(be2me_32(P
->componentInfoY
.offset
) + image_size
/ 2);
837 P
->componentInfoCr
.offset
= be2me_32(be2me_32(P
->componentInfoCb
.offset
) + image_size
/ 4);
838 P
->componentInfoY
.rowBytes
= be2me_32(imgRect
.right
);
839 P
->componentInfoCb
.rowBytes
= be2me_32(imgRect
.right
/ 2);
840 P
->componentInfoCr
.rowBytes
= be2me_32(imgRect
.right
/ 2);
841 image_buffer_size
= image_size
+ sizeof(PlanarPixmapInfoYUV420
);
845 image_buffer_size
= image_size
;
849 qterr
= DecompressSequenceBeginS(&seqId
,
853 GetWindowPort(theWindow
),
856 ((d_width
!= width
) || (d_height
!= height
)) ?
861 codecLosslessQuality
,
866 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr
);
874 RepositionWindow(theWindow
, NULL
, kWindowCenterOnMainScreen
);
875 ShowWindow (theWindow
);
887 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
896 static void check_events(void)
899 EventTargetRef theTarget
;
903 theTarget
= GetEventDispatcherTarget();
904 theErr
= ReceiveNextEvent(0, 0, kEventDurationNoWait
,true, &theEvent
);
905 if(theErr
== noErr
&& theEvent
!= NULL
)
907 SendEventToEventTarget (theEvent
, theTarget
);
908 ReleaseEvent(theEvent
);
912 static void draw_osd(void)
914 vo_draw_text(imgRect
.right
,imgRect
.bottom
,draw_alpha
);
917 static void flip_page(void)
920 static int lastTime
= 0;
922 if(theWindow
== NULL
)
925 switch (image_format
)
929 CGContextDrawImage (context
, bounds
, image
);
941 CodecFlags flags
= 0;
942 qterr
= DecompressSequenceFrameWhen(seqId
,
945 0, //codecFlagUseImageBuffer,
951 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr
, flags
);
960 CGContextBeginPath(context
);
961 CGContextSetAllowsAntialiasing(context
, false);
962 //CGContextSaveGState(context);
965 CGContextSetRGBStrokeColor (context
, 0.2, 0.2, 0.2, 0.5);
966 CGContextMoveToPoint( context
, winRect
.right
-1, 1); CGContextAddLineToPoint( context
, winRect
.right
-1, 1);
967 CGContextMoveToPoint( context
, winRect
.right
-1, 5); CGContextAddLineToPoint( context
, winRect
.right
-5, 1);
968 CGContextMoveToPoint( context
, winRect
.right
-1, 9); CGContextAddLineToPoint( context
, winRect
.right
-9, 1);
969 CGContextStrokePath( context
);
972 CGContextSetRGBStrokeColor (context
, 0.4, 0.4, 0.4, 0.5);
973 CGContextMoveToPoint( context
, winRect
.right
-1, 2); CGContextAddLineToPoint( context
, winRect
.right
-2, 1);
974 CGContextMoveToPoint( context
, winRect
.right
-1, 6); CGContextAddLineToPoint( context
, winRect
.right
-6, 1);
975 CGContextMoveToPoint( context
, winRect
.right
-1, 10); CGContextAddLineToPoint( context
, winRect
.right
-10, 1);
976 CGContextStrokePath( context
);
979 CGContextSetRGBStrokeColor (context
, 0.6, 0.6, 0.6, 0.5);
980 CGContextMoveToPoint( context
, winRect
.right
-1, 3); CGContextAddLineToPoint( context
, winRect
.right
-3, 1);
981 CGContextMoveToPoint( context
, winRect
.right
-1, 7); CGContextAddLineToPoint( context
, winRect
.right
-7, 1);
982 CGContextMoveToPoint( context
, winRect
.right
-1, 11); CGContextAddLineToPoint( context
, winRect
.right
-11, 1);
983 CGContextStrokePath( context
);
985 //CGContextRestoreGState( context );
986 CGContextFlush (context
);
989 //auto hide mouse cursor and futur on-screen control?
990 if(vo_quartz_fs
&& !mouseHide
)
992 int curTime
= TickCount()/60;
993 static int lastTime
= 0;
995 if( ((curTime
- lastTime
) >= 5) || (lastTime
== 0) )
997 CGDisplayHideCursor(kCGDirectMainDisplay
);
1003 //update activity every 30 seconds to prevent
1004 //screensaver from starting up.
1005 curTime
= TickCount()/60;
1007 if( ((curTime
- lastTime
) >= 30) || (lastTime
== 0) )
1009 UpdateSystemActivity(UsrActivity
);
1014 static int draw_slice(uint8_t *src
[], int stride
[], int w
,int h
,int x
,int y
)
1016 switch (image_format
)
1020 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1021 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1023 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1024 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1028 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1029 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1031 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1032 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1038 static int draw_frame(uint8_t *src
[])
1040 switch (image_format
)
1043 fast_memcpy(image_data
,src
[0],image_size
);
1048 memcpy_pic(((char*)P
), src
[0], imgRect
.right
* 2, imgRect
.bottom
, imgRect
.right
* 2, imgRect
.right
* 2);
1054 static int query_format(uint32_t format
)
1056 image_format
= format
;
1059 if (format
== IMGFMT_RGB32
)
1061 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1064 if ((format
== IMGFMT_YV12
) || (format
== IMGFMT_IYUV
) || (format
== IMGFMT_I420
))
1066 image_qtcodec
= kMpegYUV420CodecType
; //kYUV420CodecType ?;
1067 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1070 if (format
== IMGFMT_YUY2
)
1072 image_qtcodec
= kComponentVideoUnsigned
;
1073 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1076 if (format
== IMGFMT_UYVY
)
1078 image_qtcodec
= k422YpCbCr8CodecType
;
1079 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1085 static void uninit(void)
1089 switch (image_format
)
1097 if (EnterMoviesDone
)
1099 qterr
= CDSequenceEnd(seqId
);
1102 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: CDSequenceEnd (%d)\n", qterr
);
1114 static int preinit(const char *arg
)
1120 char *parse_pos
= (char *)&arg
[0];
1121 while (parse_pos
[0] && !parse_err
)
1123 if (strncmp (parse_pos
, "device_id=", 10) == 0)
1125 parse_pos
= &parse_pos
[10];
1126 device_id
= strtol(parse_pos
, &parse_pos
, 0);
1128 if (strncmp (parse_pos
, "fs_res=", 7) == 0)
1130 parse_pos
= &parse_pos
[7];
1131 fs_res_x
= strtol(parse_pos
, &parse_pos
, 0);
1132 parse_pos
= &parse_pos
[1];
1133 fs_res_y
= strtol(parse_pos
, &parse_pos
, 0);
1135 if (parse_pos
[0] == ':') parse_pos
= &parse_pos
[1];
1136 else if (parse_pos
[0]) parse_err
= 1;
1140 #if !defined (MACOSX_FINDER_SUPPORT) || !defined (HAVE_SDL)
1141 //this chunk of code is heavily based off SDL_macosx.m from SDL
1142 //it uses an Apple private function to request foreground operation
1144 void CPSEnableForegroundOperation(ProcessSerialNumber
* psn
);
1145 ProcessSerialNumber myProc
, frProc
;
1148 if (GetFrontProcess(&frProc
) == noErr
)
1150 if (GetCurrentProcess(&myProc
) == noErr
)
1152 if (SameProcess(&frProc
, &myProc
, &sameProc
) == noErr
&& !sameProc
)
1154 CPSEnableForegroundOperation(&myProc
);
1156 SetFrontProcess(&myProc
);
1165 static uint32_t draw_yuv_image(mp_image_t
*mpi
)
1167 // ATM we're only called for planar IMGFMT
1168 // drawing is done directly in P
1169 // and displaying is in flip_page.
1170 return get_image_done
? VO_TRUE
: VO_FALSE
;
1173 static uint32_t get_yuv_image(mp_image_t
*mpi
)
1175 if(mpi
->type
!=MP_IMGTYPE_EXPORT
) return VO_FALSE
;
1177 if(mpi
->imgfmt
!=image_format
) return VO_FALSE
;
1179 if(mpi
->flags
&MP_IMGFLAG_PLANAR
)
1181 if (mpi
->num_planes
!= 3)
1183 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi
->num_planes
);
1187 mpi
->planes
[0]=((char*)P
) + be2me_32(P
->componentInfoY
.offset
);
1188 mpi
->stride
[0]=imgRect
.right
;
1189 mpi
->width
=imgRect
.right
;
1191 if(mpi
->flags
&MP_IMGFLAG_SWAPPED
)
1194 mpi
->planes
[1]=((char*)P
) + be2me_32(P
->componentInfoCb
.offset
);
1195 mpi
->planes
[2]=((char*)P
) + be2me_32(P
->componentInfoCr
.offset
);
1196 mpi
->stride
[1]=imgRect
.right
/2;
1197 mpi
->stride
[2]=imgRect
.right
/2;
1202 mpi
->planes
[1]=((char*)P
) + be2me_32(P
->componentInfoCr
.offset
);
1203 mpi
->planes
[2]=((char*)P
) + be2me_32(P
->componentInfoCb
.offset
);
1204 mpi
->stride
[1]=imgRect
.right
/2;
1205 mpi
->stride
[2]=imgRect
.right
/2;
1208 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1215 if (mpi
->num_planes
!= 1)
1217 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi
->num_planes
);
1221 mpi
->planes
[0] = (char*)P
;
1222 mpi
->stride
[0] = imgRect
.right
* 2;
1223 mpi
->width
=imgRect
.right
;
1224 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1231 static int control(uint32_t request
, void *data
)
1235 case VOCTRL_PAUSE
: return int_pause
= 1;
1236 case VOCTRL_RESUME
: return int_pause
= 0;
1237 case VOCTRL_FULLSCREEN
: vo_fs
= (!(vo_fs
)); window_fullscreen(); return VO_TRUE
;
1238 case VOCTRL_ONTOP
: vo_ontop
= (!(vo_ontop
)); window_ontop(); return VO_TRUE
;
1239 case VOCTRL_QUERY_FORMAT
: return query_format(*((uint32_t*)data
));
1240 case VOCTRL_GET_PANSCAN
: return VO_TRUE
;
1241 case VOCTRL_SET_PANSCAN
: window_panscan(); return VO_TRUE
;
1243 case VOCTRL_GET_IMAGE
:
1244 switch (image_format
)
1251 return get_yuv_image(data
);
1256 case VOCTRL_DRAW_IMAGE
:
1257 switch (image_format
)
1264 return draw_yuv_image(data
);
1273 void window_resized()
1285 GetPortBounds( GetWindowPort(theWindow
), &winRect
);
1289 aspect( &d_width
, &d_height
, A_NOZOOM
);
1290 d_height
= ((float)d_width
/movie_aspect
);
1292 aspectX
= (float)((float)winRect
.right
/(float)d_width
);
1293 aspectY
= (float)((float)(winRect
.bottom
)/(float)d_height
);
1295 if((d_height
*aspectX
)>(winRect
.bottom
))
1297 padding
= (winRect
.right
- d_width
*aspectY
)/2;
1298 SetRect(&dstRect
, padding
, 0, d_width
*aspectY
+padding
, d_height
*aspectY
);
1302 padding
= ((winRect
.bottom
) - d_height
*aspectX
)/2;
1303 SetRect(&dstRect
, 0, padding
, (d_width
*aspectX
), d_height
*aspectX
+padding
);
1308 SetRect(&dstRect
, 0, 0, winRect
.right
, winRect
.bottom
);
1311 switch (image_format
)
1315 bounds
= CGRectMake(dstRect
.left
, dstRect
.top
, dstRect
.right
-dstRect
.left
, dstRect
.bottom
-dstRect
.top
);
1316 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
1325 long scale_X
= FixDiv(Long2Fix(dstRect
.right
- dstRect
.left
),Long2Fix(imgRect
.right
));
1326 long scale_Y
= FixDiv(Long2Fix(dstRect
.bottom
- dstRect
.top
),Long2Fix(imgRect
.bottom
));
1328 SetIdentityMatrix(&matrix
);
1329 if (((dstRect
.right
- dstRect
.left
) != imgRect
.right
) || ((dstRect
.bottom
- dstRect
.right
) != imgRect
.bottom
))
1331 ScaleMatrix(&matrix
, scale_X
, scale_Y
, 0, 0);
1335 TranslateMatrix(&matrix
, Long2Fix(dstRect
.left
), Long2Fix(dstRect
.top
));
1339 SetDSequenceMatrix(seqId
, &matrix
);
1347 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
1348 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
1349 CGContextFillRect(context
, tmpBounds
);
1356 //Cycle between level
1361 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
1364 void window_fullscreen()
1366 static Ptr restoreState
= NULL
;
1375 SetSystemUIMode( kUIModeAllHidden
, kUIOptionAutoShowMenuBar
);
1376 CGDisplayHideCursor(kCGDirectMainDisplay
);
1380 if(fs_res_x
!= 0 || fs_res_y
!= 0)
1382 BeginFullScreen( &restoreState
, deviceHdl
, &fs_res_x
, &fs_res_y
, NULL
, NULL
, 0);
1384 //Get Main device info///////////////////////////////////////////////////
1385 deviceRect
= (*deviceHdl
)->gdRect
;
1387 device_width
= deviceRect
.right
;
1388 device_height
= deviceRect
.bottom
;
1392 //save old window size
1395 GetWindowPortBounds(theWindow
, &oldWinRect
);
1396 GetWindowBounds(theWindow
, kWindowContentRgn
, &oldWinBounds
);
1401 ChangeWindowAttributes(theWindow
, kWindowNoShadowAttribute
, 0);
1402 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1403 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);
1407 else //go back to windowed mode
1410 if(restoreState
!= NULL
)
1412 EndFullScreen(restoreState
, 0);
1414 //Get Main device info///////////////////////////////////////////////////
1415 deviceRect
= (*deviceHdl
)->gdRect
;
1417 device_width
= deviceRect
.right
;
1418 device_height
= deviceRect
.bottom
;
1419 restoreState
= NULL
;
1421 SetSystemUIMode( kUIModeNormal
, 0);
1424 CGDisplayShowCursor(kCGDirectMainDisplay
);
1427 //revert window to previous setting
1428 ChangeWindowAttributes(theWindow
, 0, kWindowNoShadowAttribute
);
1429 SizeWindow(theWindow
, oldWinRect
.right
, oldWinRect
.bottom
,1);
1430 MoveWindow(theWindow
, oldWinBounds
.left
, oldWinBounds
.top
, 1);
1435 void window_panscan()
1440 CheckMenuItem (aspectMenu
, 2, 1);
1442 CheckMenuItem (aspectMenu
, 2, 0);
1446 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1447 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);