mpv/libvo/vo_quartz.c

530 lines
12 KiB
C

/*
* vo_quartz.c
*
* Copyright (c) Nicolas Plourde - January 2004
*
* MPlayer Mac OSX Quartz video out module.
*
* TODO: -Fullscreen
* -Better event handling
*
* Note on performance:
* Right now i can play fullsize dvd video with -framedrop on my
* iBook G4 800mhz. YUV to RGB converstion will speed up thing alot.
* Another thing is the slow fps when you maximize the window, I was
* not expecting that. I will fix this a.s.a.p. Im new to Mac
* programming so help is welcome.
*/
//SYS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
//OSX
#include <Carbon/Carbon.h>
#include <QuickTime/QuickTime.h>
//MPLAYER
#include "config.h"
#include "video_out.h"
#include "video_out_internal.h"
#include "aspect.h"
#include "../input/input.h"
#include "../input/mouse.h"
#include "vo_quartz.h"
static vo_info_t info = {
"MacOS X (Quartz)",
"quartz",
"Nicolas Plourde <nicolasplourde@hotmail.com>",
""
};
LIBVO_EXTERN (quartz)
static unsigned char *ImageData = NULL;
static uint32_t image_width;
static uint32_t image_height;
static uint32_t image_depth;
static uint32_t image_bytes;
static uint32_t image_format;
static int int_pause = 0;
int screen_width, screen_height;
WindowRef theWindow;
CGContextRef context;
CGRect bounds;
CGRect winBounds;
Rect contentRect;
CGImageRef image;
CGDataProviderRef dataProviderRef;
Ptr oldscreenstate;
RGBColor black = { 0, 0, 0 };
float winAlpha = 1;
#include "../osdep/keycodes.h"
extern void mplayer_put_key (int code);
//PROTOTYPE/////////////////////////////////////////////////////////////////
void resize_window (uint32_t width, uint32_t height);
static OSStatus MainWindowEventHandler (EventHandlerCallRef nextHandler,
EventRef event, void *userData);
static OSStatus MainKeyEventHandler (EventHandlerCallRef nextHandler,
EventRef event, void *userData);
//default window event handler
static OSStatus
MainWindowEventHandler (EventHandlerCallRef nextHandler, EventRef event,
void *userData)
{
OSStatus err = noErr;
WindowRef window;
Rect rectPort = { 0, 0, 0, 0 };
OSStatus result = eventNotHandledErr;
UInt32 class = GetEventClass (event);
UInt32 kind = GetEventKind (event);
GetEventParameter (event, kEventParamDirectObject, typeWindowRef, NULL,
sizeof (WindowRef), NULL, &window);
if (window)
{
GetWindowPortBounds (window, &rectPort);
}
switch (kind)
{
case kEventWindowActivated:
case kEventWindowDrawContent:
break;
case kEventWindowClosed:
HideWindow (window);
mplayer_put_key (KEY_ESC);
break;
case kEventWindowShown:
InvalWindowRect (window, &rectPort);
break;
case kEventWindowBoundsChanged:
resize_window (rectPort.right, rectPort.bottom);
break;
case kEventWindowZoomed:
resize_window (rectPort.right, rectPort.bottom);
break;
default:
err = eventNotHandledErr;
break;
}
return err;
}
//keyboard event handler
static OSStatus
MainKeyEventHandler (EventHandlerCallRef nextHandler, EventRef event,
void *userData)
{
OSStatus err = noErr;
UInt32 macKeyCode;
GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL,
sizeof (macKeyCode), NULL, &macKeyCode);
switch (GetEventKind (event))
{
case kEventRawKeyDown:
{
switch (macKeyCode)
{
case QZ_RETURN:
mplayer_put_key (KEY_ENTER);
break;
case QZ_ESCAPE:
EndFullScreen (oldscreenstate, 0);
QuitApplicationEventLoop ();
mplayer_put_key (KEY_ESC);
break;
case QZ_q:
mplayer_put_key ('q');
break;
case QZ_F1:
mplayer_put_key (KEY_F + 1);
break;
case QZ_F2:
mplayer_put_key (KEY_F + 2);
break;
case QZ_F3:
mplayer_put_key (KEY_F + 3);
break;
case QZ_F4:
mplayer_put_key (KEY_F + 4);
break;
case QZ_F5:
mplayer_put_key (KEY_F + 5);
break;
case QZ_F6:
mplayer_put_key (KEY_F + 6);
break;
case QZ_F7:
mplayer_put_key (KEY_F + 7);
break;
case QZ_F8:
mplayer_put_key (KEY_F + 8);
break;
case QZ_F9:
mplayer_put_key (KEY_F + 9);
break;
case QZ_F10:
mplayer_put_key (KEY_F + 10);
break;
case QZ_F11:
mplayer_put_key (KEY_F + 11);
break;
case QZ_F12:
mplayer_put_key (KEY_F + 12);
break;
case QZ_o:
mplayer_put_key ('o');
break;
case QZ_SPACE:
mplayer_put_key (' ');
break;
case QZ_p:
mplayer_put_key ('p');
break;
//case QZ_7: mplayer_put_key(shift_key?'/':'7');
//case QZ_PLUS: mplayer_put_key(shift_key?'*':'+');
case QZ_KP_PLUS:
mplayer_put_key ('+');
break;
case QZ_MINUS:
case QZ_KP_MINUS:
mplayer_put_key ('-');
break;
case QZ_TAB:
mplayer_put_key ('\t');
break;
case QZ_PAGEUP:
mplayer_put_key (KEY_PAGE_UP);
break;
case QZ_PAGEDOWN:
mplayer_put_key (KEY_PAGE_DOWN);
break;
case QZ_UP:
mplayer_put_key (KEY_UP);
break;
case QZ_DOWN:
mplayer_put_key (KEY_DOWN);
break;
case QZ_LEFT:
mplayer_put_key (KEY_LEFT);
break;
case QZ_RIGHT:
mplayer_put_key (KEY_RIGHT);
break;
//case QZ_LESS: mplayer_put_key(shift_key?'>':'<'); break;
//case QZ_GREATER: mplayer_put_key('>'); break;
//case QZ_ASTERISK:
case QZ_KP_MULTIPLY:
mplayer_put_key ('*');
break;
case QZ_SLASH:
case QZ_KP_DIVIDE:
mplayer_put_key ('/');
break;
case QZ_KP0:
mplayer_put_key (KEY_KP0);
break;
case QZ_KP1:
mplayer_put_key (KEY_KP1);
break;
case QZ_KP2:
mplayer_put_key (KEY_KP2);
break;
case QZ_KP3:
mplayer_put_key (KEY_KP3);
break;
case QZ_KP4:
mplayer_put_key (KEY_KP4);
break;
case QZ_KP5:
mplayer_put_key (KEY_KP5);
break;
case QZ_KP6:
mplayer_put_key (KEY_KP6);
break;
case QZ_KP7:
mplayer_put_key (KEY_KP7);
break;
case QZ_KP8:
mplayer_put_key (KEY_KP8);
break;
case QZ_KP9:
mplayer_put_key (KEY_KP9);
break;
case QZ_KP_PERIOD:
mplayer_put_key (KEY_KPDEC);
break;
case QZ_KP_ENTER:
mplayer_put_key (KEY_KPENTER);
break;
case QZ_LEFTBRACKET:
SetWindowAlpha (theWindow, winAlpha -= 0.05);
break;
case QZ_RIGHTBRACKET:
SetWindowAlpha (theWindow, winAlpha += 0.05);
break;
case QZ_f:
break;
default:
break;
}
}
break;
default:
err = eventNotHandledErr;
break;
}
return err;
}
static uint32_t
config (uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height,
uint32_t flags, char *title, uint32_t format)
{
WindowAttributes windowAttrs;
CFStringRef titleKey;
CFStringRef windowTitle;
OSStatus result;
GDHandle deviceHdl;
Rect deviceRect;
//Get Main device info///////////////////////////////////////////////////
deviceHdl = GetMainDevice ();
deviceRect = (*deviceHdl)->gdRect;
screen_width = deviceRect.right;
screen_height = deviceRect.bottom;
//misc mplayer setup/////////////////////////////////////////////////////
image_width = width;
image_height = height;
image_depth = IMGFMT_RGB_DEPTH (format);
image_bytes = (IMGFMT_RGB_DEPTH (format) + 7) / 8;
aspect_save_orig (width, height);
aspect_save_prescale (d_width, d_height);
aspect_save_screenres (screen_width, screen_height);
aspect (&d_width, &d_height, A_NOZOOM);
if (ImageData)
free (ImageData);
ImageData = malloc (image_width * image_height * image_bytes);
//Create player window//////////////////////////////////////////////////
windowAttrs = kWindowStandardDocumentAttributes
| kWindowMetalAttribute
| kWindowStandardHandlerAttribute
| kWindowInWindowMenuAttribute
| kWindowLiveResizeAttribute | kWindowCompositingAttribute;
SetRect (&contentRect, 0, 0, d_width, d_height);
CreateNewWindow (kDocumentWindowClass, windowAttrs, &contentRect,
&theWindow);
titleKey = CFSTR ("MPlayer");
windowTitle = CFCopyLocalizedString (titleKey, NULL);
result = SetWindowTitleWithCFString (theWindow, windowTitle);
CFRelease (titleKey);
CFRelease (windowTitle);
const EventTypeSpec winEvents[] = {
{kEventClassWindow, kEventWindowActivated},
{kEventClassWindow, kEventWindowDrawContent},
{kEventClassWindow, kEventWindowClosed},
{kEventClassWindow, kEventWindowShown},
{kEventClassWindow, kEventWindowBoundsChanged},
{kEventClassWindow, kEventWindowZoomed}
};
const EventTypeSpec keyEvents[] =
{ {kEventClassKeyboard, kEventRawKeyDown} };
InstallWindowEventHandler (theWindow,
NewEventHandlerUPP (MainWindowEventHandler),
GetEventTypeCount (winEvents), winEvents,
theWindow, NULL);
InstallWindowEventHandler (theWindow,
NewEventHandlerUPP (MainKeyEventHandler),
GetEventTypeCount (keyEvents), keyEvents,
theWindow, NULL);
RepositionWindow (theWindow, NULL, kWindowCascadeOnMainScreen);
ShowWindow (theWindow);
//Setup Quartz context
CreateCGContextForPort (GetWindowPort (theWindow), &context);
//set size and aspect for current window
resize_window (d_width, d_height);
return 0;
}
//resize drawing context to fit window
void
resize_window (uint32_t width, uint32_t height)
{
//this is a "wow it work". Need some improvement.
uint32_t d_width;
uint32_t d_height;
uint32_t size;
Rect tmpRect;
float aspectX;
float aspectY;
aspect (&d_width, &d_height, A_NOZOOM);
aspectX = (float) ((float) d_width * (width / (float) d_width));
aspectY = (float) ((float) d_height * (width / (float) d_width));
if (aspectY > height)
{
aspectX = (float) ((float) d_width * (height / (float) d_height));
aspectY = (float) ((float) d_height * (height / (float) d_height));
bounds = CGRectMake ((width - aspectX) / 2, 0, aspectX, aspectY);
}
else
{
bounds = CGRectMake (0, (height - aspectY) / 2, aspectX, aspectY);
}
//create a graphic context for the window
GetWindowPortBounds (theWindow, &tmpRect);
SetPortBounds (GetWindowPort (theWindow), &tmpRect);
CreateCGContextForPort (GetWindowPort (theWindow), &context);
//fill background with black
winBounds =
CGRectMake (tmpRect.top, tmpRect.left, tmpRect.right, tmpRect.bottom);
CGContextSetRGBFillColor (context, 0.0, 0.0, 0.0, 1.0);
CGContextFillRect (context, winBounds);
}
static void
check_events (void)
{
EventRef theEvent;
EventTargetRef theTarget;
theTarget = GetEventDispatcherTarget ();
ReceiveNextEvent (0, NULL, kEventDurationNoWait, true, &theEvent);
SendEventToEventTarget (theEvent, theTarget);
ReleaseEvent (theEvent);
//if(VO_EVENT_RESIZE) resize_window(vo_dwidth,vo_dheight);
if (VO_EVENT_EXPOSE && int_pause)
flip_page ();
}
static void
draw_osd (void)
{
}
static void
flip_page (void)
{
CGContextFlush (context);
}
static uint32_t
draw_slice (uint8_t * src[], int stride[], int w, int h, int x, int y)
{
return -1;
}
static uint32_t
draw_frame (uint8_t * src[])
{
//this is very slow. I have to find another way.
CGImageAlphaInfo alphaInfo;
dataProviderRef =
CGDataProviderCreateWithData (0, src[0],
image_width * image_height * image_bytes,
0);
if (image_format == IMGFMT_RGB24)
alphaInfo = kCGImageAlphaNone;
else if (image_format == IMGFMT_RGB32)
alphaInfo = kCGImageAlphaNoneSkipFirst;
image = CGImageCreate (image_width,
image_height,
8,
image_depth,
((image_width * image_depth) + 7) / 8,
CGColorSpaceCreateDeviceRGB (),
alphaInfo,
dataProviderRef, 0, 0, kCGRenderingIntentDefault);
CGContextDrawImage (context, bounds, image);
return 0;
}
static uint32_t
query_format (uint32_t format)
{
image_format = format;
//Curently supporting only rgb format.
if ((format == IMGFMT_RGB24) || (format == IMGFMT_RGB32))
return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW;
return 0;
}
static void
uninit (void)
{
}
static uint32_t
preinit (const char *arg)
{
return 0;
}
static uint32_t
control (uint32_t request, void *data, ...)
{
switch (request)
{
case VOCTRL_PAUSE:
return (int_pause = 1);
case VOCTRL_RESUME:
return (int_pause = 0);
case VOCTRL_QUERY_FORMAT:
return query_format (*((uint32_t *) data));
}
return VO_NOTIMPL;
}