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 extern void vo_draw_text(int dxs
,int dys
,void (*draw_alpha
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
));
134 //PROTOTYPE/////////////////////////////////////////////////////////////////
135 static OSStatus
KeyEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
136 static OSStatus
MouseEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
137 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
138 void window_resized();
140 void window_fullscreen();
141 void window_panscan();
143 static inline int convert_key(UInt32 key
, UInt32 charcode
)
148 case QZ_RETURN
: return KEY_ENTER
;
149 case QZ_ESCAPE
: return KEY_ESC
;
150 case QZ_BACKSPACE
: return KEY_BACKSPACE
;
151 case QZ_LALT
: return KEY_BACKSPACE
;
152 case QZ_LCTRL
: return KEY_BACKSPACE
;
153 case QZ_LSHIFT
: return KEY_BACKSPACE
;
154 case QZ_F1
: return KEY_F
+1;
155 case QZ_F2
: return KEY_F
+2;
156 case QZ_F3
: return KEY_F
+3;
157 case QZ_F4
: return KEY_F
+4;
158 case QZ_F5
: return KEY_F
+5;
159 case QZ_F6
: return KEY_F
+6;
160 case QZ_F7
: return KEY_F
+7;
161 case QZ_F8
: return KEY_F
+8;
162 case QZ_F9
: return KEY_F
+9;
163 case QZ_F10
: return KEY_F
+10;
164 case QZ_F11
: return KEY_F
+11;
165 case QZ_F12
: return KEY_F
+12;
166 case QZ_INSERT
: return KEY_INSERT
;
167 case QZ_DELETE
: return KEY_DELETE
;
168 case QZ_HOME
: return KEY_HOME
;
169 case QZ_END
: return KEY_END
;
170 case QZ_KP_PLUS
: return '+';
171 case QZ_KP_MINUS
: return '-';
172 case QZ_TAB
: return KEY_TAB
;
173 case QZ_PAGEUP
: return KEY_PAGE_UP
;
174 case QZ_PAGEDOWN
: return KEY_PAGE_DOWN
;
175 case QZ_UP
: return KEY_UP
;
176 case QZ_DOWN
: return KEY_DOWN
;
177 case QZ_LEFT
: return KEY_LEFT
;
178 case QZ_RIGHT
: return KEY_RIGHT
;
179 case QZ_KP_MULTIPLY
: return '*';
180 case QZ_KP_DIVIDE
: return '/';
181 case QZ_KP_ENTER
: return KEY_KPENTER
;
182 case QZ_KP_PERIOD
: return KEY_KPDEC
;
183 case QZ_KP0
: return KEY_KP0
;
184 case QZ_KP1
: return KEY_KP1
;
185 case QZ_KP2
: return KEY_KP2
;
186 case QZ_KP3
: return KEY_KP3
;
187 case QZ_KP4
: return KEY_KP4
;
188 case QZ_KP5
: return KEY_KP5
;
189 case QZ_KP6
: return KEY_KP6
;
190 case QZ_KP7
: return KEY_KP7
;
191 case QZ_KP8
: return KEY_KP8
;
192 case QZ_KP9
: return KEY_KP9
;
193 default: return charcode
;
197 static void draw_alpha(int x0
, int y0
, int w
, int h
, unsigned char *src
, unsigned char *srca
, int stride
)
199 switch (image_format
)
202 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,image_data
+4*(y0
*imgRect
.right
+x0
),4*imgRect
.right
);
207 vo_draw_alpha_yv12(w
,h
,src
,srca
,stride
, ((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x0
+ y0
* imgRect
.right
, imgRect
.right
);
210 vo_draw_alpha_uyvy(w
,h
,src
,srca
,stride
,((char*)P
) + (x0
+ y0
* imgRect
.right
) * 2,imgRect
.right
*2);
213 vo_draw_alpha_yuy2(w
,h
,src
,srca
,stride
,((char*)P
) + (x0
+ y0
* imgRect
.right
) * 2,imgRect
.right
*2);
218 //default keyboard event handler
219 static OSStatus
KeyEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
221 OSStatus result
= noErr
;
222 UInt32
class = GetEventClass (event
);
223 UInt32 kind
= GetEventKind (event
);
225 result
= CallNextEventHandler(nextHandler
, event
);
227 if(class == kEventClassKeyboard
)
231 UInt32 macKeyModifiers
;
233 GetEventParameter(event
, kEventParamKeyMacCharCodes
, typeChar
, NULL
, sizeof(macCharCodes
), NULL
, &macCharCodes
);
234 GetEventParameter(event
, kEventParamKeyCode
, typeUInt32
, NULL
, sizeof(macKeyCode
), NULL
, &macKeyCode
);
235 GetEventParameter(event
, kEventParamKeyModifiers
, typeUInt32
, NULL
, sizeof(macKeyModifiers
), NULL
, &macKeyModifiers
);
237 if(macKeyModifiers
!= 256)
239 if (kind
== kEventRawKeyRepeat
|| kind
== kEventRawKeyDown
)
241 int key
= convert_key(macKeyCode
, macCharCodes
);
243 mplayer_put_key(key
);
246 else if(macKeyModifiers
== 256)
250 case '[': SetWindowAlpha(theWindow
, winAlpha
-=0.05); break;
251 case ']': SetWindowAlpha(theWindow
, winAlpha
+=0.05); break;
255 result
= eventNotHandledErr
;
261 //default mouse event handler
262 static OSStatus
MouseEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
264 OSStatus result
= noErr
;
265 UInt32
class = GetEventClass (event
);
266 UInt32 kind
= GetEventKind (event
);
268 result
= CallNextEventHandler(nextHandler
, event
);
270 if(class == kEventClassMouse
)
276 GetEventParameter(event
, kEventParamMouseLocation
, typeQDPoint
, 0, sizeof(Point
), 0, &mousePos
);
277 GetEventParameter(event
, kEventParamWindowMouseLocation
, typeQDPoint
, 0, sizeof(Point
), 0, &winMousePos
);
281 case kEventMouseMoved
:
285 CGDisplayShowCursor(kCGDirectMainDisplay
);
291 case kEventMouseWheelMoved
:
296 GetEventParameter(event
, kEventParamMouseWheelDelta
, typeSInt32
, 0, sizeof(int), 0, &wheel
);
298 part
= FindWindow(mousePos
,&tmpWin
);
300 if(part
== inContent
)
303 mplayer_put_key(MOUSE_BTN3
);
305 mplayer_put_key(MOUSE_BTN4
);
310 case kEventMouseDown
:
313 EventMouseButton button
;
317 GetWindowPortBounds(theWindow
, &bounds
);
318 GetEventParameter(event
, kEventParamMouseButton
, typeMouseButton
, 0, sizeof(EventMouseButton
), 0, &button
);
320 part
= FindWindow(mousePos
,&tmpWin
);
321 if(kind
== kEventMouseUp
)
323 if (part
!= inContent
)
327 case kEventMouseButtonPrimary
:
328 mplayer_put_key(MOUSE_BTN0
);
330 case kEventMouseButtonSecondary
:
331 mplayer_put_key(MOUSE_BTN2
);
333 case kEventMouseButtonTertiary
:
334 mplayer_put_key(MOUSE_BTN1
);
337 default:result
= eventNotHandledErr
;break;
341 if( (winMousePos
.h
> (bounds
.right
- 15)) && (winMousePos
.v
> (bounds
.bottom
)) )
345 GrowWindow(theWindow
, mousePos
, NULL
);
348 else if(part
== inMenuBar
)
350 MenuSelect(mousePos
);
353 else if(part
== inContent
)
357 case kEventMouseButtonPrimary
:
358 mplayer_put_key(MOUSE_BTN0
| MP_KEY_DOWN
);
360 case kEventMouseButtonSecondary
:
361 mplayer_put_key(MOUSE_BTN2
| MP_KEY_DOWN
);
363 case kEventMouseButtonTertiary
:
364 mplayer_put_key(MOUSE_BTN1
| MP_KEY_DOWN
);
367 default:result
= eventNotHandledErr
;break;
373 case kEventMouseDragged
:
376 default:result
= eventNotHandledErr
;break;
383 //default window event handler
384 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
386 OSStatus result
= noErr
;
389 UInt32
class = GetEventClass (event
);
390 UInt32 kind
= GetEventKind (event
);
392 result
= CallNextEventHandler(nextHandler
, event
);
394 aspect(&d_width
,&d_height
,A_NOZOOM
);
396 if(class == kEventClassCommand
)
398 HICommand theHICommand
;
399 GetEventParameter( event
, kEventParamDirectObject
, typeHICommand
, NULL
, sizeof( HICommand
), NULL
, &theHICommand
);
401 switch ( theHICommand
.commandID
)
404 mplayer_put_key(KEY_CLOSE_WIN
);
410 vo_fs
= (!(vo_fs
)); window_fullscreen();
413 SizeWindow(theWindow
, (d_width
/2), ((d_width
/movie_aspect
)/2), 1);
417 case kNormalScreenCmd
:
420 vo_fs
= (!(vo_fs
)); window_fullscreen();
423 SizeWindow(theWindow
, d_width
, (d_width
/movie_aspect
), 1);
427 case kDoubleScreenCmd
:
430 vo_fs
= (!(vo_fs
)); window_fullscreen();
433 SizeWindow(theWindow
, (d_width
*2), ((d_width
/movie_aspect
)*2), 1);
438 vo_fs
= (!(vo_fs
)); window_fullscreen();
442 vo_keepaspect
= (!(vo_keepaspect
));
443 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
448 movie_aspect
= old_movie_aspect
;
451 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
457 movie_aspect
= 4.0f
/3.0f
;
460 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
466 movie_aspect
= 16.0f
/9.0f
;
469 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
475 vo_panscan
= (!(vo_panscan
));
476 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
482 result
= eventNotHandledErr
;
486 else if(class == kEventClassWindow
)
489 Rect rectPort
= {0,0,0,0};
491 GetEventParameter(event
, kEventParamDirectObject
, typeWindowRef
, NULL
, sizeof(WindowRef
), NULL
, &window
);
495 GetPortBounds(GetWindowPort(window
), &rectPort
);
500 case kEventWindowClosed
:
502 mplayer_put_key(KEY_CLOSE_WIN
);
506 case kEventWindowZoomed
:
507 case kEventWindowBoundsChanged
:
514 result
= eventNotHandledErr
;
522 static void quartz_CreateWindow(uint32_t d_width
, uint32_t d_height
, WindowAttributes windowAttrs
)
524 CFStringRef titleKey
;
525 CFStringRef windowTitle
;
529 CFStringRef movMenuTitle
;
530 CFStringRef aspMenuTitle
;
532 const EventTypeSpec win_events
[] = {
533 { kEventClassWindow
, kEventWindowClosed
},
534 { kEventClassWindow
, kEventWindowBoundsChanged
},
535 { kEventClassCommand
, kEventCommandProcess
}
538 const EventTypeSpec key_events
[] = {
539 { kEventClassKeyboard
, kEventRawKeyDown
},
540 { kEventClassKeyboard
, kEventRawKeyRepeat
}
543 const EventTypeSpec mouse_events
[] = {
544 { kEventClassMouse
, kEventMouseMoved
},
545 { kEventClassMouse
, kEventMouseWheelMoved
},
546 { kEventClassMouse
, kEventMouseDown
},
547 { kEventClassMouse
, kEventMouseUp
},
548 { kEventClassMouse
, kEventMouseDragged
}
551 SetRect(&winRect
, 0, 0, d_width
, d_height
);
552 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
553 SetRect(&dstRect
, 0, 0, d_width
, d_height
);
559 CreateStandardWindowMenu(0, &windMenu
);
560 InsertMenu(windMenu
, 0);
563 CreateNewMenu (1004, 0, &movMenu
);
564 movMenuTitle
= CFSTR("Movie");
565 SetMenuTitleWithCFString(movMenu
, movMenuTitle
);
567 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Half Size"), 0, kHalfScreenCmd
, &index
);
568 SetMenuItemCommandKey(movMenu
, index
, 0, '0');
570 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Normal Size"), 0, kNormalScreenCmd
, &index
);
571 SetMenuItemCommandKey(movMenu
, index
, 0, '1');
573 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Double Size"), 0, kDoubleScreenCmd
, &index
);
574 SetMenuItemCommandKey(movMenu
, index
, 0, '2');
576 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Full Size"), 0, kFullScreenCmd
, &index
);
577 SetMenuItemCommandKey(movMenu
, index
, 0, 'F');
579 AppendMenuItemTextWithCFString(movMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
581 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Aspect Ratio"), 0, 0, &index
);
583 ////Create Aspect Ratio Sub Menu
584 CreateNewMenu (0, 0, &aspectMenu
);
585 aspMenuTitle
= CFSTR("Aspect Ratio");
586 SetMenuTitleWithCFString(aspectMenu
, aspMenuTitle
);
587 SetMenuItemHierarchicalMenu(movMenu
, 6, aspectMenu
);
589 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Keep"), 0, kKeepAspectCmd
, &index
);
590 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
591 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Pan-Scan"), 0, kPanScanCmd
, &index
);
592 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
593 AppendMenuItemTextWithCFString(aspectMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
594 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Original"), 0, kAspectOrgCmd
, &index
);
595 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("4:3"), 0, kAspectFullCmd
, &index
);
596 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("16:9"), 0, kAspectWideCmd
, &index
);
598 InsertMenu(movMenu
, GetMenuID(windMenu
)); //insert before Window menu
603 CreateNewWindow(kDocumentWindowClass
, windowAttrs
, &winRect
, &theWindow
);
605 CreateWindowGroup(0, &winGroup
);
606 SetWindowGroup(theWindow
, winGroup
);
609 titleKey
= CFSTR("MPlayer - The Movie Player");
610 windowTitle
= CFCopyLocalizedString(titleKey
, NULL
);
611 result
= SetWindowTitleWithCFString(theWindow
, windowTitle
);
613 CFRelease(windowTitle
);
615 //Install event handler
616 InstallApplicationEventHandler (NewEventHandlerUPP (KeyEventHandler
), GetEventTypeCount(key_events
), key_events
, NULL
, NULL
);
617 InstallApplicationEventHandler (NewEventHandlerUPP (MouseEventHandler
), GetEventTypeCount(mouse_events
), mouse_events
, NULL
, NULL
);
618 InstallWindowEventHandler (theWindow
, NewEventHandlerUPP (WindowEventHandler
), GetEventTypeCount(win_events
), win_events
, theWindow
, NULL
);
621 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
)
623 WindowAttributes windowAttrs
;
628 //Get Main device info///////////////////////////////////////////////////
631 deviceHdl
= GetMainDevice();
633 for(i
=0; i
<device_id
; i
++)
635 deviceHdl
= GetNextDevice(deviceHdl
);
637 if(deviceHdl
== NULL
)
639 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id
);
640 deviceHdl
= GetMainDevice();
646 deviceRect
= (*deviceHdl
)->gdRect
;
647 device_width
= deviceRect
.right
-deviceRect
.left
;
648 device_height
= deviceRect
.bottom
-deviceRect
.top
;
650 monitor_aspect
= (float)device_width
/(float)device_height
;
652 //misc mplayer setup/////////////////////////////////////////////////////
653 SetRect(&imgRect
, 0, 0, width
, height
);
654 switch (image_format
)
667 image_size
= ((imgRect
.right
*imgRect
.bottom
*image_depth
)+7)/8;
669 vo_fs
= flags
& VOFLAG_FULLSCREEN
;
673 aspect_save_orig(width
,height
);
674 aspect_save_prescale(d_width
,d_height
);
675 aspect_save_screenres(device_width
, device_height
);
677 aspect(&d_width
,&d_height
,A_NOZOOM
);
679 movie_aspect
= (float)d_width
/(float)d_height
;
680 old_movie_aspect
= movie_aspect
;
685 image_data
= malloc(image_size
);
687 //Create player window//////////////////////////////////////////////////
688 windowAttrs
= kWindowStandardDocumentAttributes
689 | kWindowStandardHandlerAttribute
690 | kWindowLiveResizeAttribute
;
692 windowAttrs
&= (~kWindowResizableAttribute
);
694 if (theWindow
== NULL
)
696 quartz_CreateWindow(d_width
, d_height
, windowAttrs
);
698 if (theWindow
== NULL
)
700 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Couldn't create window !!!!!\n");
703 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
704 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
705 CGContextFillRect(context
, tmpBounds
);
709 HideWindow(theWindow
);
710 ChangeWindowAttributes(theWindow
, ~windowAttrs
, windowAttrs
);
711 SetRect(&winRect
, 0, 0, d_width
, d_height
);
712 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
713 SizeWindow (theWindow
, d_width
, d_height
, 1);
716 switch (image_format
)
720 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
722 dataProviderRef
= CGDataProviderCreateWithData (0, image_data
, imgRect
.right
* imgRect
.bottom
* 4, 0);
724 image
= CGImageCreate (imgRect
.right
,
728 ((imgRect
.right
*32)+7)/8,
729 CGColorSpaceCreateDeviceRGB(),
730 kCGImageAlphaNoneSkipFirst
,
731 dataProviderRef
, 0, 1, kCGRenderingIntentDefault
);
743 if (!EnterMoviesDone
)
745 qterr
= EnterMovies();
753 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: EnterMovies (%d)\n", qterr
);
758 SetIdentityMatrix(&matrix
);
760 if ((d_width
!= width
) || (d_height
!= height
))
762 ScaleMatrix(&matrix
, FixDiv(Long2Fix(d_width
),Long2Fix(width
)), FixDiv(Long2Fix(d_height
),Long2Fix(height
)), 0, 0);
765 yuv_qt_stuff
.desc
= (ImageDescriptionHandle
)NewHandleClear( sizeof(ImageDescription
) );
767 yuv_qt_stuff
.extension_colr
= NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension
));
768 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->colorParamType
= kVideoColorInfoImageDescriptionExtensionType
;
769 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->primaries
= 2;
770 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->transferFunction
= 2;
771 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->matrix
= 2;
773 yuv_qt_stuff
.extension_fiel
= NewHandleClear(sizeof(FieldInfoImageDescriptionExtension
));
774 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldCount
= 1;
775 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldOrderings
= 0;
777 yuv_qt_stuff
.extension_clap
= NewHandleClear(sizeof(CleanApertureImageDescriptionExtension
));
778 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthN
= imgRect
.right
;
779 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthD
= 1;
780 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightN
= imgRect
.bottom
;
781 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightD
= 1;
782 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffN
= 0;
783 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffD
= 1;
784 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffN
= 0;
785 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffD
= 1;
787 yuv_qt_stuff
.extension_pasp
= NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension
));
788 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->hSpacing
= 1;
789 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->vSpacing
= 1;
791 (*yuv_qt_stuff
.desc
)->idSize
= sizeof(ImageDescription
);
792 (*yuv_qt_stuff
.desc
)->cType
= image_qtcodec
;
793 (*yuv_qt_stuff
.desc
)->version
= 2;
794 (*yuv_qt_stuff
.desc
)->revisionLevel
= 0;
795 (*yuv_qt_stuff
.desc
)->vendor
= 'mpla';
796 (*yuv_qt_stuff
.desc
)->width
= imgRect
.right
;
797 (*yuv_qt_stuff
.desc
)->height
= imgRect
.bottom
;
798 (*yuv_qt_stuff
.desc
)->hRes
= Long2Fix(72);
799 (*yuv_qt_stuff
.desc
)->vRes
= Long2Fix(72);
800 (*yuv_qt_stuff
.desc
)->temporalQuality
= 0;
801 (*yuv_qt_stuff
.desc
)->spatialQuality
= codecLosslessQuality
;
802 (*yuv_qt_stuff
.desc
)->frameCount
= 1;
803 (*yuv_qt_stuff
.desc
)->dataSize
= 0;
804 (*yuv_qt_stuff
.desc
)->depth
= 24;
805 (*yuv_qt_stuff
.desc
)->clutID
= -1;
807 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_colr
, kColorInfoImageDescriptionExtension
);
810 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr
);
813 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_fiel
, kFieldInfoImageDescriptionExtension
);
816 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr
);
819 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_clap
, kCleanApertureImageDescriptionExtension
);
822 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr
);
825 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_pasp
, kCleanApertureImageDescriptionExtension
);
828 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr
);
830 if (P
!= NULL
) { // second or subsequent movie
833 P
= calloc(sizeof(PlanarPixmapInfoYUV420
) + image_size
, 1);
834 switch (image_format
)
839 P
->componentInfoY
.offset
= be2me_32(sizeof(PlanarPixmapInfoYUV420
));
840 P
->componentInfoCb
.offset
= be2me_32(be2me_32(P
->componentInfoY
.offset
) + image_size
/ 2);
841 P
->componentInfoCr
.offset
= be2me_32(be2me_32(P
->componentInfoCb
.offset
) + image_size
/ 4);
842 P
->componentInfoY
.rowBytes
= be2me_32(imgRect
.right
);
843 P
->componentInfoCb
.rowBytes
= be2me_32(imgRect
.right
/ 2);
844 P
->componentInfoCr
.rowBytes
= be2me_32(imgRect
.right
/ 2);
845 image_buffer_size
= image_size
+ sizeof(PlanarPixmapInfoYUV420
);
849 image_buffer_size
= image_size
;
853 qterr
= DecompressSequenceBeginS(&seqId
,
857 GetWindowPort(theWindow
),
860 ((d_width
!= width
) || (d_height
!= height
)) ?
865 codecLosslessQuality
,
870 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr
);
878 RepositionWindow(theWindow
, NULL
, kWindowCenterOnMainScreen
);
879 ShowWindow (theWindow
);
891 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
900 static void check_events(void)
903 EventTargetRef theTarget
;
907 theTarget
= GetEventDispatcherTarget();
908 theErr
= ReceiveNextEvent(0, 0, kEventDurationNoWait
,true, &theEvent
);
909 if(theErr
== noErr
&& theEvent
!= NULL
)
911 SendEventToEventTarget (theEvent
, theTarget
);
912 ReleaseEvent(theEvent
);
916 static void draw_osd(void)
918 vo_draw_text(imgRect
.right
,imgRect
.bottom
,draw_alpha
);
921 static void flip_page(void)
924 static int lastTime
= 0;
926 if(theWindow
== NULL
)
929 switch (image_format
)
933 CGContextDrawImage (context
, bounds
, image
);
945 CodecFlags flags
= 0;
946 qterr
= DecompressSequenceFrameWhen(seqId
,
949 0, //codecFlagUseImageBuffer,
955 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr
, flags
);
964 CGContextBeginPath(context
);
965 CGContextSetAllowsAntialiasing(context
, false);
966 //CGContextSaveGState(context);
969 CGContextSetRGBStrokeColor (context
, 0.2, 0.2, 0.2, 0.5);
970 CGContextMoveToPoint( context
, winRect
.right
-1, 1); CGContextAddLineToPoint( context
, winRect
.right
-1, 1);
971 CGContextMoveToPoint( context
, winRect
.right
-1, 5); CGContextAddLineToPoint( context
, winRect
.right
-5, 1);
972 CGContextMoveToPoint( context
, winRect
.right
-1, 9); CGContextAddLineToPoint( context
, winRect
.right
-9, 1);
973 CGContextStrokePath( context
);
976 CGContextSetRGBStrokeColor (context
, 0.4, 0.4, 0.4, 0.5);
977 CGContextMoveToPoint( context
, winRect
.right
-1, 2); CGContextAddLineToPoint( context
, winRect
.right
-2, 1);
978 CGContextMoveToPoint( context
, winRect
.right
-1, 6); CGContextAddLineToPoint( context
, winRect
.right
-6, 1);
979 CGContextMoveToPoint( context
, winRect
.right
-1, 10); CGContextAddLineToPoint( context
, winRect
.right
-10, 1);
980 CGContextStrokePath( context
);
983 CGContextSetRGBStrokeColor (context
, 0.6, 0.6, 0.6, 0.5);
984 CGContextMoveToPoint( context
, winRect
.right
-1, 3); CGContextAddLineToPoint( context
, winRect
.right
-3, 1);
985 CGContextMoveToPoint( context
, winRect
.right
-1, 7); CGContextAddLineToPoint( context
, winRect
.right
-7, 1);
986 CGContextMoveToPoint( context
, winRect
.right
-1, 11); CGContextAddLineToPoint( context
, winRect
.right
-11, 1);
987 CGContextStrokePath( context
);
989 //CGContextRestoreGState( context );
990 CGContextFlush (context
);
993 //auto hide mouse cursor and futur on-screen control?
994 if(vo_quartz_fs
&& !mouseHide
)
996 int curTime
= TickCount()/60;
997 static int lastTime
= 0;
999 if( ((curTime
- lastTime
) >= 5) || (lastTime
== 0) )
1001 CGDisplayHideCursor(kCGDirectMainDisplay
);
1007 //update activity every 30 seconds to prevent
1008 //screensaver from starting up.
1009 curTime
= TickCount()/60;
1011 if( ((curTime
- lastTime
) >= 30) || (lastTime
== 0) )
1013 UpdateSystemActivity(UsrActivity
);
1018 static int draw_slice(uint8_t *src
[], int stride
[], int w
,int h
,int x
,int y
)
1020 switch (image_format
)
1024 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1025 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1027 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1028 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1032 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1033 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1035 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1036 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1042 static int draw_frame(uint8_t *src
[])
1044 switch (image_format
)
1047 fast_memcpy(image_data
,src
[0],image_size
);
1052 memcpy_pic(((char*)P
), src
[0], imgRect
.right
* 2, imgRect
.bottom
, imgRect
.right
* 2, imgRect
.right
* 2);
1058 static int query_format(uint32_t format
)
1060 image_format
= format
;
1063 if (format
== IMGFMT_RGB32
)
1065 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1068 if ((format
== IMGFMT_YV12
) || (format
== IMGFMT_IYUV
) || (format
== IMGFMT_I420
))
1070 image_qtcodec
= kMpegYUV420CodecType
; //kYUV420CodecType ?;
1071 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1074 if (format
== IMGFMT_YUY2
)
1076 image_qtcodec
= kComponentVideoUnsigned
;
1077 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1080 if (format
== IMGFMT_UYVY
)
1082 image_qtcodec
= k422YpCbCr8CodecType
;
1083 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1089 static void uninit(void)
1093 switch (image_format
)
1101 if (EnterMoviesDone
)
1103 qterr
= CDSequenceEnd(seqId
);
1106 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: CDSequenceEnd (%d)\n", qterr
);
1118 static int preinit(const char *arg
)
1124 char *parse_pos
= (char *)&arg
[0];
1125 while (parse_pos
[0] && !parse_err
)
1127 if (strncmp (parse_pos
, "device_id=", 10) == 0)
1129 parse_pos
= &parse_pos
[10];
1130 device_id
= strtol(parse_pos
, &parse_pos
, 0);
1132 if (strncmp (parse_pos
, "fs_res=", 7) == 0)
1134 parse_pos
= &parse_pos
[7];
1135 fs_res_x
= strtol(parse_pos
, &parse_pos
, 0);
1136 parse_pos
= &parse_pos
[1];
1137 fs_res_y
= strtol(parse_pos
, &parse_pos
, 0);
1139 if (parse_pos
[0] == ':') parse_pos
= &parse_pos
[1];
1140 else if (parse_pos
[0]) parse_err
= 1;
1144 #if !defined (MACOSX_FINDER_SUPPORT) || !defined (HAVE_SDL)
1145 //this chunk of code is heavily based off SDL_macosx.m from SDL
1146 //it uses an Apple private function to request foreground operation
1148 void CPSEnableForegroundOperation(ProcessSerialNumber
* psn
);
1149 ProcessSerialNumber myProc
, frProc
;
1152 if (GetFrontProcess(&frProc
) == noErr
)
1154 if (GetCurrentProcess(&myProc
) == noErr
)
1156 if (SameProcess(&frProc
, &myProc
, &sameProc
) == noErr
&& !sameProc
)
1158 CPSEnableForegroundOperation(&myProc
);
1160 SetFrontProcess(&myProc
);
1169 static uint32_t draw_yuv_image(mp_image_t
*mpi
)
1171 // ATM we're only called for planar IMGFMT
1172 // drawing is done directly in P
1173 // and displaying is in flip_page.
1174 return get_image_done
? VO_TRUE
: VO_FALSE
;
1177 static uint32_t get_yuv_image(mp_image_t
*mpi
)
1179 if(mpi
->type
!=MP_IMGTYPE_EXPORT
) return VO_FALSE
;
1181 if(mpi
->imgfmt
!=image_format
) return VO_FALSE
;
1183 if(mpi
->flags
&MP_IMGFLAG_PLANAR
)
1185 if (mpi
->num_planes
!= 3)
1187 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi
->num_planes
);
1191 mpi
->planes
[0]=((char*)P
) + be2me_32(P
->componentInfoY
.offset
);
1192 mpi
->stride
[0]=imgRect
.right
;
1193 mpi
->width
=imgRect
.right
;
1195 if(mpi
->flags
&MP_IMGFLAG_SWAPPED
)
1198 mpi
->planes
[1]=((char*)P
) + be2me_32(P
->componentInfoCb
.offset
);
1199 mpi
->planes
[2]=((char*)P
) + be2me_32(P
->componentInfoCr
.offset
);
1200 mpi
->stride
[1]=imgRect
.right
/2;
1201 mpi
->stride
[2]=imgRect
.right
/2;
1206 mpi
->planes
[1]=((char*)P
) + be2me_32(P
->componentInfoCr
.offset
);
1207 mpi
->planes
[2]=((char*)P
) + be2me_32(P
->componentInfoCb
.offset
);
1208 mpi
->stride
[1]=imgRect
.right
/2;
1209 mpi
->stride
[2]=imgRect
.right
/2;
1212 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1219 if (mpi
->num_planes
!= 1)
1221 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi
->num_planes
);
1225 mpi
->planes
[0] = (char*)P
;
1226 mpi
->stride
[0] = imgRect
.right
* 2;
1227 mpi
->width
=imgRect
.right
;
1228 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1235 static int control(uint32_t request
, void *data
, ...)
1239 case VOCTRL_PAUSE
: return (int_pause
=1);
1240 case VOCTRL_RESUME
: return (int_pause
=0);
1241 case VOCTRL_FULLSCREEN
: vo_fs
= (!(vo_fs
)); window_fullscreen(); return VO_TRUE
;
1242 case VOCTRL_ONTOP
: vo_ontop
= (!(vo_ontop
)); window_ontop(); return VO_TRUE
;
1243 case VOCTRL_QUERY_FORMAT
: return query_format(*((uint32_t*)data
));
1244 case VOCTRL_GET_PANSCAN
: return VO_TRUE
;
1245 case VOCTRL_SET_PANSCAN
: window_panscan(); return VO_TRUE
;
1247 case VOCTRL_GET_IMAGE
:
1248 switch (image_format
)
1255 return get_yuv_image(data
);
1260 case VOCTRL_DRAW_IMAGE
:
1261 switch (image_format
)
1268 return draw_yuv_image(data
);
1277 void window_resized()
1289 GetPortBounds( GetWindowPort(theWindow
), &winRect
);
1293 aspect( &d_width
, &d_height
, A_NOZOOM
);
1294 d_height
= ((float)d_width
/movie_aspect
);
1296 aspectX
= (float)((float)winRect
.right
/(float)d_width
);
1297 aspectY
= (float)((float)(winRect
.bottom
)/(float)d_height
);
1299 if((d_height
*aspectX
)>(winRect
.bottom
))
1301 padding
= (winRect
.right
- d_width
*aspectY
)/2;
1302 SetRect(&dstRect
, padding
, 0, d_width
*aspectY
+padding
, d_height
*aspectY
);
1306 padding
= ((winRect
.bottom
) - d_height
*aspectX
)/2;
1307 SetRect(&dstRect
, 0, padding
, (d_width
*aspectX
), d_height
*aspectX
+padding
);
1312 SetRect(&dstRect
, 0, 0, winRect
.right
, winRect
.bottom
);
1315 switch (image_format
)
1319 bounds
= CGRectMake(dstRect
.left
, dstRect
.top
, dstRect
.right
-dstRect
.left
, dstRect
.bottom
-dstRect
.top
);
1320 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
1329 long scale_X
= FixDiv(Long2Fix(dstRect
.right
- dstRect
.left
),Long2Fix(imgRect
.right
));
1330 long scale_Y
= FixDiv(Long2Fix(dstRect
.bottom
- dstRect
.top
),Long2Fix(imgRect
.bottom
));
1332 SetIdentityMatrix(&matrix
);
1333 if (((dstRect
.right
- dstRect
.left
) != imgRect
.right
) || ((dstRect
.bottom
- dstRect
.right
) != imgRect
.bottom
))
1335 ScaleMatrix(&matrix
, scale_X
, scale_Y
, 0, 0);
1339 TranslateMatrix(&matrix
, Long2Fix(dstRect
.left
), Long2Fix(dstRect
.top
));
1343 SetDSequenceMatrix(seqId
, &matrix
);
1351 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
1352 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
1353 CGContextFillRect(context
, tmpBounds
);
1360 //Cycle between level
1365 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
1368 void window_fullscreen()
1370 static Ptr restoreState
= NULL
;
1379 SetSystemUIMode( kUIModeAllHidden
, kUIOptionAutoShowMenuBar
);
1380 CGDisplayHideCursor(kCGDirectMainDisplay
);
1384 if(fs_res_x
!= 0 || fs_res_y
!= 0)
1386 BeginFullScreen( &restoreState
, deviceHdl
, &fs_res_x
, &fs_res_y
, NULL
, NULL
, 0);
1388 //Get Main device info///////////////////////////////////////////////////
1389 deviceRect
= (*deviceHdl
)->gdRect
;
1391 device_width
= deviceRect
.right
;
1392 device_height
= deviceRect
.bottom
;
1396 //save old window size
1399 GetWindowPortBounds(theWindow
, &oldWinRect
);
1400 GetWindowBounds(theWindow
, kWindowContentRgn
, &oldWinBounds
);
1405 ChangeWindowAttributes(theWindow
, kWindowNoShadowAttribute
, 0);
1406 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1407 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);
1411 else //go back to windowed mode
1414 if(restoreState
!= NULL
)
1416 EndFullScreen(restoreState
, 0);
1418 //Get Main device info///////////////////////////////////////////////////
1419 deviceRect
= (*deviceHdl
)->gdRect
;
1421 device_width
= deviceRect
.right
;
1422 device_height
= deviceRect
.bottom
;
1423 restoreState
= NULL
;
1425 SetSystemUIMode( kUIModeNormal
, 0);
1428 CGDisplayShowCursor(kCGDirectMainDisplay
);
1431 //revert window to previous setting
1432 ChangeWindowAttributes(theWindow
, 0, kWindowNoShadowAttribute
);
1433 SizeWindow(theWindow
, oldWinRect
.right
, oldWinRect
.bottom
,1);
1434 MoveWindow(theWindow
, oldWinBounds
.left
, oldWinBounds
.top
, 1);
1439 void window_panscan()
1444 CheckMenuItem (aspectMenu
, 2, 1);
1446 CheckMenuItem (aspectMenu
, 2, 0);
1450 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1451 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);