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"
34 #include "input/input.h"
35 #include "input/mouse.h"
37 #include "vo_quartz.h"
39 static vo_info_t info
=
43 "Nicolas Plourde <nicolasplourde@hotmail.com>, Romain Dolbeau <romain@dolbeau.org>",
49 static uint32_t image_depth
;
50 static uint32_t image_format
;
51 static uint32_t image_size
;
52 static uint32_t image_buffer_size
;
53 static char *image_data
;
55 static ImageSequence seqId
;
56 static CodecType image_qtcodec
;
57 static PlanarPixmapInfoYUV420
*P
= NULL
;
60 ImageDescriptionHandle desc
;
61 Handle extension_colr
;
62 Handle extension_fiel
;
63 Handle extension_clap
;
64 Handle extension_pasp
;
66 static MatrixRecord matrix
;
67 static int EnterMoviesDone
= 0;
68 static int get_image_done
= 0;
70 static int vo_quartz_fs
; // we are in fullscreen
71 extern float monitor_aspect
;
72 extern float movie_aspect
;
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 CGImageAlphaInfo alphaInfo
;
102 static CGImageRef image
;
104 static Rect imgRect
; // size of the original image (unscaled)
105 static Rect dstRect
; // size of the displayed image (after scaling)
106 static Rect winRect
; // size of the window containg the displayed image (include padding)
107 static Rect oldWinRect
; // size of the window containg the displayed image (include padding) when NOT in FS mode
108 static Rect deviceRect
; // size of the display device
109 static Rect oldWinBounds
;
111 static MenuRef windMenu
;
112 static MenuRef movMenu
;
113 static MenuRef aspectMenu
;
119 kNormalScreenCmd
= 3,
120 kDoubleScreenCmd
= 4,
129 #include "osdep/keycodes.h"
131 extern void mplayer_put_key(int code
);
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_BACKSPACE
;
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
) + 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 1: mplayer_put_key(MOUSE_BTN0
);break;
338 case 2: mplayer_put_key(MOUSE_BTN2
);break;
339 case 3: mplayer_put_key(MOUSE_BTN1
);break;
341 default:result
= eventNotHandledErr
;break;
350 case kEventMouseDragged
:
353 default:result
= eventNotHandledErr
;break;
360 //default window event handler
361 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
363 OSStatus result
= noErr
;
366 UInt32
class = GetEventClass (event
);
367 UInt32 kind
= GetEventKind (event
);
369 result
= CallNextEventHandler(nextHandler
, event
);
371 aspect(&d_width
,&d_height
,A_NOZOOM
);
373 if(class == kEventClassCommand
)
375 HICommand theHICommand
;
376 GetEventParameter( event
, kEventParamDirectObject
, typeHICommand
, NULL
, sizeof( HICommand
), NULL
, &theHICommand
);
378 switch ( theHICommand
.commandID
)
381 mplayer_put_key(KEY_CLOSE_WIN
);
387 vo_fs
= (!(vo_fs
)); window_fullscreen();
390 SizeWindow(theWindow
, (d_width
/2), ((d_width
/movie_aspect
)/2), 1);
394 case kNormalScreenCmd
:
397 vo_fs
= (!(vo_fs
)); window_fullscreen();
400 SizeWindow(theWindow
, d_width
, (d_width
/movie_aspect
), 1);
404 case kDoubleScreenCmd
:
407 vo_fs
= (!(vo_fs
)); window_fullscreen();
410 SizeWindow(theWindow
, (d_width
*2), ((d_width
/movie_aspect
)*2), 1);
415 vo_fs
= (!(vo_fs
)); window_fullscreen();
419 vo_keepaspect
= (!(vo_keepaspect
));
420 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
425 movie_aspect
= old_movie_aspect
;
428 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
434 movie_aspect
= 4.0f
/3.0f
;
437 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
443 movie_aspect
= 16.0f
/9.0f
;
446 SizeWindow(theWindow
, dstRect
.right
, (dstRect
.right
/movie_aspect
),1);
452 vo_panscan
= (!(vo_panscan
));
453 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
459 result
= eventNotHandledErr
;
463 else if(class == kEventClassWindow
)
466 Rect rectPort
= {0,0,0,0};
468 GetEventParameter(event
, kEventParamDirectObject
, typeWindowRef
, NULL
, sizeof(WindowRef
), NULL
, &window
);
472 GetPortBounds(GetWindowPort(window
), &rectPort
);
477 case kEventWindowClosed
:
479 mplayer_put_key(KEY_CLOSE_WIN
);
483 case kEventWindowZoomed
:
484 case kEventWindowBoundsChanged
:
491 result
= eventNotHandledErr
;
499 static void quartz_CreateWindow(uint32_t d_width
, uint32_t d_height
, WindowAttributes windowAttrs
)
501 CFStringRef titleKey
;
502 CFStringRef windowTitle
;
506 CFStringRef movMenuTitle
;
507 CFStringRef aspMenuTitle
;
509 SetRect(&winRect
, 0, 0, d_width
, d_height
);
510 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
511 SetRect(&dstRect
, 0, 0, d_width
, d_height
);
517 CreateStandardWindowMenu(0, &windMenu
);
518 InsertMenu(windMenu
, 0);
521 CreateNewMenu (1004, 0, &movMenu
);
522 movMenuTitle
= CFSTR("Movie");
523 SetMenuTitleWithCFString(movMenu
, movMenuTitle
);
525 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Half Size"), 0, kHalfScreenCmd
, &index
);
526 SetMenuItemCommandKey(movMenu
, index
, 0, '0');
528 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Normal Size"), 0, kNormalScreenCmd
, &index
);
529 SetMenuItemCommandKey(movMenu
, index
, 0, '1');
531 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Double Size"), 0, kDoubleScreenCmd
, &index
);
532 SetMenuItemCommandKey(movMenu
, index
, 0, '2');
534 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Full Size"), 0, kFullScreenCmd
, &index
);
535 SetMenuItemCommandKey(movMenu
, index
, 0, 'F');
537 AppendMenuItemTextWithCFString(movMenu
, NULL
, kMenuItemAttrSeparator
, NULL
, &index
);
539 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Aspect Ratio"), 0, NULL
, &index
);
541 ////Create Aspect Ratio Sub Menu
542 CreateNewMenu (0, 0, &aspectMenu
);
543 aspMenuTitle
= CFSTR("Aspect Ratio");
544 SetMenuTitleWithCFString(aspectMenu
, aspMenuTitle
);
545 SetMenuItemHierarchicalMenu(movMenu
, 6, aspectMenu
);
547 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Keep"), 0, kKeepAspectCmd
, &index
);
548 CheckMenuItem (aspectMenu
, 1, vo_keepaspect
);
549 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Pan-Scan"), 0, kPanScanCmd
, &index
);
550 CheckMenuItem (aspectMenu
, 2, vo_panscan
);
551 AppendMenuItemTextWithCFString(aspectMenu
, NULL
, kMenuItemAttrSeparator
, NULL
, &index
);
552 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Original"), 0, kAspectOrgCmd
, &index
);
553 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("4:3"), 0, kAspectFullCmd
, &index
);
554 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("16:9"), 0, kAspectWideCmd
, &index
);
556 InsertMenu(movMenu
, GetMenuID(windMenu
)); //insert before Window menu
561 CreateNewWindow(kDocumentWindowClass
, windowAttrs
, &winRect
, &theWindow
);
563 CreateWindowGroup(0, &winGroup
);
564 SetWindowGroup(theWindow
, winGroup
);
567 titleKey
= CFSTR("MPlayer - The Movie Player");
568 windowTitle
= CFCopyLocalizedString(titleKey
, NULL
);
569 result
= SetWindowTitleWithCFString(theWindow
, windowTitle
);
571 CFRelease(windowTitle
);
573 //Install event handler
574 const EventTypeSpec win_events
[] = {
575 { kEventClassWindow
, kEventWindowClosed
},
576 { kEventClassWindow
, kEventWindowBoundsChanged
},
577 { kEventClassCommand
, kEventCommandProcess
}
580 const EventTypeSpec key_events
[] = {
581 { kEventClassKeyboard
, kEventRawKeyDown
},
582 { kEventClassKeyboard
, kEventRawKeyRepeat
}
585 const EventTypeSpec mouse_events
[] = {
586 { kEventClassMouse
, kEventMouseMoved
},
587 { kEventClassMouse
, kEventMouseWheelMoved
},
588 { kEventClassMouse
, kEventMouseDown
},
589 { kEventClassMouse
, kEventMouseUp
},
590 { kEventClassMouse
, kEventMouseDragged
}
593 InstallApplicationEventHandler (NewEventHandlerUPP (KeyEventHandler
), GetEventTypeCount(key_events
), key_events
, NULL
, NULL
);
594 InstallApplicationEventHandler (NewEventHandlerUPP (MouseEventHandler
), GetEventTypeCount(mouse_events
), mouse_events
, NULL
, NULL
);
595 InstallWindowEventHandler (theWindow
, NewEventHandlerUPP (WindowEventHandler
), GetEventTypeCount(win_events
), win_events
, theWindow
, NULL
);
598 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
)
600 WindowAttributes windowAttrs
;
605 //Get Main device info///////////////////////////////////////////////////
608 deviceHdl
= GetMainDevice();
610 for(i
=0; i
<device_id
; i
++)
612 deviceHdl
= GetNextDevice(deviceHdl
);
614 if(deviceHdl
== NULL
)
616 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id
);
617 deviceHdl
= GetMainDevice();
623 deviceRect
= (*deviceHdl
)->gdRect
;
624 device_width
= deviceRect
.right
-deviceRect
.left
;
625 device_height
= deviceRect
.bottom
-deviceRect
.top
;
627 monitor_aspect
= (float)device_width
/(float)device_height
;
629 //misc mplayer setup/////////////////////////////////////////////////////
630 SetRect(&imgRect
, 0, 0, width
, height
);
631 switch (image_format
)
644 image_size
= ((imgRect
.right
*imgRect
.bottom
*image_depth
)+7)/8;
646 vo_fs
= flags
& VOFLAG_FULLSCREEN
;
650 aspect_save_orig(width
,height
);
651 aspect_save_prescale(d_width
,d_height
);
652 aspect_save_screenres(device_width
, device_height
);
654 aspect(&d_width
,&d_height
,A_NOZOOM
);
656 movie_aspect
= (float)d_width
/(float)d_height
;
657 old_movie_aspect
= movie_aspect
;
662 image_data
= malloc(image_size
);
664 //Create player window//////////////////////////////////////////////////
665 windowAttrs
= kWindowStandardDocumentAttributes
666 | kWindowStandardHandlerAttribute
667 | kWindowLiveResizeAttribute
;
669 windowAttrs
&= (~kWindowResizableAttribute
);
671 if (theWindow
== NULL
)
673 quartz_CreateWindow(d_width
, d_height
, windowAttrs
);
675 if (theWindow
== NULL
)
677 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Couldn't create window !!!!!\n");
680 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
681 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
682 CGContextFillRect(context
, tmpBounds
);
686 HideWindow(theWindow
);
687 ChangeWindowAttributes(theWindow
, ~windowAttrs
, windowAttrs
);
688 SetRect(&winRect
, 0, 0, d_width
, d_height
);
689 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
690 SizeWindow (theWindow
, d_width
, d_height
, 1);
693 switch (image_format
)
697 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
699 dataProviderRef
= CGDataProviderCreateWithData (0, image_data
, imgRect
.right
* imgRect
.bottom
* 4, 0);
701 image
= CGImageCreate (imgRect
.right
,
705 ((imgRect
.right
*32)+7)/8,
706 CGColorSpaceCreateDeviceRGB(),
707 kCGImageAlphaNoneSkipFirst
,
708 dataProviderRef
, 0, 1, kCGRenderingIntentDefault
);
720 if (!EnterMoviesDone
)
722 qterr
= EnterMovies();
730 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: EnterMovies (%d)\n", qterr
);
735 SetIdentityMatrix(&matrix
);
737 if ((d_width
!= width
) || (d_height
!= height
))
739 ScaleMatrix(&matrix
, FixDiv(Long2Fix(d_width
),Long2Fix(width
)), FixDiv(Long2Fix(d_height
),Long2Fix(height
)), 0, 0);
742 yuv_qt_stuff
.desc
= (ImageDescriptionHandle
)NewHandleClear( sizeof(ImageDescription
) );
744 yuv_qt_stuff
.extension_colr
= NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension
));
745 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->colorParamType
= kVideoColorInfoImageDescriptionExtensionType
;
746 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->primaries
= 2;
747 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->transferFunction
= 2;
748 ((NCLCColorInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_colr
))->matrix
= 2;
750 yuv_qt_stuff
.extension_fiel
= NewHandleClear(sizeof(FieldInfoImageDescriptionExtension
));
751 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldCount
= 1;
752 ((FieldInfoImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_fiel
))->fieldOrderings
= 0;
754 yuv_qt_stuff
.extension_clap
= NewHandleClear(sizeof(CleanApertureImageDescriptionExtension
));
755 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthN
= imgRect
.right
;
756 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthD
= 1;
757 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightN
= imgRect
.bottom
;
758 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightD
= 1;
759 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffN
= 0;
760 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->horizOffD
= 1;
761 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffN
= 0;
762 ((CleanApertureImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_clap
))->vertOffD
= 1;
764 yuv_qt_stuff
.extension_pasp
= NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension
));
765 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->hSpacing
= 1;
766 ((PixelAspectRatioImageDescriptionExtension
*)(*yuv_qt_stuff
.extension_pasp
))->vSpacing
= 1;
768 (*yuv_qt_stuff
.desc
)->idSize
= sizeof(ImageDescription
);
769 (*yuv_qt_stuff
.desc
)->cType
= image_qtcodec
;
770 (*yuv_qt_stuff
.desc
)->version
= 2;
771 (*yuv_qt_stuff
.desc
)->revisionLevel
= 0;
772 (*yuv_qt_stuff
.desc
)->vendor
= 'mpla';
773 (*yuv_qt_stuff
.desc
)->width
= imgRect
.right
;
774 (*yuv_qt_stuff
.desc
)->height
= imgRect
.bottom
;
775 (*yuv_qt_stuff
.desc
)->hRes
= Long2Fix(72);
776 (*yuv_qt_stuff
.desc
)->vRes
= Long2Fix(72);
777 (*yuv_qt_stuff
.desc
)->temporalQuality
= 0;
778 (*yuv_qt_stuff
.desc
)->spatialQuality
= codecLosslessQuality
;
779 (*yuv_qt_stuff
.desc
)->frameCount
= 1;
780 (*yuv_qt_stuff
.desc
)->dataSize
= 0;
781 (*yuv_qt_stuff
.desc
)->depth
= 24;
782 (*yuv_qt_stuff
.desc
)->clutID
= -1;
784 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_colr
, kColorInfoImageDescriptionExtension
);
787 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr
);
790 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_fiel
, kFieldInfoImageDescriptionExtension
);
793 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr
);
796 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_clap
, kCleanApertureImageDescriptionExtension
);
799 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr
);
802 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_pasp
, kCleanApertureImageDescriptionExtension
);
805 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr
);
807 if (P
!= NULL
) { // second or subsequent movie
810 P
= calloc(sizeof(PlanarPixmapInfoYUV420
) + image_size
, 1);
811 switch (image_format
)
816 P
->componentInfoY
.offset
= sizeof(PlanarPixmapInfoYUV420
);
817 P
->componentInfoCb
.offset
= P
->componentInfoY
.offset
+ image_size
/ 2;
818 P
->componentInfoCr
.offset
= P
->componentInfoCb
.offset
+ image_size
/ 4;
819 P
->componentInfoY
.rowBytes
= imgRect
.right
;
820 P
->componentInfoCb
.rowBytes
= imgRect
.right
/ 2;
821 P
->componentInfoCr
.rowBytes
= imgRect
.right
/ 2;
822 image_buffer_size
= image_size
+ sizeof(PlanarPixmapInfoYUV420
);
826 image_buffer_size
= image_size
;
830 qterr
= DecompressSequenceBeginS(&seqId
,
834 GetWindowPort(theWindow
),
837 ((d_width
!= width
) || (d_height
!= height
)) ?
842 codecLosslessQuality
,
847 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr
);
855 RepositionWindow(theWindow
, NULL
, kWindowCenterOnMainScreen
);
856 ShowWindow (theWindow
);
868 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
877 static void check_events(void)
880 EventTargetRef theTarget
;
884 theTarget
= GetEventDispatcherTarget();
885 theErr
= ReceiveNextEvent(0, 0, kEventDurationNoWait
,true, &theEvent
);
886 if(theErr
== noErr
&& theEvent
!= NULL
)
888 SendEventToEventTarget (theEvent
, theTarget
);
889 ReleaseEvent(theEvent
);
893 static void draw_osd(void)
895 vo_draw_text(imgRect
.right
,imgRect
.bottom
,draw_alpha
);
898 static void flip_page(void)
900 if(theWindow
== NULL
)
903 switch (image_format
)
907 CGContextDrawImage (context
, bounds
, image
);
919 CodecFlags flags
= 0;
920 qterr
= DecompressSequenceFrameWhen(seqId
,
923 0, //codecFlagUseImageBuffer,
929 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr
, flags
);
938 CGContextBeginPath(context
);
939 CGContextSetAllowsAntialiasing(context
, false);
940 //CGContextSaveGState(context);
943 CGContextSetRGBStrokeColor (context
, 0.2, 0.2, 0.2, 0.5);
944 CGContextMoveToPoint( context
, winRect
.right
-1, 1); CGContextAddLineToPoint( context
, winRect
.right
-1, 1);
945 CGContextMoveToPoint( context
, winRect
.right
-1, 5); CGContextAddLineToPoint( context
, winRect
.right
-5, 1);
946 CGContextMoveToPoint( context
, winRect
.right
-1, 9); CGContextAddLineToPoint( context
, winRect
.right
-9, 1);
947 CGContextStrokePath( context
);
950 CGContextSetRGBStrokeColor (context
, 0.4, 0.4, 0.4, 0.5);
951 CGContextMoveToPoint( context
, winRect
.right
-1, 2); CGContextAddLineToPoint( context
, winRect
.right
-2, 1);
952 CGContextMoveToPoint( context
, winRect
.right
-1, 6); CGContextAddLineToPoint( context
, winRect
.right
-6, 1);
953 CGContextMoveToPoint( context
, winRect
.right
-1, 10); CGContextAddLineToPoint( context
, winRect
.right
-10, 1);
954 CGContextStrokePath( context
);
957 CGContextSetRGBStrokeColor (context
, 0.6, 0.6, 0.6, 0.5);
958 CGContextMoveToPoint( context
, winRect
.right
-1, 3); CGContextAddLineToPoint( context
, winRect
.right
-3, 1);
959 CGContextMoveToPoint( context
, winRect
.right
-1, 7); CGContextAddLineToPoint( context
, winRect
.right
-7, 1);
960 CGContextMoveToPoint( context
, winRect
.right
-1, 11); CGContextAddLineToPoint( context
, winRect
.right
-11, 1);
961 CGContextStrokePath( context
);
963 //CGContextRestoreGState( context );
964 CGContextFlush (context
);
967 //auto hide mouse cursor and futur on-screen control?
968 if(vo_quartz_fs
&& !mouseHide
)
970 int curTime
= TickCount()/60;
971 static int lastTime
= 0;
973 if( ((curTime
- lastTime
) >= 5) || (lastTime
== 0) )
975 CGDisplayHideCursor(kCGDirectMainDisplay
);
981 //update activity every 30 seconds to prevent
982 //screensaver from starting up.
983 int curTime
= TickCount()/60;
984 static int lastTime
= 0;
986 if( ((curTime
/ - lastTime
) >= 5) || (lastTime
== 0) )
988 UpdateSystemActivity(UsrActivity
);
993 static int draw_slice(uint8_t *src
[], int stride
[], int w
,int h
,int x
,int y
)
995 switch (image_format
)
999 memcpy_pic(((char*)P
) + P
->componentInfoY
.offset
+ x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
1000 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
1002 memcpy_pic(((char*)P
) + P
->componentInfoCb
.offset
+ x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1003 memcpy_pic(((char*)P
) + P
->componentInfoCr
.offset
+ x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1007 memcpy_pic(((char*)P
) + 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
) + P
->componentInfoCr
.offset
+ x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
1011 memcpy_pic(((char*)P
) + P
->componentInfoCb
.offset
+ x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1017 static int draw_frame(uint8_t *src
[])
1019 switch (image_format
)
1022 memcpy(image_data
,src
[0],image_size
);
1027 memcpy_pic(((char*)P
), src
[0], imgRect
.right
* 2, imgRect
.bottom
, imgRect
.right
* 2, imgRect
.right
* 2);
1033 static int query_format(uint32_t format
)
1035 image_format
= format
;
1038 if (format
== IMGFMT_RGB32
)
1040 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1043 if ((format
== IMGFMT_YV12
) || (format
== IMGFMT_IYUV
) || (format
== IMGFMT_I420
))
1045 image_qtcodec
= kMpegYUV420CodecType
; //kYUV420CodecType ?;
1046 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1049 if (format
== IMGFMT_YUY2
)
1051 image_qtcodec
= kComponentVideoUnsigned
;
1052 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1055 if (format
== IMGFMT_UYVY
)
1057 image_qtcodec
= k422YpCbCr8CodecType
;
1058 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1064 static void uninit(void)
1068 switch (image_format
)
1076 if (EnterMoviesDone
)
1078 qterr
= CDSequenceEnd(seqId
);
1081 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: CDSequenceEnd (%d)\n", qterr
);
1093 static int preinit(const char *arg
)
1099 char *parse_pos
= (char *)&arg
[0];
1100 while (parse_pos
[0] && !parse_err
)
1102 if (strncmp (parse_pos
, "device_id=", 10) == 0)
1104 parse_pos
= &parse_pos
[10];
1105 device_id
= strtol(parse_pos
, &parse_pos
, 0);
1107 if (strncmp (parse_pos
, "fs_res=", 7) == 0)
1109 parse_pos
= &parse_pos
[7];
1110 fs_res_x
= strtol(parse_pos
, &parse_pos
, 0);
1111 parse_pos
= &parse_pos
[1];
1112 fs_res_y
= strtol(parse_pos
, &parse_pos
, 0);
1114 if (parse_pos
[0] == ':') parse_pos
= &parse_pos
[1];
1115 else if (parse_pos
[0]) parse_err
= 1;
1119 #if !defined (MACOSX_FINDER_SUPPORT) || !defined (HAVE_SDL)
1120 //this chunk of code is heavily based off SDL_macosx.m from SDL
1121 //it uses an Apple private function to request foreground operation
1123 void CPSEnableForegroundOperation(ProcessSerialNumber
* psn
);
1124 ProcessSerialNumber myProc
, frProc
;
1127 if (GetFrontProcess(&frProc
) == noErr
)
1129 if (GetCurrentProcess(&myProc
) == noErr
)
1131 if (SameProcess(&frProc
, &myProc
, &sameProc
) == noErr
&& !sameProc
)
1133 CPSEnableForegroundOperation(&myProc
);
1135 SetFrontProcess(&myProc
);
1143 static uint32_t draw_yuv_image(mp_image_t
*mpi
)
1145 // ATM we're only called for planar IMGFMT
1146 // drawing is done directly in P
1147 // and displaying is in flip_page.
1148 return get_image_done
? VO_TRUE
: VO_FALSE
;
1151 static uint32_t get_yuv_image(mp_image_t
*mpi
)
1153 if(mpi
->type
!=MP_IMGTYPE_EXPORT
) return VO_FALSE
;
1155 if(mpi
->imgfmt
!=image_format
) return VO_FALSE
;
1157 if(mpi
->flags
&MP_IMGFLAG_PLANAR
)
1159 if (mpi
->num_planes
!= 3)
1161 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi
->num_planes
);
1165 mpi
->planes
[0]=((char*)P
) + P
->componentInfoY
.offset
;
1166 mpi
->stride
[0]=imgRect
.right
;
1167 mpi
->width
=imgRect
.right
;
1169 if(mpi
->flags
&MP_IMGFLAG_SWAPPED
)
1172 mpi
->planes
[1]=((char*)P
) + P
->componentInfoCb
.offset
;
1173 mpi
->planes
[2]=((char*)P
) + P
->componentInfoCr
.offset
;
1174 mpi
->stride
[1]=imgRect
.right
/2;
1175 mpi
->stride
[2]=imgRect
.right
/2;
1180 mpi
->planes
[1]=((char*)P
) + P
->componentInfoCr
.offset
;
1181 mpi
->planes
[2]=((char*)P
) + P
->componentInfoCb
.offset
;
1182 mpi
->stride
[1]=imgRect
.right
/2;
1183 mpi
->stride
[2]=imgRect
.right
/2;
1186 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1193 if (mpi
->num_planes
!= 1)
1195 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi
->num_planes
);
1199 mpi
->planes
[0] = (char*)P
;
1200 mpi
->stride
[0] = imgRect
.right
* 2;
1201 mpi
->width
=imgRect
.right
;
1202 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
1209 static int control(uint32_t request
, void *data
, ...)
1213 case VOCTRL_PAUSE
: return (int_pause
=1);
1214 case VOCTRL_RESUME
: return (int_pause
=0);
1215 case VOCTRL_FULLSCREEN
: vo_fs
= (!(vo_fs
)); window_fullscreen(); return VO_TRUE
;
1216 case VOCTRL_ONTOP
: vo_ontop
= (!(vo_ontop
)); window_ontop(); return VO_TRUE
;
1217 case VOCTRL_QUERY_FORMAT
: return query_format(*((uint32_t*)data
));
1218 case VOCTRL_GET_PANSCAN
: return VO_TRUE
;
1219 case VOCTRL_SET_PANSCAN
: window_panscan(); return VO_TRUE
;
1221 case VOCTRL_GET_IMAGE
:
1222 switch (image_format
)
1229 return get_yuv_image(data
);
1234 case VOCTRL_DRAW_IMAGE
:
1235 switch (image_format
)
1242 return draw_yuv_image(data
);
1251 void window_resized()
1263 GetPortBounds( GetWindowPort(theWindow
), &winRect
);
1267 aspect( &d_width
, &d_height
, A_NOZOOM
);
1268 d_height
= ((float)d_width
/movie_aspect
);
1270 aspectX
= (float)((float)winRect
.right
/(float)d_width
);
1271 aspectY
= (float)((float)(winRect
.bottom
)/(float)d_height
);
1273 if((d_height
*aspectX
)>(winRect
.bottom
))
1275 padding
= (winRect
.right
- d_width
*aspectY
)/2;
1276 SetRect(&dstRect
, padding
, 0, d_width
*aspectY
+padding
, d_height
*aspectY
);
1280 padding
= ((winRect
.bottom
) - d_height
*aspectX
)/2;
1281 SetRect(&dstRect
, 0, padding
, (d_width
*aspectX
), d_height
*aspectX
+padding
);
1286 SetRect(&dstRect
, 0, 0, winRect
.right
, winRect
.bottom
);
1289 switch (image_format
)
1293 bounds
= CGRectMake(dstRect
.left
, dstRect
.top
, dstRect
.right
-dstRect
.left
, dstRect
.bottom
-dstRect
.top
);
1294 CreateCGContextForPort (GetWindowPort (theWindow
), &context
);
1303 long scale_X
= FixDiv(Long2Fix(dstRect
.right
- dstRect
.left
),Long2Fix(imgRect
.right
));
1304 long scale_Y
= FixDiv(Long2Fix(dstRect
.bottom
- dstRect
.top
),Long2Fix(imgRect
.bottom
));
1306 SetIdentityMatrix(&matrix
);
1307 if (((dstRect
.right
- dstRect
.left
) != imgRect
.right
) || ((dstRect
.bottom
- dstRect
.right
) != imgRect
.bottom
))
1309 ScaleMatrix(&matrix
, scale_X
, scale_Y
, 0, 0);
1313 TranslateMatrix(&matrix
, Long2Fix(dstRect
.left
), Long2Fix(dstRect
.top
));
1317 SetDSequenceMatrix(seqId
, &matrix
);
1325 tmpBounds
= CGRectMake( 0, 0, winRect
.right
, winRect
.bottom
);
1326 CreateCGContextForPort(GetWindowPort(theWindow
),&context
);
1327 CGContextFillRect(context
, tmpBounds
);
1334 //Cycle between level
1339 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
1342 void window_fullscreen()
1344 static Ptr restoreState
= NULL
;
1353 SetSystemUIMode( kUIModeAllHidden
, kUIOptionAutoShowMenuBar
);
1354 CGDisplayHideCursor(kCGDirectMainDisplay
);
1358 if(fs_res_x
!= 0 || fs_res_y
!= 0)
1360 BeginFullScreen( &restoreState
, deviceHdl
, &fs_res_x
, &fs_res_y
, NULL
, NULL
, NULL
);
1362 //Get Main device info///////////////////////////////////////////////////
1363 deviceRect
= (*deviceHdl
)->gdRect
;
1365 device_width
= deviceRect
.right
;
1366 device_height
= deviceRect
.bottom
;
1370 //save old window size
1373 GetWindowPortBounds(theWindow
, &oldWinRect
);
1374 GetWindowBounds(theWindow
, kWindowContentRgn
, &oldWinBounds
);
1379 ChangeWindowAttributes(theWindow
, kWindowNoShadowAttribute
, 0);
1380 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1381 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);
1385 else //go back to windowed mode
1388 if(restoreState
!= NULL
)
1390 EndFullScreen(restoreState
, NULL
);
1392 //Get Main device info///////////////////////////////////////////////////
1393 deviceRect
= (*deviceHdl
)->gdRect
;
1395 device_width
= deviceRect
.right
;
1396 device_height
= deviceRect
.bottom
;
1397 restoreState
= NULL
;
1399 SetSystemUIMode( kUIModeNormal
, NULL
);
1402 CGDisplayShowCursor(kCGDirectMainDisplay
);
1405 //revert window to previous setting
1406 ChangeWindowAttributes(theWindow
, 0, kWindowNoShadowAttribute
);
1407 SizeWindow(theWindow
, oldWinRect
.right
, oldWinRect
.bottom
,1);
1408 MoveWindow(theWindow
, oldWinBounds
.left
, oldWinBounds
.top
, 1);
1413 void window_panscan()
1418 CheckMenuItem (aspectMenu
, 2, 1);
1420 CheckMenuItem (aspectMenu
, 2, 0);
1424 MoveWindow(theWindow
, deviceRect
.left
-(vo_panscan_x
>> 1), deviceRect
.top
-(vo_panscan_y
>> 1), 1);
1425 SizeWindow(theWindow
, device_width
+vo_panscan_x
, device_height
+vo_panscan_y
,1);