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 vo_info_t info
=
45 "Nicolas Plourde <nicolasplourde@hotmail.com>, Romain Dolbeau <romain@dolbeau.org>",
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
:
312 EventMouseButton button
;
316 GetWindowPortBounds(theWindow
, &bounds
);
317 GetEventParameter(event
, kEventParamMouseButton
, typeMouseButton
, 0, sizeof(EventMouseButton
), 0, &button
);
319 part
= FindWindow(mousePos
,&tmpWin
);
321 if( (winMousePos
.h
> (bounds
.right
- 15)) && (winMousePos
.v
> (bounds
.bottom
)) )
325 GrowWindow(theWindow
, mousePos
, NULL
);
328 else if(part
== inMenuBar
)
330 MenuSelect(mousePos
);
333 else if(part
== inContent
)
337 case kEventMouseButtonPrimary
:
338 mplayer_put_key(MOUSE_BTN0
);
340 case kEventMouseButtonSecondary
:
341 mplayer_put_key(MOUSE_BTN1
);
343 case kEventMouseButtonTertiary
:
344 mplayer_put_key(MOUSE_BTN2
);
347 default:result
= eventNotHandledErr
;break;
356 case kEventMouseDragged
:
359 default:result
= eventNotHandledErr
;break;
366 //default window event handler
367 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
369 OSStatus result
= noErr
;
372 UInt32
class = GetEventClass (event
);
373 UInt32 kind
= GetEventKind (event
);
375 result
= CallNextEventHandler(nextHandler
, event
);
377 aspect(&d_width
,&d_height
,A_NOZOOM
);
379 if(class == kEventClassCommand
)
381 HICommand theHICommand
;
382 GetEventParameter( event
, kEventParamDirectObject
, typeHICommand
, NULL
, sizeof( HICommand
), NULL
, &theHICommand
);
384 switch ( theHICommand
.commandID
)
387 mplayer_put_key(KEY_CLOSE_WIN
);
393 vo_fs
= (!(vo_fs
)); window_fullscreen();
396 SizeWindow(theWindow
, (d_width
/2), ((d_width
/movie_aspect
)/2), 1);
400 case kNormalScreenCmd
:
403 vo_fs
= (!(vo_fs
)); window_fullscreen();
406 SizeWindow(theWindow
, d_width
, (d_width
/movie_aspect
), 1);
410 case kDoubleScreenCmd
:
413 vo_fs
= (!(vo_fs
)); window_fullscreen();
416 SizeWindow(theWindow
, (d_width
*2), ((d_width
/movie_aspect
)*2), 1);
421 vo_fs
= (!(vo_fs
)); window_fullscreen();
425 vo_keepaspect
= (!(vo_keepaspect
));
426 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
431 movie_aspect
= old_movie_aspect
;
434 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
440 movie_aspect
= 4.0f
/3.0f
;
443 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
449 movie_aspect
= 16.0f
/9.0f
;
452 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
458 vo_panscan
= (!(vo_panscan
));
459 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
465 result
= eventNotHandledErr
;
469 else if(class == kEventClassWindow
)
472 Rect rectPort
= {0,0,0,0};
474 GetEventParameter(event
, kEventParamDirectObject
, typeWindowRef
, NULL
, sizeof(WindowRef
), NULL
, &window
);
478 GetPortBounds(GetWindowPort(window
), &rectPort
);
483 case kEventWindowClosed
:
485 mplayer_put_key(KEY_CLOSE_WIN
);
489 case kEventWindowZoomed
:
490 case kEventWindowBoundsChanged
:
497 result
= eventNotHandledErr
;
505 static void quartz_CreateWindow(uint32_t d_width
, uint32_t d_height
, WindowAttributes windowAttrs
)
507 CFStringRef titleKey
;
508 CFStringRef windowTitle
;
512 CFStringRef movMenuTitle
;
513 CFStringRef aspMenuTitle
;
515 const EventTypeSpec win_events
[] = {
516 { kEventClassWindow
, kEventWindowClosed
},
517 { kEventClassWindow
, kEventWindowBoundsChanged
},
518 { kEventClassCommand
, kEventCommandProcess
}
521 const EventTypeSpec key_events
[] = {
522 { kEventClassKeyboard
, kEventRawKeyDown
},
523 { kEventClassKeyboard
, kEventRawKeyRepeat
}
526 const EventTypeSpec mouse_events
[] = {
527 { kEventClassMouse
, kEventMouseMoved
},
528 { kEventClassMouse
, kEventMouseWheelMoved
},
529 { kEventClassMouse
, kEventMouseDown
},
530 { kEventClassMouse
, kEventMouseUp
},
531 { kEventClassMouse
, kEventMouseDragged
}
534 SetRect(&winRect
, 0, 0, d_width
, d_height
);
535 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
536 SetRect(&dstRect
, 0, 0, d_width
, d_height
);
542 CreateStandardWindowMenu(0, &windMenu
);
543 InsertMenu(windMenu
, 0);
546 CreateNewMenu (1004, 0, &movMenu
);
547 movMenuTitle
= CFSTR("Movie");
548 SetMenuTitleWithCFString(movMenu
, movMenuTitle
);
550 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Half Size"), 0, kHalfScreenCmd
, &index
);
551 SetMenuItemCommandKey(movMenu
, index
, 0, '0');
553 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Normal Size"), 0, kNormalScreenCmd
, &index
);
554 SetMenuItemCommandKey(movMenu
, index
, 0, '1');
556 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Double Size"), 0, kDoubleScreenCmd
, &index
);
557 SetMenuItemCommandKey(movMenu
, index
, 0, '2');
559 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Full Size"), 0, kFullScreenCmd
, &index
);
560 SetMenuItemCommandKey(movMenu
, index
, 0, 'F');
562 AppendMenuItemTextWithCFString(movMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
564 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Aspect Ratio"), 0, 0, &index
);
566 ////Create Aspect Ratio Sub Menu
567 CreateNewMenu (0, 0, &aspectMenu
);
568 aspMenuTitle
= CFSTR("Aspect Ratio");
569 SetMenuTitleWithCFString(aspectMenu
, aspMenuTitle
);
570 SetMenuItemHierarchicalMenu(movMenu
, 6, aspectMenu
);
572 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Keep"), 0, kKeepAspectCmd
, &index
);
573 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
574 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Pan-Scan"), 0, kPanScanCmd
, &index
);
575 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
576 AppendMenuItemTextWithCFString(aspectMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
577 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Original"), 0, kAspectOrgCmd
, &index
);
578 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("4:3"), 0, kAspectFullCmd
, &index
);
579 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("16:9"), 0, kAspectWideCmd
, &index
);
581 InsertMenu(movMenu
, GetMenuID(windMenu
)); //insert before Window menu
586 CreateNewWindow(kDocumentWindowClass
, windowAttrs
, &winRect
, &theWindow
);
588 CreateWindowGroup(0, &winGroup
);
589 SetWindowGroup(theWindow
, winGroup
);
592 titleKey
= CFSTR("MPlayer - The Movie Player");
593 windowTitle
= CFCopyLocalizedString(titleKey
, NULL
);
594 result
= SetWindowTitleWithCFString(theWindow
, windowTitle
);
596 CFRelease(windowTitle
);
598 //Install event handler
599 InstallApplicationEventHandler (NewEventHandlerUPP (KeyEventHandler
), GetEventTypeCount(key_events
), key_events
, NULL
, NULL
);
600 InstallApplicationEventHandler (NewEventHandlerUPP (MouseEventHandler
), GetEventTypeCount(mouse_events
), mouse_events
, NULL
, NULL
);
601 InstallWindowEventHandler (theWindow
, NewEventHandlerUPP (WindowEventHandler
), GetEventTypeCount(win_events
), win_events
, theWindow
, NULL
);
604 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
)
606 WindowAttributes windowAttrs
;
611 //Get Main device info///////////////////////////////////////////////////
614 deviceHdl
= GetMainDevice();
616 for(i
=0; i
<device_id
; i
++)
618 deviceHdl
= GetNextDevice(deviceHdl
);
620 if(deviceHdl
== NULL
)
622 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id
);
623 deviceHdl
= GetMainDevice();
629 deviceRect
= (*deviceHdl
)->gdRect
;
630 device_width
= deviceRect
.right
-deviceRect
.left
;
631 device_height
= deviceRect
.bottom
-deviceRect
.top
;
633 monitor_aspect
= (float)device_width
/(float)device_height
;
635 //misc mplayer setup/////////////////////////////////////////////////////
636 SetRect(&imgRect
, 0, 0, width
, height
);
637 switch (image_format
)
650 image_size
= ((imgRect
.right
*imgRect
.bottom
*image_depth
)+7)/8;
652 vo_fs
= flags
& VOFLAG_FULLSCREEN
;
656 aspect_save_orig(width
,height
);
657 aspect_save_prescale(d_width
,d_height
);
658 aspect_save_screenres(device_width
, device_height
);
660 aspect(&d_width
,&d_height
,A_NOZOOM
);
662 movie_aspect
= (float)d_width
/(float)d_height
;
663 old_movie_aspect
= movie_aspect
;
668 image_data
= malloc(image_size
);
670 //Create player window//////////////////////////////////////////////////
671 windowAttrs
= kWindowStandardDocumentAttributes
672 | kWindowStandardHandlerAttribute
673 | kWindowLiveResizeAttribute
;
675 windowAttrs
&= (~kWindowResizableAttribute
);
677 if (theWindow
== NULL
)
679 quartz_CreateWindow(d_width
, d_height
, windowAttrs
);
681 if (theWindow
== NULL
)
683 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Couldn't create window !!!!!\n");
686 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
687 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
688 CGContextFillRect(context
, tmpBounds
);
692 HideWindow(theWindow
);
693 ChangeWindowAttributes(theWindow
, ~windowAttrs
, windowAttrs
);
694 SetRect(&winRect
, 0, 0, d_width
, d_height
);
695 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
696 SizeWindow (theWindow
, d_width
, d_height
, 1);
699 switch (image_format
)
703 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
705 dataProviderRef
= CGDataProviderCreateWithData (0, image_data
, imgRect
.right
* imgRect
.bottom
* 4, 0);
707 image
= CGImageCreate (imgRect
.right
,
711 ((imgRect
.right
*32)+7)/8,
712 CGColorSpaceCreateDeviceRGB(),
713 kCGImageAlphaNoneSkipFirst
,
714 dataProviderRef
, 0, 1, kCGRenderingIntentDefault
);
726 if (!EnterMoviesDone
)
728 qterr
= EnterMovies();
736 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: EnterMovies (%d)\n", qterr
);
741 SetIdentityMatrix(&matrix
);
743 if ((d_width
!= width
) || (d_height
!= height
))
745 ScaleMatrix(&matrix
, FixDiv(Long2Fix(d_width
),Long2Fix(width
)), FixDiv(Long2Fix(d_height
),Long2Fix(height
)), 0, 0);
748 yuv_qt_stuff
.desc
= (ImageDescriptionHandle
)NewHandleClear( sizeof(ImageDescription
) );
750 yuv_qt_stuff
.extension_colr
= NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension
));
751 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->colorParamType
= kVideoColorInfoImageDescriptionExtensionType
;
752 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->primaries
= 2;
753 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->transferFunction
= 2;
754 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->matrix
= 2;
756 yuv_qt_stuff
.extension_fiel
= NewHandleClear(sizeof(FieldInfoImageDescriptionExtension
));
757 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldCount
= 1;
758 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldOrderings
= 0;
760 yuv_qt_stuff
.extension_clap
= NewHandleClear(sizeof(CleanApertureImageDescriptionExtension
));
761 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthN
= imgRect
.right
;
762 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthD
= 1;
763 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightN
= imgRect
.bottom
;
764 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightD
= 1;
765 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffN
= 0;
766 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffD
= 1;
767 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffN
= 0;
768 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffD
= 1;
770 yuv_qt_stuff
.extension_pasp
= NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension
));
771 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->hSpacing
= 1;
772 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->vSpacing
= 1;
774 (*yuv_qt_stuff
.desc
)->idSize
= sizeof(ImageDescription
);
775 (*yuv_qt_stuff
.desc
)->cType
= image_qtcodec
;
776 (*yuv_qt_stuff
.desc
)->version
= 2;
777 (*yuv_qt_stuff
.desc
)->revisionLevel
= 0;
778 (*yuv_qt_stuff
.desc
)->vendor
= 'mpla';
779 (*yuv_qt_stuff
.desc
)->width
= imgRect
.right
;
780 (*yuv_qt_stuff
.desc
)->height
= imgRect
.bottom
;
781 (*yuv_qt_stuff
.desc
)->hRes
= Long2Fix(72);
782 (*yuv_qt_stuff
.desc
)->vRes
= Long2Fix(72);
783 (*yuv_qt_stuff
.desc
)->temporalQuality
= 0;
784 (*yuv_qt_stuff
.desc
)->spatialQuality
= codecLosslessQuality
;
785 (*yuv_qt_stuff
.desc
)->frameCount
= 1;
786 (*yuv_qt_stuff
.desc
)->dataSize
= 0;
787 (*yuv_qt_stuff
.desc
)->depth
= 24;
788 (*yuv_qt_stuff
.desc
)->clutID
= -1;
790 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_colr
, kColorInfoImageDescriptionExtension
);
793 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr
);
796 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_fiel
, kFieldInfoImageDescriptionExtension
);
799 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr
);
802 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_clap
, kCleanApertureImageDescriptionExtension
);
805 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr
);
808 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_pasp
, kCleanApertureImageDescriptionExtension
);
811 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr
);
813 if (P
!= NULL
) { // second or subsequent movie
816 P
= calloc(sizeof(PlanarPixmapInfoYUV420
) + image_size
, 1);
817 switch (image_format
)
822 P
->componentInfoY
.offset
= be2me_32(sizeof(PlanarPixmapInfoYUV420
));
823 P
->componentInfoCb
.offset
= be2me_32(be2me_32(P
->componentInfoY
.offset
) + image_size
/ 2);
824 P
->componentInfoCr
.offset
= be2me_32(be2me_32(P
->componentInfoCb
.offset
) + image_size
/ 4);
825 P
->componentInfoY
.rowBytes
= be2me_32(imgRect
.right
);
826 P
->componentInfoCb
.rowBytes
= be2me_32(imgRect
.right
/ 2);
827 P
->componentInfoCr
.rowBytes
= be2me_32(imgRect
.right
/ 2);
828 image_buffer_size
= image_size
+ sizeof(PlanarPixmapInfoYUV420
);
832 image_buffer_size
= image_size
;
836 qterr
= DecompressSequenceBeginS(&seqId
,
840 GetWindowPort(theWindow
),
843 ((d_width
!= width
) || (d_height
!= height
)) ?
848 codecLosslessQuality
,
853 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr
);
861 RepositionWindow(theWindow
, NULL
, kWindowCenterOnMainScreen
);
862 ShowWindow (theWindow
);
874 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
883 static void check_events(void)
886 EventTargetRef theTarget
;
890 theTarget
= GetEventDispatcherTarget();
891 theErr
= ReceiveNextEvent(0, 0, kEventDurationNoWait
,true, &theEvent
);
892 if(theErr
== noErr
&& theEvent
!= NULL
)
894 SendEventToEventTarget (theEvent
, theTarget
);
895 ReleaseEvent(theEvent
);
899 static void draw_osd(void)
901 vo_draw_text(imgRect
.right
,imgRect
.bottom
,draw_alpha
);
904 static void flip_page(void)
907 static int lastTime
= 0;
909 if(theWindow
== NULL
)
912 switch (image_format
)
916 CGContextDrawImage (context
, bounds
, image
);
928 CodecFlags flags
= 0;
929 qterr
= DecompressSequenceFrameWhen(seqId
,
932 0, //codecFlagUseImageBuffer,
938 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr
, flags
);
947 CGContextBeginPath(context
);
948 CGContextSetAllowsAntialiasing(context
, false);
949 //CGContextSaveGState(context);
952 CGContextSetRGBStrokeColor (context
, 0.2, 0.2, 0.2, 0.5);
953 CGContextMoveToPoint( context
, winRect
.right
-1, 1); CGContextAddLineToPoint( context
, winRect
.right
-1, 1);
954 CGContextMoveToPoint( context
, winRect
.right
-1, 5); CGContextAddLineToPoint( context
, winRect
.right
-5, 1);
955 CGContextMoveToPoint( context
, winRect
.right
-1, 9); CGContextAddLineToPoint( context
, winRect
.right
-9, 1);
956 CGContextStrokePath( context
);
959 CGContextSetRGBStrokeColor (context
, 0.4, 0.4, 0.4, 0.5);
960 CGContextMoveToPoint( context
, winRect
.right
-1, 2); CGContextAddLineToPoint( context
, winRect
.right
-2, 1);
961 CGContextMoveToPoint( context
, winRect
.right
-1, 6); CGContextAddLineToPoint( context
, winRect
.right
-6, 1);
962 CGContextMoveToPoint( context
, winRect
.right
-1, 10); CGContextAddLineToPoint( context
, winRect
.right
-10, 1);
963 CGContextStrokePath( context
);
966 CGContextSetRGBStrokeColor (context
, 0.6, 0.6, 0.6, 0.5);
967 CGContextMoveToPoint( context
, winRect
.right
-1, 3); CGContextAddLineToPoint( context
, winRect
.right
-3, 1);
968 CGContextMoveToPoint( context
, winRect
.right
-1, 7); CGContextAddLineToPoint( context
, winRect
.right
-7, 1);
969 CGContextMoveToPoint( context
, winRect
.right
-1, 11); CGContextAddLineToPoint( context
, winRect
.right
-11, 1);
970 CGContextStrokePath( context
);
972 //CGContextRestoreGState( context );
973 CGContextFlush (context
);
976 //auto hide mouse cursor and futur on-screen control?
977 if(vo_quartz_fs
&& !mouseHide
)
979 int curTime
= TickCount()/60;
980 static int lastTime
= 0;
982 if( ((curTime
- lastTime
) >= 5) || (lastTime
== 0) )
984 CGDisplayHideCursor(kCGDirectMainDisplay
);
990 //update activity every 30 seconds to prevent
991 //screensaver from starting up.
992 curTime
= TickCount()/60;
994 if( ((curTime
- lastTime
) >= 30) || (lastTime
== 0) )
996 UpdateSystemActivity(UsrActivity
);
1001 static int draw_slice(uint8_t *src
[], int stride
[], int w
,int h
,int x
,int y
)
1003 switch (image_format
)
1007 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1008 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1010 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1011 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1015 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1016 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1018 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1019 memcpy_pic(((char*)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1025 static int draw_frame(uint8_t *src
[])
1027 switch (image_format
)
1030 fast_memcpy(image_data
,src
[0],image_size
);
1035 memcpy_pic(((char*)P
), src
[0], imgRect
.right
* 2, imgRect
.bottom
, imgRect
.right
* 2, imgRect
.right
* 2);
1041 static int query_format(uint32_t format
)
1043 image_format
= format
;
1046 if (format
== IMGFMT_RGB32
)
1048 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1051 if ((format
== IMGFMT_YV12
) || (format
== IMGFMT_IYUV
) || (format
== IMGFMT_I420
))
1053 image_qtcodec
= kMpegYUV420CodecType
; //kYUV420CodecType ?;
1054 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1057 if (format
== IMGFMT_YUY2
)
1059 image_qtcodec
= kComponentVideoUnsigned
;
1060 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1063 if (format
== IMGFMT_UYVY
)
1065 image_qtcodec
= k422YpCbCr8CodecType
;
1066 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1072 static void uninit(void)
1076 switch (image_format
)
1084 if (EnterMoviesDone
)
1086 qterr
= CDSequenceEnd(seqId
);
1089 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: CDSequenceEnd (%d)\n", qterr
);
1101 static int preinit(const char *arg
)
1107 char *parse_pos
= (char *)&arg
[0];
1108 while (parse_pos
[0] && !parse_err
)
1110 if (strncmp (parse_pos
, "device_id=", 10) == 0)
1112 parse_pos
= &parse_pos
[10];
1113 device_id
= strtol(parse_pos
, &parse_pos
, 0);
1115 if (strncmp (parse_pos
, "fs_res=", 7) == 0)
1117 parse_pos
= &parse_pos
[7];
1118 fs_res_x
= strtol(parse_pos
, &parse_pos
, 0);
1119 parse_pos
= &parse_pos
[1];
1120 fs_res_y
= strtol(parse_pos
, &parse_pos
, 0);
1122 if (parse_pos
[0] == ':') parse_pos
= &parse_pos
[1];
1123 else if (parse_pos
[0]) parse_err
= 1;
1127 #if !defined (MACOSX_FINDER_SUPPORT) || !defined (HAVE_SDL)
1128 //this chunk of code is heavily based off SDL_macosx.m from SDL
1129 //it uses an Apple private function to request foreground operation
1131 void CPSEnableForegroundOperation(ProcessSerialNumber
* psn
);
1132 ProcessSerialNumber myProc
, frProc
;
1135 if (GetFrontProcess(&frProc
) == noErr
)
1137 if (GetCurrentProcess(&myProc
) == noErr
)
1139 if (SameProcess(&frProc
, &myProc
, &sameProc
) == noErr
&& !sameProc
)
1141 CPSEnableForegroundOperation(&myProc
);
1143 SetFrontProcess(&myProc
);
1152 static uint32_t draw_yuv_image(mp_image_t
*mpi
)
1154 // ATM we're only called for planar IMGFMT
1155 // drawing is done directly in P
1156 // and displaying is in flip_page.
1157 return get_image_done
? VO_TRUE
: VO_FALSE
;
1160 static uint32_t get_yuv_image(mp_image_t
*mpi
)
1162 if(mpi
->type
!=MP_IMGTYPE_EXPORT
) return VO_FALSE
;
1164 if(mpi
->imgfmt
!=image_format
) return VO_FALSE
;
1166 if(mpi
->flags
&MP_IMGFLAG_PLANAR
)
1168 if (mpi
->num_planes
!= 3)
1170 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi
->num_planes
);
1174 mpi
->planes
[0]=((char*)P
) + be2me_32(P
->componentInfoY
.offset
);
1175 mpi
->stride
[0]=imgRect
.right
;
1176 mpi
->width
=imgRect
.right
;
1178 if(mpi
->flags
&MP_IMGFLAG_SWAPPED
)
1181 mpi
->planes
[1]=((char*)P
) + be2me_32(P
->componentInfoCb
.offset
);
1182 mpi
->planes
[2]=((char*)P
) + be2me_32(P
->componentInfoCr
.offset
);
1183 mpi
->stride
[1]=imgRect
.right
/2;
1184 mpi
->stride
[2]=imgRect
.right
/2;
1189 mpi
->planes
[1]=((char*)P
) + be2me_32(P
->componentInfoCr
.offset
);
1190 mpi
->planes
[2]=((char*)P
) + be2me_32(P
->componentInfoCb
.offset
);
1191 mpi
->stride
[1]=imgRect
.right
/2;
1192 mpi
->stride
[2]=imgRect
.right
/2;
1195 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1202 if (mpi
->num_planes
!= 1)
1204 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi
->num_planes
);
1208 mpi
->planes
[0] = (char*)P
;
1209 mpi
->stride
[0] = imgRect
.right
* 2;
1210 mpi
->width
=imgRect
.right
;
1211 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1218 static int control(uint32_t request
, void *data
, ...)
1222 case VOCTRL_PAUSE
: return (int_pause
=1);
1223 case VOCTRL_RESUME
: return (int_pause
=0);
1224 case VOCTRL_FULLSCREEN
: vo_fs
= (!(vo_fs
)); window_fullscreen(); return VO_TRUE
;
1225 case VOCTRL_ONTOP
: vo_ontop
= (!(vo_ontop
)); window_ontop(); return VO_TRUE
;
1226 case VOCTRL_QUERY_FORMAT
: return query_format(*((uint32_t*)data
));
1227 case VOCTRL_GET_PANSCAN
: return VO_TRUE
;
1228 case VOCTRL_SET_PANSCAN
: window_panscan(); return VO_TRUE
;
1230 case VOCTRL_GET_IMAGE
:
1231 switch (image_format
)
1238 return get_yuv_image(data
);
1243 case VOCTRL_DRAW_IMAGE
:
1244 switch (image_format
)
1251 return draw_yuv_image(data
);
1260 void window_resized()
1272 GetPortBounds( GetWindowPort(theWindow
), &winRect
);
1276 aspect( &d_width
, &d_height
, A_NOZOOM
);
1277 d_height
= ((float)d_width
/movie_aspect
);
1279 aspectX
= (float)((float)winRect
.right
/(float)d_width
);
1280 aspectY
= (float)((float)(winRect
.bottom
)/(float)d_height
);
1282 if((d_height
*aspectX
)>(winRect
.bottom
))
1284 padding
= (winRect
.right
- d_width
*aspectY
)/2;
1285 SetRect(&dstRect
, padding
, 0, d_width
*aspectY
+padding
, d_height
*aspectY
);
1289 padding
= ((winRect
.bottom
) - d_height
*aspectX
)/2;
1290 SetRect(&dstRect
, 0, padding
, (d_width
*aspectX
), d_height
*aspectX
+padding
);
1295 SetRect(&dstRect
, 0, 0, winRect
.right
, winRect
.bottom
);
1298 switch (image_format
)
1302 bounds
= CGRectMake(dstRect
.left
, dstRect
.top
, dstRect
.right
-dstRect
.left
, dstRect
.bottom
-dstRect
.top
);
1303 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
1312 long scale_X
= FixDiv(Long2Fix(dstRect
.right
- dstRect
.left
),Long2Fix(imgRect
.right
));
1313 long scale_Y
= FixDiv(Long2Fix(dstRect
.bottom
- dstRect
.top
),Long2Fix(imgRect
.bottom
));
1315 SetIdentityMatrix(&matrix
);
1316 if (((dstRect
.right
- dstRect
.left
) != imgRect
.right
) || ((dstRect
.bottom
- dstRect
.right
) != imgRect
.bottom
))
1318 ScaleMatrix(&matrix
, scale_X
, scale_Y
, 0, 0);
1322 TranslateMatrix(&matrix
, Long2Fix(dstRect
.left
), Long2Fix(dstRect
.top
));
1326 SetDSequenceMatrix(seqId
, &matrix
);
1334 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
1335 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
1336 CGContextFillRect(context
, tmpBounds
);
1343 //Cycle between level
1348 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
1351 void window_fullscreen()
1353 static Ptr restoreState
= NULL
;
1362 SetSystemUIMode( kUIModeAllHidden
, kUIOptionAutoShowMenuBar
);
1363 CGDisplayHideCursor(kCGDirectMainDisplay
);
1367 if(fs_res_x
!= 0 || fs_res_y
!= 0)
1369 BeginFullScreen( &restoreState
, deviceHdl
, &fs_res_x
, &fs_res_y
, NULL
, NULL
, 0);
1371 //Get Main device info///////////////////////////////////////////////////
1372 deviceRect
= (*deviceHdl
)->gdRect
;
1374 device_width
= deviceRect
.right
;
1375 device_height
= deviceRect
.bottom
;
1379 //save old window size
1382 GetWindowPortBounds(theWindow
, &oldWinRect
);
1383 GetWindowBounds(theWindow
, kWindowContentRgn
, &oldWinBounds
);
1388 ChangeWindowAttributes(theWindow
, kWindowNoShadowAttribute
, 0);
1389 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1390 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);
1394 else //go back to windowed mode
1397 if(restoreState
!= NULL
)
1399 EndFullScreen(restoreState
, 0);
1401 //Get Main device info///////////////////////////////////////////////////
1402 deviceRect
= (*deviceHdl
)->gdRect
;
1404 device_width
= deviceRect
.right
;
1405 device_height
= deviceRect
.bottom
;
1406 restoreState
= NULL
;
1408 SetSystemUIMode( kUIModeNormal
, 0);
1411 CGDisplayShowCursor(kCGDirectMainDisplay
);
1414 //revert window to previous setting
1415 ChangeWindowAttributes(theWindow
, 0, kWindowNoShadowAttribute
);
1416 SizeWindow(theWindow
, oldWinRect
.right
, oldWinRect
.bottom
,1);
1417 MoveWindow(theWindow
, oldWinBounds
.left
, oldWinBounds
.top
, 1);
1422 void window_panscan()
1427 CheckMenuItem (aspectMenu
, 2, 1);
1429 CheckMenuItem (aspectMenu
, 2, 0);
1433 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1434 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);