2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 \author Nicolas Plourde <nicolasplourde@gmail.com>
22 Copyright (c) Nicolas Plourde - April 2004
24 YUV support Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
26 \brief MPlayer Mac OSX Quartz video out module.
28 \todo: -screen overlay output
29 -fit osd in black bar when available
38 #include <Carbon/Carbon.h>
39 #include <QuickTime/QuickTime.h>
43 #include "fastmemcpy.h"
44 #include "video_out.h"
45 #include "video_out_internal.h"
53 #include "input/input.h"
54 #include "input/mouse.h"
56 #include "osx_common.h"
58 static const vo_info_t info
=
62 "Nicolas Plourde <nicolasplourde@hotmail.com>, Romain Dolbeau <romain@dolbeau.org>",
66 const LIBVO_EXTERN(quartz
)
68 static uint32_t image_depth
;
69 static uint32_t image_format
;
70 static uint32_t image_size
;
71 static uint32_t image_buffer_size
;
72 static char *image_data
;
74 static ImageSequence seqId
;
75 static CodecType image_qtcodec
;
76 static PlanarPixmapInfoYUV420
*P
= NULL
;
79 ImageDescriptionHandle desc
;
80 Handle extension_colr
;
81 Handle extension_fiel
;
82 Handle extension_clap
;
83 Handle extension_pasp
;
85 static MatrixRecord matrix
;
86 static int EnterMoviesDone
= 0;
87 static int get_image_done
= 0;
89 static int vo_quartz_fs
; // we are in fullscreen
91 static int winLevel
= 1;
94 kCGDesktopWindowLevelKey
,
95 kCGNormalWindowLevelKey
,
96 kCGScreenSaverWindowLevelKey
99 static int int_pause
= 0;
100 static float winAlpha
= 1;
101 static int mouseHide
= FALSE
;
102 static float winSizeMult
= 1;
104 static int device_id
= 0;
106 static short fs_res_x
= 0;
107 static short fs_res_y
= 0;
109 static WindowRef theWindow
= NULL
;
110 static WindowGroupRef winGroup
= NULL
;
111 static CGRect bounds
;
112 static CGDirectDisplayID displayId
= 0;
113 static CFDictionaryRef originalMode
= NULL
;
115 static CGDataProviderRef dataProviderRef
= NULL
;
116 static CGImageRef image
= NULL
;
118 static Rect imgRect
; // size of the original image (unscaled)
119 static Rect dstRect
; // size of the displayed image (after scaling)
120 static Rect winRect
; // size of the window containg the displayed image (include padding)
121 static Rect oldWinRect
; // size of the window containg the displayed image (include padding) when NOT in FS mode
122 static Rect oldWinBounds
;
124 static MenuRef windMenu
;
125 static MenuRef movMenu
;
126 static MenuRef aspectMenu
;
128 static int lastScreensaverUpdate
= 0;
129 static int lastMouseHide
= 0;
134 kNormalScreenCmd
= 3,
135 kDoubleScreenCmd
= 4,
144 #include "osdep/keycodes.h"
146 //PROTOTYPE/////////////////////////////////////////////////////////////////
147 static OSStatus
KeyEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
148 static OSStatus
MouseEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
149 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
);
150 void window_resized(void);
151 void window_ontop(void);
152 void window_fullscreen(void);
153 void window_panscan(void);
155 static void draw_alpha(int x0
, int y0
, int w
, int h
, unsigned char *src
, unsigned char *srca
, int stride
)
157 switch (image_format
)
160 vo_draw_alpha_rgb32(w
, h
, src
, srca
, stride
, image_data
+ 4 * (y0
* imgRect
.right
+ x0
), 4 * imgRect
.right
);
165 vo_draw_alpha_yv12(w
, h
, src
, srca
, stride
, ((char *)P
) + be2me_32(P
->componentInfoY
.offset
) + x0
+ y0
* imgRect
.right
, imgRect
.right
);
168 vo_draw_alpha_uyvy(w
, h
, src
, srca
, stride
, ((char *)P
) + (x0
+ y0
* imgRect
.right
) * 2, imgRect
.right
* 2);
171 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
, ((char *)P
) + (x0
+ y0
* imgRect
.right
) * 2, imgRect
.right
* 2);
176 //default keyboard event handler
177 static OSStatus
KeyEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
179 OSStatus result
= noErr
;
180 UInt32
class = GetEventClass(event
);
181 UInt32 kind
= GetEventKind(event
);
183 result
= CallNextEventHandler(nextHandler
, event
);
185 if (class == kEventClassKeyboard
)
189 UInt32 macKeyModifiers
;
191 GetEventParameter(event
, kEventParamKeyMacCharCodes
, typeChar
, NULL
, sizeof(macCharCodes
), NULL
, &macCharCodes
);
192 GetEventParameter(event
, kEventParamKeyCode
, typeUInt32
, NULL
, sizeof(macKeyCode
), NULL
, &macKeyCode
);
193 GetEventParameter(event
, kEventParamKeyModifiers
, typeUInt32
, NULL
, sizeof(macKeyModifiers
), NULL
, &macKeyModifiers
);
195 if (macKeyModifiers
!= 256)
197 if (kind
== kEventRawKeyRepeat
|| kind
== kEventRawKeyDown
)
199 int key
= convert_key(macKeyCode
, macCharCodes
);
202 mplayer_put_key(key
);
205 else if (macKeyModifiers
== 256)
207 switch (macCharCodes
)
209 case '[': SetWindowAlpha(theWindow
, winAlpha
-= 0.05); break;
210 case ']': SetWindowAlpha(theWindow
, winAlpha
+= 0.05); break;
214 result
= eventNotHandledErr
;
220 //default mouse event handler
221 static OSStatus
MouseEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
223 OSStatus result
= noErr
;
224 UInt32
class = GetEventClass(event
);
225 UInt32 kind
= GetEventKind(event
);
227 result
= CallNextEventHandler(nextHandler
, event
);
229 if (class == kEventClassMouse
)
235 GetEventParameter(event
, kEventParamMouseLocation
, typeQDPoint
, 0, sizeof(mousePos
), 0, &mousePos
);
236 GetEventParameter(event
, kEventParamWindowMouseLocation
, typeQDPoint
, 0, sizeof(winMousePos
), 0, &winMousePos
);
240 case kEventMouseMoved
:
244 CGDisplayShowCursor(displayId
);
250 case kEventMouseWheelMoved
:
255 GetEventParameter(event
, kEventParamMouseWheelDelta
, typeSInt32
, 0, sizeof(wheel
), 0, &wheel
);
257 part
= FindWindow(mousePos
, &tmpWin
);
259 if (part
== inContent
)
262 mplayer_put_key(MOUSE_BTN3
);
264 mplayer_put_key(MOUSE_BTN4
);
269 case kEventMouseDown
:
272 EventMouseButton button
;
276 GetWindowPortBounds(theWindow
, &bounds
);
277 GetEventParameter(event
, kEventParamMouseButton
, typeMouseButton
, 0, sizeof(button
), 0, &button
);
279 part
= FindWindow(mousePos
, &tmpWin
);
280 if (kind
== kEventMouseUp
)
282 if (part
!= inContent
)
286 case kEventMouseButtonPrimary
:
287 mplayer_put_key(MOUSE_BTN0
);
289 case kEventMouseButtonSecondary
:
290 mplayer_put_key(MOUSE_BTN2
);
292 case kEventMouseButtonTertiary
:
293 mplayer_put_key(MOUSE_BTN1
);
297 result
= eventNotHandledErr
;
302 if (winMousePos
.h
> bounds
.right
- 15 && winMousePos
.v
> bounds
.bottom
)
308 ResizeWindow(theWindow
, mousePos
, NULL
, &newSize
);
311 else if (part
== inMenuBar
)
313 MenuSelect(mousePos
);
316 else if (part
== inContent
)
320 case kEventMouseButtonPrimary
:
321 mplayer_put_key(MOUSE_BTN0
| MP_KEY_DOWN
);
323 case kEventMouseButtonSecondary
:
324 mplayer_put_key(MOUSE_BTN2
| MP_KEY_DOWN
);
326 case kEventMouseButtonTertiary
:
327 mplayer_put_key(MOUSE_BTN1
| MP_KEY_DOWN
);
331 result
= eventNotHandledErr
;
338 case kEventMouseDragged
:
342 result
= eventNotHandledErr
;
350 static void set_winSizeMult(float mult
)
352 int d_width
, d_height
;
353 aspect(&d_width
, &d_height
, A_NOZOOM
);
362 SizeWindow(theWindow
, d_width
* mult
, d_height
* mult
, 1);
366 //default window event handler
367 static OSStatus
WindowEventHandler(EventHandlerCallRef nextHandler
, EventRef event
, void *userData
)
369 OSStatus result
= noErr
;
370 UInt32
class = GetEventClass(event
);
371 UInt32 kind
= GetEventKind(event
);
373 result
= CallNextEventHandler(nextHandler
, event
);
375 if (class == kEventClassCommand
)
377 HICommand theHICommand
;
379 GetEventParameter(event
, kEventParamDirectObject
, typeHICommand
, NULL
, sizeof(theHICommand
), NULL
, &theHICommand
);
381 switch (theHICommand
.commandID
)
384 mplayer_put_key(KEY_CLOSE_WIN
);
388 set_winSizeMult(0.5);
391 case kNormalScreenCmd
:
395 case kDoubleScreenCmd
:
405 vo_keepaspect
= !vo_keepaspect
;
406 CheckMenuItem(aspectMenu
, 1, vo_keepaspect
);
411 change_movie_aspect(-1);
415 change_movie_aspect(4.0 / 3.0);
419 change_movie_aspect(16.0 / 9.0);
423 vo_panscan
= !vo_panscan
;
424 CheckMenuItem(aspectMenu
, 2, vo_panscan
);
430 result
= eventNotHandledErr
;
434 else if (class == kEventClassWindow
)
437 Rect rectWindow
= { 0, 0, 0, 0 };
439 GetEventParameter(event
, kEventParamDirectObject
, typeWindowRef
, NULL
, sizeof(window
), NULL
, &window
);
443 GetWindowBounds(window
, kWindowGlobalPortRgn
, &rectWindow
);
448 case kEventWindowClosed
:
450 mplayer_put_key(KEY_CLOSE_WIN
);
454 case kEventWindowZoomed
:
455 case kEventWindowBoundsChanged
:
462 result
= eventNotHandledErr
;
470 static void quartz_CreateWindow(uint32_t d_width
, uint32_t d_height
, WindowAttributes windowAttrs
)
472 CFStringRef titleKey
;
473 CFStringRef windowTitle
;
477 CFStringRef movMenuTitle
;
478 CFStringRef aspMenuTitle
;
480 const EventTypeSpec win_events
[] = {
481 {kEventClassWindow
, kEventWindowClosed
},
482 {kEventClassWindow
, kEventWindowBoundsChanged
},
483 {kEventClassCommand
, kEventCommandProcess
}
486 const EventTypeSpec key_events
[] = {
487 {kEventClassKeyboard
, kEventRawKeyDown
},
488 {kEventClassKeyboard
, kEventRawKeyRepeat
}
491 const EventTypeSpec mouse_events
[] = {
492 {kEventClassMouse
, kEventMouseMoved
},
493 {kEventClassMouse
, kEventMouseWheelMoved
},
494 {kEventClassMouse
, kEventMouseDown
},
495 {kEventClassMouse
, kEventMouseUp
},
496 {kEventClassMouse
, kEventMouseDragged
}
499 SetRect(&winRect
, 0, 0, d_width
, d_height
);
500 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
501 SetRect(&dstRect
, 0, 0, d_width
, d_height
);
506 // Create Window Menu
507 CreateStandardWindowMenu(0, &windMenu
);
508 InsertMenu(windMenu
, 0);
511 CreateNewMenu(1004, 0, &movMenu
);
512 movMenuTitle
= CFSTR("Movie");
513 SetMenuTitleWithCFString(movMenu
, movMenuTitle
);
515 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Half Size"), 0, kHalfScreenCmd
, &index
);
516 SetMenuItemCommandKey(movMenu
, index
, 0, '0');
518 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Normal Size"), 0, kNormalScreenCmd
, &index
);
519 SetMenuItemCommandKey(movMenu
, index
, 0, '1');
521 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Double Size"), 0, kDoubleScreenCmd
, &index
);
522 SetMenuItemCommandKey(movMenu
, index
, 0, '2');
524 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Full Size"), 0, kFullScreenCmd
, &index
);
525 SetMenuItemCommandKey(movMenu
, index
, 0, 'F');
527 AppendMenuItemTextWithCFString(movMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
529 AppendMenuItemTextWithCFString(movMenu
, CFSTR("Aspect Ratio"), 0, 0, &index
);
531 //// Create Aspect Ratio Sub Menu
532 CreateNewMenu(0, 0, &aspectMenu
);
533 aspMenuTitle
= CFSTR("Aspect Ratio");
534 SetMenuTitleWithCFString(aspectMenu
, aspMenuTitle
);
535 SetMenuItemHierarchicalMenu(movMenu
, 6, aspectMenu
);
537 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Keep"), 0, kKeepAspectCmd
, &index
);
538 CheckMenuItem(aspectMenu
, 1, vo_keepaspect
);
539 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Pan-Scan"), 0, kPanScanCmd
, &index
);
540 CheckMenuItem(aspectMenu
, 2, vo_panscan
);
541 AppendMenuItemTextWithCFString(aspectMenu
, NULL
, kMenuItemAttrSeparator
, 0, &index
);
542 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("Original"), 0, kAspectOrgCmd
, &index
);
543 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("4:3"), 0, kAspectFullCmd
, &index
);
544 AppendMenuItemTextWithCFString(aspectMenu
, CFSTR("16:9"), 0, kAspectWideCmd
, &index
);
546 InsertMenu(movMenu
, GetMenuID(windMenu
)); //insert before Window menu
551 CreateNewWindow(kDocumentWindowClass
, windowAttrs
, &winRect
, &theWindow
);
553 CreateWindowGroup(0, &winGroup
);
554 SetWindowGroup(theWindow
, winGroup
);
557 titleKey
= CFSTR("MPlayer - The Movie Player");
558 windowTitle
= CFCopyLocalizedString(titleKey
, NULL
);
559 result
= SetWindowTitleWithCFString(theWindow
, windowTitle
);
561 CFRelease(windowTitle
);
563 // Install event handler
564 InstallApplicationEventHandler(NewEventHandlerUPP(KeyEventHandler
), GetEventTypeCount(key_events
), key_events
, NULL
, NULL
);
565 InstallApplicationEventHandler(NewEventHandlerUPP(MouseEventHandler
), GetEventTypeCount(mouse_events
), mouse_events
, NULL
, NULL
);
566 InstallWindowEventHandler(theWindow
, NewEventHandlerUPP(WindowEventHandler
), GetEventTypeCount(win_events
), win_events
, theWindow
, NULL
);
569 static void update_screen_info(void)
572 CGDisplayCount displayCount
;
573 CGDirectDisplayID
*displays
;
574 // Display IDs might not be consecutive, get the list of all devices up to # device_id
575 displayCount
= device_id
+ 1;
576 displays
= malloc(sizeof(*displays
) * displayCount
);
577 if (kCGErrorSuccess
!= CGGetActiveDisplayList(displayCount
, displays
, &displayCount
) || displayCount
< device_id
+ 1) {
578 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id
);
579 displayId
= kCGDirectMainDisplay
;
584 displayId
= displays
[device_id
];
588 displayRect
= CGDisplayBounds(displayId
);
589 xinerama_x
= displayRect
.origin
.x
;
590 xinerama_y
= displayRect
.origin
.y
;
591 vo_screenwidth
= displayRect
.size
.width
;
592 vo_screenheight
= displayRect
.size
.height
;
593 aspect_save_screenres(vo_screenwidth
, vo_screenheight
);
596 static void free_video_specific(void)
598 if (seqId
) CDSequenceEnd(seqId
);
604 CGDataProviderRelease(dataProviderRef
);
605 dataProviderRef
= NULL
;
606 CGImageRelease(image
);
610 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
)
612 WindowAttributes windowAttrs
;
616 free_video_specific();
618 vo_dwidth
= d_width
*= winSizeMult
;
619 vo_dheight
= d_height
*= winSizeMult
;
620 config_movie_aspect((float)d_width
/ d_height
);
622 // misc mplayer setup/////////////////////////////////////////////////////
623 SetRect(&imgRect
, 0, 0, width
, height
);
624 switch (image_format
)
637 image_size
= (imgRect
.right
* imgRect
.bottom
* image_depth
+ 7) / 8;
639 image_data
= malloc(image_size
);
641 // Create player window//////////////////////////////////////////////////
642 windowAttrs
= kWindowStandardDocumentAttributes
643 | kWindowStandardHandlerAttribute
644 | kWindowLiveResizeAttribute
;
646 windowAttrs
&= ~kWindowResizableAttribute
;
648 if (theWindow
== NULL
)
650 CGContextRef context
;
652 quartz_CreateWindow(d_width
, d_height
, windowAttrs
);
654 if (theWindow
== NULL
)
656 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: Couldn't create window !!!!!\n");
659 tmpBounds
= CGRectMake(0, 0, winRect
.right
, winRect
.bottom
);
660 QDBeginCGContext(GetWindowPort(theWindow
), &context
);
661 CGContextFillRect(context
, tmpBounds
);
662 QDEndCGContext(GetWindowPort(theWindow
), &context
);
666 HideWindow(theWindow
);
667 ChangeWindowAttributes(theWindow
, ~windowAttrs
, windowAttrs
);
668 SetRect(&winRect
, 0, 0, d_width
, d_height
);
669 SetRect(&oldWinRect
, 0, 0, d_width
, d_height
);
670 SizeWindow(theWindow
, d_width
, d_height
, 1);
673 switch (image_format
)
677 CGContextRef context
;
679 QDBeginCGContext(GetWindowPort(theWindow
), &context
);
681 dataProviderRef
= CGDataProviderCreateWithData(0, image_data
, imgRect
.right
* imgRect
.bottom
* 4, 0);
683 image
= CGImageCreate(imgRect
.right
,
687 (imgRect
.right
* 32 + 7) / 8,
688 CGColorSpaceCreateDeviceRGB(),
689 kCGImageAlphaNoneSkipFirst
,
690 dataProviderRef
, 0, 1, kCGRenderingIntentDefault
);
692 QDEndCGContext(GetWindowPort(theWindow
), &context
);
704 if (!EnterMoviesDone
)
706 qterr
= EnterMovies();
714 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: EnterMovies (%d)\n", qterr
);
719 SetIdentityMatrix(&matrix
);
721 if (d_width
!= width
|| d_height
!= height
)
723 ScaleMatrix(&matrix
, FixDiv(Long2Fix(d_width
), Long2Fix(width
)), FixDiv(Long2Fix(d_height
), Long2Fix(height
)), 0, 0);
726 yuv_qt_stuff
.desc
= (ImageDescriptionHandle
) NewHandleClear(sizeof(ImageDescription
));
728 yuv_qt_stuff
.extension_colr
= NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension
));
729 ((NCLCColorInfoImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_colr
))->colorParamType
= kVideoColorInfoImageDescriptionExtensionType
;
730 ((NCLCColorInfoImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_colr
))->primaries
= 2;
731 ((NCLCColorInfoImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_colr
))->transferFunction
= 2;
732 ((NCLCColorInfoImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_colr
))->matrix
= 2;
734 yuv_qt_stuff
.extension_fiel
= NewHandleClear(sizeof(FieldInfoImageDescriptionExtension
));
735 ((FieldInfoImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_fiel
))->fieldCount
= 1;
736 ((FieldInfoImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_fiel
))->fieldOrderings
= 0;
738 yuv_qt_stuff
.extension_clap
= NewHandleClear(sizeof(CleanApertureImageDescriptionExtension
));
739 ((CleanApertureImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthN
= imgRect
.right
;
740 ((CleanApertureImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_clap
))->cleanApertureWidthD
= 1;
741 ((CleanApertureImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightN
= imgRect
.bottom
;
742 ((CleanApertureImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_clap
))->cleanApertureHeightD
= 1;
743 ((CleanApertureImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_clap
))->horizOffN
= 0;
744 ((CleanApertureImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_clap
))->horizOffD
= 1;
745 ((CleanApertureImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_clap
))->vertOffN
= 0;
746 ((CleanApertureImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_clap
))->vertOffD
= 1;
748 yuv_qt_stuff
.extension_pasp
= NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension
));
749 ((PixelAspectRatioImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_pasp
))->hSpacing
= 1;
750 ((PixelAspectRatioImageDescriptionExtension
*) (*yuv_qt_stuff
.extension_pasp
))->vSpacing
= 1;
752 (*yuv_qt_stuff
.desc
)->idSize
= sizeof(ImageDescription
);
753 (*yuv_qt_stuff
.desc
)->cType
= image_qtcodec
;
754 (*yuv_qt_stuff
.desc
)->version
= 2;
755 (*yuv_qt_stuff
.desc
)->revisionLevel
= 0;
756 (*yuv_qt_stuff
.desc
)->vendor
= 'mpla';
757 (*yuv_qt_stuff
.desc
)->width
= imgRect
.right
;
758 (*yuv_qt_stuff
.desc
)->height
= imgRect
.bottom
;
759 (*yuv_qt_stuff
.desc
)->hRes
= Long2Fix(72);
760 (*yuv_qt_stuff
.desc
)->vRes
= Long2Fix(72);
761 (*yuv_qt_stuff
.desc
)->temporalQuality
= 0;
762 (*yuv_qt_stuff
.desc
)->spatialQuality
= codecLosslessQuality
;
763 (*yuv_qt_stuff
.desc
)->frameCount
= 1;
764 (*yuv_qt_stuff
.desc
)->dataSize
= 0;
765 (*yuv_qt_stuff
.desc
)->depth
= 24;
766 (*yuv_qt_stuff
.desc
)->clutID
= -1;
768 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_colr
, kColorInfoImageDescriptionExtension
);
771 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr
);
774 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_fiel
, kFieldInfoImageDescriptionExtension
);
777 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr
);
780 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_clap
, kCleanApertureImageDescriptionExtension
);
783 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr
);
786 qterr
= AddImageDescriptionExtension(yuv_qt_stuff
.desc
, yuv_qt_stuff
.extension_pasp
, kCleanApertureImageDescriptionExtension
);
789 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr
);
791 P
= calloc(sizeof(PlanarPixmapInfoYUV420
) + image_size
, 1);
792 switch (image_format
)
797 P
->componentInfoY
.offset
= be2me_32(sizeof(PlanarPixmapInfoYUV420
));
798 P
->componentInfoCb
.offset
= be2me_32(be2me_32(P
->componentInfoY
.offset
) + image_size
/ 2);
799 P
->componentInfoCr
.offset
= be2me_32(be2me_32(P
->componentInfoCb
.offset
) + image_size
/ 4);
800 P
->componentInfoY
.rowBytes
= be2me_32(imgRect
.right
);
801 P
->componentInfoCb
.rowBytes
= be2me_32(imgRect
.right
/ 2);
802 P
->componentInfoCr
.rowBytes
= be2me_32(imgRect
.right
/ 2);
803 image_buffer_size
= image_size
+ sizeof(PlanarPixmapInfoYUV420
);
807 image_buffer_size
= image_size
;
811 qterr
= DecompressSequenceBeginS(&seqId
,
815 GetWindowPort(theWindow
),
818 d_width
!= width
|| d_height
!= height
?
823 codecLosslessQuality
,
828 mp_msg(MSGT_VO
, MSGL_FATAL
, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr
);
836 RepositionWindow(theWindow
, NULL
, kWindowCenterOnMainScreen
);
837 ShowWindow(theWindow
);
849 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
858 static void check_events(void)
861 EventTargetRef theTarget
;
865 theTarget
= GetEventDispatcherTarget();
866 theErr
= ReceiveNextEvent(0, 0, kEventDurationNoWait
, true, &theEvent
);
867 if (theErr
== noErr
&& theEvent
!= NULL
)
869 SendEventToEventTarget(theEvent
, theTarget
);
870 ReleaseEvent(theEvent
);
874 static void draw_osd(void)
876 vo_draw_text(imgRect
.right
, imgRect
.bottom
, draw_alpha
);
879 static void flip_page(void)
883 if (theWindow
== NULL
)
886 switch (image_format
)
890 CGContextRef context
;
892 QDBeginCGContext(GetWindowPort(theWindow
), &context
);
893 CGContextDrawImage(context
, bounds
, image
);
894 QDEndCGContext(GetWindowPort(theWindow
), &context
);
906 CodecFlags flags
= 0;
908 qterr
= DecompressSequenceFrameWhen(seqId
,
911 0, //codecFlagUseImageBuffer,
917 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr
, flags
);
925 CGContextRef context
;
927 QDBeginCGContext(GetWindowPort(theWindow
), &context
);
929 CGContextBeginPath(context
);
930 CGContextSetAllowsAntialiasing(context
, false);
931 //CGContextSaveGState(context);
934 CGContextSetRGBStrokeColor(context
, 0.2, 0.2, 0.2, 0.5);
935 CGContextMoveToPoint(context
, winRect
.right
- 1, 1); CGContextAddLineToPoint(context
, winRect
.right
- 1, 1);
936 CGContextMoveToPoint(context
, winRect
.right
- 1, 5); CGContextAddLineToPoint(context
, winRect
.right
- 5, 1);
937 CGContextMoveToPoint(context
, winRect
.right
- 1, 9); CGContextAddLineToPoint(context
, winRect
.right
- 9, 1);
938 CGContextStrokePath(context
);
941 CGContextSetRGBStrokeColor(context
, 0.4, 0.4, 0.4, 0.5);
942 CGContextMoveToPoint(context
, winRect
.right
- 1, 2); CGContextAddLineToPoint(context
, winRect
.right
- 2, 1);
943 CGContextMoveToPoint(context
, winRect
.right
- 1, 6); CGContextAddLineToPoint(context
, winRect
.right
- 6, 1);
944 CGContextMoveToPoint(context
, winRect
.right
- 1, 10); CGContextAddLineToPoint(context
, winRect
.right
- 10, 1);
945 CGContextStrokePath(context
);
948 CGContextSetRGBStrokeColor(context
, 0.6, 0.6, 0.6, 0.5);
949 CGContextMoveToPoint(context
, winRect
.right
- 1, 3); CGContextAddLineToPoint(context
, winRect
.right
- 3, 1);
950 CGContextMoveToPoint(context
, winRect
.right
- 1, 7); CGContextAddLineToPoint(context
, winRect
.right
- 7, 1);
951 CGContextMoveToPoint(context
, winRect
.right
- 1, 11); CGContextAddLineToPoint(context
, winRect
.right
- 11, 1);
952 CGContextStrokePath(context
);
954 // CGContextRestoreGState( context );
955 CGContextFlush(context
);
956 QDEndCGContext(GetWindowPort(theWindow
), &context
);
959 curTime
= TickCount() / 60;
961 // auto hide mouse cursor (and future on-screen control?)
962 if (vo_quartz_fs
&& !mouseHide
)
964 if (curTime
- lastMouseHide
>= 5 || lastMouseHide
== 0)
966 CGDisplayHideCursor(displayId
);
968 lastMouseHide
= curTime
;
971 // update activity every 30 seconds to prevent
972 // screensaver from starting up.
973 if (curTime
- lastScreensaverUpdate
>= 30 || lastScreensaverUpdate
== 0)
975 UpdateSystemActivity(UsrActivity
);
976 lastScreensaverUpdate
= curTime
;
980 static int draw_slice(uint8_t * src
[], int stride
[], int w
, int h
, int x
, int y
)
982 switch (image_format
)
986 memcpy_pic(((char *)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
987 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
989 memcpy_pic(((char *)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
990 memcpy_pic(((char *)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
994 memcpy_pic(((char *)P
) + be2me_32(P
->componentInfoY
.offset
) + x
+ imgRect
.right
* y
, src
[0], w
, h
, imgRect
.right
, stride
[0]);
995 x
=x
/2;y
=y
/2;w
=w
/2;h
=h
/2;
997 memcpy_pic(((char *)P
) + be2me_32(P
->componentInfoCr
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[1], w
, h
, imgRect
.right
/ 2, stride
[1]);
998 memcpy_pic(((char *)P
) + be2me_32(P
->componentInfoCb
.offset
) + x
+ imgRect
.right
/ 2 * y
, src
[2], w
, h
, imgRect
.right
/ 2, stride
[2]);
1004 static int draw_frame(uint8_t * src
[])
1006 switch (image_format
)
1009 fast_memcpy(image_data
, src
[0], image_size
);
1014 memcpy_pic(((char *)P
), src
[0], imgRect
.right
* 2, imgRect
.bottom
, imgRect
.right
* 2, imgRect
.right
* 2);
1020 static int query_format(uint32_t format
)
1022 image_format
= format
;
1025 if (format
== IMGFMT_RGB32
)
1027 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1030 if (format
== IMGFMT_YV12
|| format
== IMGFMT_IYUV
|| format
== IMGFMT_I420
)
1032 image_qtcodec
= kMpegYUV420CodecType
; //kYUV420CodecType ?;
1033 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1036 if (format
== IMGFMT_YUY2
)
1038 image_qtcodec
= kComponentVideoUnsigned
;
1039 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1042 if (format
== IMGFMT_UYVY
)
1044 image_qtcodec
= k422YpCbCr8CodecType
;
1045 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
1051 static void uninit(void)
1053 free_video_specific();
1054 if (EnterMoviesDone
)
1056 EnterMoviesDone
= 0;
1061 static int preinit(const char *arg
)
1067 char *parse_pos
= (char *)&arg
[0];
1069 while (parse_pos
[0] && !parse_err
)
1071 if (strncmp(parse_pos
, "device_id=", 10) == 0)
1073 parse_pos
= &parse_pos
[10];
1074 device_id
= strtol(parse_pos
, &parse_pos
, 0);
1076 if (strncmp(parse_pos
, "fs_res=", 7) == 0)
1078 parse_pos
= &parse_pos
[7];
1079 fs_res_x
= strtol(parse_pos
, &parse_pos
, 0);
1080 parse_pos
= &parse_pos
[1];
1081 fs_res_y
= strtol(parse_pos
, &parse_pos
, 0);
1083 if (parse_pos
[0] == ':')
1084 parse_pos
= &parse_pos
[1];
1085 else if (parse_pos
[0])
1090 osx_foreground_hack();
1095 static uint32_t draw_yuv_image(mp_image_t
* mpi
)
1097 // ATM we're only called for planar IMGFMT
1098 // drawing is done directly in P
1099 // and displaying is in flip_page.
1100 return get_image_done
? VO_TRUE
: VO_FALSE
;
1103 static uint32_t get_yuv_image(mp_image_t
* mpi
)
1105 if (mpi
->type
!= MP_IMGTYPE_EXPORT
) return VO_FALSE
;
1107 if (mpi
->imgfmt
!= image_format
) return VO_FALSE
;
1109 if (mpi
->flags
& MP_IMGFLAG_PLANAR
)
1111 if (mpi
->num_planes
!= 3)
1113 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi
->num_planes
);
1117 mpi
->planes
[0] = ((char *)P
) + be2me_32(P
->componentInfoY
.offset
);
1118 mpi
->stride
[0] = imgRect
.right
;
1119 mpi
->width
= imgRect
.right
;
1121 if (mpi
->flags
& MP_IMGFLAG_SWAPPED
)
1124 mpi
->planes
[1] = ((char *)P
) + be2me_32(P
->componentInfoCb
.offset
);
1125 mpi
->planes
[2] = ((char *)P
) + be2me_32(P
->componentInfoCr
.offset
);
1126 mpi
->stride
[1] = imgRect
.right
/ 2;
1127 mpi
->stride
[2] = imgRect
.right
/ 2;
1132 mpi
->planes
[1] = ((char *)P
) + be2me_32(P
->componentInfoCr
.offset
);
1133 mpi
->planes
[2] = ((char *)P
) + be2me_32(P
->componentInfoCb
.offset
);
1134 mpi
->stride
[1] = imgRect
.right
/ 2;
1135 mpi
->stride
[2] = imgRect
.right
/ 2;
1138 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1145 if (mpi
->num_planes
!= 1)
1147 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi
->num_planes
);
1151 mpi
->planes
[0] = (char *)P
;
1152 mpi
->stride
[0] = imgRect
.right
* 2;
1153 mpi
->width
= imgRect
.right
;
1154 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1161 static int control(uint32_t request
, void *data
)
1165 case VOCTRL_PAUSE
: return int_pause
= 1;
1166 case VOCTRL_RESUME
: return int_pause
= 0;
1167 case VOCTRL_FULLSCREEN
: vo_fs
= !vo_fs
; window_fullscreen(); return VO_TRUE
;
1168 case VOCTRL_ONTOP
: vo_ontop
= !vo_ontop
; window_ontop(); return VO_TRUE
;
1169 case VOCTRL_QUERY_FORMAT
: return query_format(*(uint32_t *) data
);
1170 case VOCTRL_GET_PANSCAN
: return VO_TRUE
;
1171 case VOCTRL_SET_PANSCAN
: window_panscan(); return VO_TRUE
;
1173 case VOCTRL_GET_IMAGE
:
1174 switch (image_format
)
1181 return get_yuv_image(data
);
1186 case VOCTRL_DRAW_IMAGE
:
1187 switch (image_format
)
1194 return draw_yuv_image(data
);
1199 case VOCTRL_UPDATE_SCREENINFO
:
1200 update_screen_info();
1206 void window_resized(void)
1213 CGContextRef context
;
1215 GetWindowPortBounds(theWindow
, &winRect
);
1216 d_width
= vo_dwidth
= winRect
.right
;
1217 d_height
= vo_dheight
= winRect
.bottom
;
1220 aspect(&d_width
, &d_height
, A_WINZOOM
);
1221 SetRect(&dstRect
, (vo_dwidth
- d_width
) / 2, (vo_dheight
- d_height
) / 2, d_width
, d_height
);
1223 switch (image_format
)
1227 bounds
= CGRectMake(dstRect
.left
, dstRect
.top
, dstRect
.right
- dstRect
.left
, dstRect
.bottom
- dstRect
.top
);
1236 long scale_X
= FixDiv(Long2Fix(dstRect
.right
- dstRect
.left
), Long2Fix(imgRect
.right
));
1237 long scale_Y
= FixDiv(Long2Fix(dstRect
.bottom
- dstRect
.top
), Long2Fix(imgRect
.bottom
));
1239 SetIdentityMatrix(&matrix
);
1240 if (dstRect
.right
- dstRect
.left
!= imgRect
.right
|| dstRect
.bottom
- dstRect
.right
!= imgRect
.bottom
)
1242 ScaleMatrix(&matrix
, scale_X
, scale_Y
, 0, 0);
1244 if (vo_dwidth
> d_width
|| vo_dheight
> d_height
)
1246 TranslateMatrix(&matrix
, Long2Fix(dstRect
.left
), Long2Fix(dstRect
.top
));
1250 SetDSequenceMatrix(seqId
, &matrix
);
1258 tmpBounds
= CGRectMake(0, 0, winRect
.right
, winRect
.bottom
);
1259 QDBeginCGContext(GetWindowPort(theWindow
), &context
);
1260 CGContextFillRect(context
, tmpBounds
);
1261 QDEndCGContext(GetWindowPort(theWindow
), &context
);
1264 void window_ontop(void)
1268 // Cycle between level
1273 SetWindowGroupLevel(winGroup
, CGWindowLevelForKey(levelList
[winLevel
]));
1276 void window_fullscreen(void)
1283 if (displayId
== kCGDirectMainDisplay
)
1285 SetSystemUIMode(kUIModeAllHidden
, kUIOptionAutoShowMenuBar
);
1286 CGDisplayHideCursor(displayId
);
1290 if (fs_res_x
!= 0 || fs_res_y
!= 0)
1292 CFDictionaryRef mode
;
1293 size_t desiredBitDepth
= 32;
1294 boolean_t exactMatch
;
1296 originalMode
= CGDisplayCurrentMode(displayId
);
1298 mode
= CGDisplayBestModeForParameters(displayId
, desiredBitDepth
, fs_res_x
, fs_res_y
, &exactMatch
);
1304 // Warn if the mode doesn't match exactly
1305 mp_msg(MSGT_VO
, MSGL_WARN
, "Quartz warning: did not get exact mode match (got %dx%d) \n", (int)CFDictionaryGetValue(mode
, kCGDisplayWidth
), (int)CFDictionaryGetValue(mode
, kCGDisplayHeight
));
1308 CGDisplayCapture(displayId
);
1309 CGDisplaySwitchToMode(displayId
, mode
);
1313 mp_msg(MSGT_VO
, MSGL_ERR
, "Quartz error: can't switch to fullscreen \n");
1316 // Get Main device info///////////////////////////////////////////////////
1317 update_screen_info();
1320 // save old window size
1323 GetWindowPortBounds(theWindow
, &oldWinRect
);
1324 GetWindowBounds(theWindow
, kWindowContentRgn
, &oldWinBounds
);
1327 ChangeWindowAttributes(theWindow
, kWindowNoShadowAttribute
, 0);
1332 else //go back to windowed mode
1335 if (originalMode
!= NULL
)
1337 CGDisplaySwitchToMode(displayId
, originalMode
);
1338 CGDisplayRelease(displayId
);
1340 // Get Main device info///////////////////////////////////////////////////
1341 update_screen_info();
1343 originalMode
= NULL
;
1345 SetSystemUIMode(kUIModeNormal
, 0);
1347 // show mouse cursor
1348 CGDisplayShowCursor(displayId
);
1351 // revert window to previous setting
1352 ChangeWindowAttributes(theWindow
, 0, kWindowNoShadowAttribute
);
1353 SizeWindow(theWindow
, oldWinRect
.right
, oldWinRect
.bottom
, 1);
1354 MoveWindow(theWindow
, oldWinBounds
.left
, oldWinBounds
.top
, 1);
1359 void window_panscan(void)
1364 CheckMenuItem(aspectMenu
, 2, 1);
1366 CheckMenuItem(aspectMenu
, 2, 0);
1370 MoveWindow(theWindow
, xinerama_x
- (vo_panscan_x
>> 1), xinerama_y
- (vo_panscan_y
>> 1), 1);
1371 SizeWindow(theWindow
, vo_screenwidth
+ vo_panscan_x
, vo_screenheight
+ vo_panscan_y
, 1);