📄 voutgl.m
字号:
[[self openGLContext] makeCurrentContext]; glFlush(); [super drawRect:rect]; Unlock( p_vout );}@end/***************************************************************************** * embedded AGL context implementation *****************************************************************************/static void aglSetViewport( vout_thread_t *p_vout, Rect viewBounds, Rect clipBounds );static void aglReshape( vout_thread_t * p_vout );static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);static int aglInit( vout_thread_t * p_vout ){ vlc_value_t val; Rect viewBounds; Rect clipBounds; var_Get( p_vout->p_vlc, "drawable", &val ); p_vout->p_sys->agl_drawable = (AGLDrawable)val.i_int; aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable); var_Get( p_vout->p_vlc, "drawable-view-top", &val ); viewBounds.top = val.i_int; var_Get( p_vout->p_vlc, "drawable-view-left", &val ); viewBounds.left = val.i_int; var_Get( p_vout->p_vlc, "drawable-view-bottom", &val ); viewBounds.bottom = val.i_int; var_Get( p_vout->p_vlc, "drawable-view-right", &val ); viewBounds.right = val.i_int; var_Get( p_vout->p_vlc, "drawable-clip-top", &val ); clipBounds.top = val.i_int; var_Get( p_vout->p_vlc, "drawable-clip-left", &val ); clipBounds.left = val.i_int; var_Get( p_vout->p_vlc, "drawable-clip-bottom", &val ); clipBounds.bottom = val.i_int; var_Get( p_vout->p_vlc, "drawable-clip-right", &val ); clipBounds.right = val.i_int; aglSetViewport(p_vout, viewBounds, clipBounds); aglSetCurrentContext(p_vout->p_sys->agl_ctx); aglReshape( p_vout ); return VLC_SUCCESS;}static void aglEnd( vout_thread_t * p_vout ){ aglSetCurrentContext(NULL); if( p_vout->p_sys->theWindow ) DisposeWindow( p_vout->p_sys->theWindow );}static void aglReshape( vout_thread_t * p_vout ){ unsigned int x, y; unsigned int i_height = p_vout->p_sys->i_height; unsigned int i_width = p_vout->p_sys->i_width; Lock( p_vout ); vout_PlacePicture(p_vout, i_width, i_height, &x, &y, &i_width, &i_height); aglSetCurrentContext(p_vout->p_sys->agl_ctx); glViewport( p_vout->p_sys->i_offx + x, p_vout->p_sys->i_offy + y, i_width, i_height ); if( p_vout->p_sys->b_got_frame ) { /* Ask the opengl module to redraw */ vout_thread_t * p_parent; p_parent = (vout_thread_t *) p_vout->p_parent; Unlock( p_vout ); if( p_parent && p_parent->pf_display ) { p_parent->pf_display( p_parent, NULL ); } } else { glClear( GL_COLOR_BUFFER_BIT ); Unlock( p_vout ); }}/* private event class */enum { kEventClassVLCPlugin = 'vlcp',};/* private event kinds */enum{ kEventVLCPluginShowFullscreen = 32768, kEventVLCPluginHideFullscreen,};static void sendEventToMainThread(EventTargetRef target, UInt32 class, UInt32 kind){ EventRef myEvent; if( noErr == CreateEvent(NULL, class, kind, 0, kEventAttributeNone, &myEvent) ) { if( noErr == SetEventParameter(myEvent, kEventParamPostTarget, typeEventTargetRef, sizeof(EventTargetRef), &target) ) { PostEventToQueue(GetMainEventQueue(), myEvent, kEventPriorityStandard); } ReleaseEvent(myEvent); }}static int aglManage( vout_thread_t * p_vout ){ if( p_vout->i_changes & VOUT_ASPECT_CHANGE ) { aglReshape(p_vout); p_vout->i_changes &= ~VOUT_ASPECT_CHANGE; } if( p_vout->i_changes & VOUT_CROP_CHANGE ) { aglReshape(p_vout); p_vout->i_changes &= ~VOUT_CROP_CHANGE; } if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) { aglSetDrawable(p_vout->p_sys->agl_ctx, NULL); Lock( p_vout ); if( p_vout->b_fullscreen ) { /* Close the window resume normal drawing */ vlc_value_t val; Rect viewBounds; Rect clipBounds; var_Get( p_vout->p_vlc, "drawable", &val ); p_vout->p_sys->agl_drawable = (AGLDrawable)val.i_int; aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable); var_Get( p_vout->p_vlc, "drawable-view-top", &val ); viewBounds.top = val.i_int; var_Get( p_vout->p_vlc, "drawable-view-left", &val ); viewBounds.left = val.i_int; var_Get( p_vout->p_vlc, "drawable-view-bottom", &val ); viewBounds.bottom = val.i_int; var_Get( p_vout->p_vlc, "drawable-view-right", &val ); viewBounds.right = val.i_int; var_Get( p_vout->p_vlc, "drawable-clip-top", &val ); clipBounds.top = val.i_int; var_Get( p_vout->p_vlc, "drawable-clip-left", &val ); clipBounds.left = val.i_int; var_Get( p_vout->p_vlc, "drawable-clip-bottom", &val ); clipBounds.bottom = val.i_int; var_Get( p_vout->p_vlc, "drawable-clip-right", &val ); clipBounds.right = val.i_int; aglSetCurrentContext(p_vout->p_sys->agl_ctx); aglSetViewport(p_vout, viewBounds, clipBounds); /* Most Carbon APIs are not thread-safe, therefore delagate some GUI visibilty update to the main thread */ sendEventToMainThread(GetWindowEventTarget(p_vout->p_sys->theWindow), kEventClassVLCPlugin, kEventVLCPluginHideFullscreen); } else { Rect deviceRect; GDHandle deviceHdl = GetMainDevice(); deviceRect = (*deviceHdl)->gdRect; if( !p_vout->p_sys->theWindow ) { /* Create a window */ WindowAttributes windowAttrs; windowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute | kWindowNoShadowAttribute; windowAttrs &= (~kWindowResizableAttribute); CreateNewWindow(kDocumentWindowClass, windowAttrs, &deviceRect, &p_vout->p_sys->theWindow); if( !p_vout->p_sys->winGroup ) { CreateWindowGroup(0, &p_vout->p_sys->winGroup); SetWindowGroup(p_vout->p_sys->theWindow, p_vout->p_sys->winGroup); SetWindowGroupParent( p_vout->p_sys->winGroup, GetWindowGroupOfClass(kDocumentWindowClass) ) ; } // Window title CFStringRef titleKey = CFSTR("Fullscreen VLC media plugin"); CFStringRef windowTitle = CFCopyLocalizedString(titleKey, NULL); SetWindowTitleWithCFString(p_vout->p_sys->theWindow, windowTitle); CFRelease(titleKey); CFRelease(windowTitle); //Install event handler static const EventTypeSpec win_events[] = { { kEventClassMouse, kEventMouseUp }, { kEventClassWindow, kEventWindowClosed }, { kEventClassWindow, kEventWindowBoundsChanged }, { kEventClassCommand, kEventCommandProcess }, { kEventClassVLCPlugin, kEventVLCPluginShowFullscreen }, { kEventClassVLCPlugin, kEventVLCPluginHideFullscreen }, }; InstallWindowEventHandler (p_vout->p_sys->theWindow, NewEventHandlerUPP (WindowEventHandler), GetEventTypeCount(win_events), win_events, p_vout, NULL); } else { /* just in case device resolution changed */ SetWindowBounds(p_vout->p_sys->theWindow, kWindowContentRgn, &deviceRect); } glClear( GL_COLOR_BUFFER_BIT ); p_vout->p_sys->agl_drawable = (AGLDrawable)GetWindowPort(p_vout->p_sys->theWindow); aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable); aglSetCurrentContext(p_vout->p_sys->agl_ctx); aglSetViewport(p_vout, deviceRect, deviceRect); //aglSetFullScreen(p_vout->p_sys->agl_ctx, device_width, device_height, 0, 0); /* Most Carbon APIs are not thread-safe, therefore delagate some GUI visibilty update to the main thread */ sendEventToMainThread(GetWindowEventTarget(p_vout->p_sys->theWindow), kEventClassVLCPlugin, kEventVLCPluginShowFullscreen); } p_vout->b_fullscreen = !p_vout->b_fullscreen; p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; Unlock( p_vout ); aglReshape(p_vout); } return VLC_SUCCESS;}static int aglControl( vout_thread_t *p_vout, int i_query, va_list args ){ switch( i_query ) { case VOUT_SET_VIEWPORT: { Rect viewBounds, clipBounds; viewBounds.top = va_arg( args, int); viewBounds.left = va_arg( args, int); viewBounds.bottom = va_arg( args, int); viewBounds.right = va_arg( args, int); clipBounds.top = va_arg( args, int); clipBounds.left = va_arg( args, int); clipBounds.bottom = va_arg( args, int); clipBounds.right = va_arg( args, int); if( !p_vout->b_fullscreen ) { Lock( p_vout ); aglSetViewport(p_vout, viewBounds, clipBounds); Unlock( p_vout ); aglReshape( p_vout ); } return VLC_SUCCESS; } case VOUT_REPARENT: { AGLDrawable drawable = (AGLDrawable)va_arg( args, int); if( !p_vout->b_fullscreen && drawable != p_vout->p_sys->agl_drawable ) { p_vout->p_sys->agl_drawable = drawable; aglSetDrawable(p_vout->p_sys->agl_ctx, drawable); } return VLC_SUCCESS; } default: return vout_vaControlDefault( p_vout, i_query, args ); }}static void aglSwap( vout_thread_t * p_vout ){ p_vout->p_sys->b_got_frame = VLC_TRUE; aglSwapBuffers(p_vout->p_sys->agl_ctx);}/* Enter this function with the p_vout locked */static void aglSetViewport( vout_thread_t *p_vout, Rect viewBounds, Rect clipBounds ){ // mozilla plugin provides coordinates based on port bounds // however AGL coordinates are based on window structure region // and are vertically flipped GLint rect[4]; CGrafPtr port = (CGrafPtr)p_vout->p_sys->agl_drawable; Rect winBounds, clientBounds; GetWindowBounds(GetWindowFromPort(port), kWindowStructureRgn, &winBounds); GetWindowBounds(GetWindowFromPort(port), kWindowContentRgn, &clientBounds); /* update video clipping bounds in drawable */ rect[0] = (clientBounds.left-winBounds.left) + clipBounds.left; // from window left edge rect[1] = (winBounds.bottom-winBounds.top) - (clientBounds.top-winBounds.top) - clipBounds.bottom; // from window bottom edge rect[2] = clipBounds.right-clipBounds.left; // width rect[3] = clipBounds.bottom-clipBounds.top; // height aglSetInteger(p_vout->p_sys->agl_ctx, AGL_BUFFER_RECT, rect); aglEnable(p_vout->p_sys->agl_ctx, AGL_BUFFER_RECT); /* update video internal bounds in drawable */ p_vout->p_sys->i_width = viewBounds.right-viewBounds.left; p_vout->p_sys->i_height = viewBounds.bottom-viewBounds.top; p_vout->p_sys->i_offx = -clipBounds.left - viewBounds.left; p_vout->p_sys->i_offy = clipBounds.bottom + viewBounds.top - p_vout->p_sys->i_height; aglUpdateContext(p_vout->p_sys->agl_ctx);}//default window event handlerstatic pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData){ OSStatus result = noErr; UInt32 class = GetEventClass (event); UInt32 kind = GetEventKind (event); vout_thread_t *p_vout = (vout_thread_t *)userData; result = CallNextEventHandler(nextHandler, event); if(class == kEventClassCommand) { HICommand theHICommand; GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof( HICommand ), NULL, &theHICommand ); switch ( theHICommand.commandID ) { default: result = eventNotHandledErr; break; } } else if(class == kEventClassWindow) { WindowRef window; Rect rectPort = {0,0,0,0}; GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); if(window) { GetPortBounds(GetWindowPort(window), &rectPort); } switch (kind) { case kEventWindowClosed: case kEventWindowZoomed: case kEventWindowBoundsChanged: break; default: result = eventNotHandledErr; break; } } else if(class == kEventClassMouse) { UInt16 button; switch (kind) { case kEventMouseDown: GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); switch (button) { case kEventMouseButtonPrimary: { vlc_value_t val; var_Get( p_vout, "mouse-button-down", &val ); val.i_int |= 1; var_Set( p_vout, "mouse-button-down", val ); } default: result = eventNotHandledErr; break; } break; case kEventMouseUp: GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); switch (button) { case kEventMouseButtonPrimary: { UInt32 clickCount = 0; GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount); if( clickCount > 1 ) { vlc_value_t val; val.b_bool = VLC_FALSE; var_Set((vout_thread_t *) p_vout->p_parent, "fullscreen", val); } else { vlc_value_t val; var_Get( p_vout, "mouse-button-down", &val ); val.i_int &= ~1; var_Set( p_vout, "mouse-button-down", val ); } break; } default: result = eventNotHandledErr; break; } break; default: result = eventNotHandledErr; break; } } else if(class == kEventClassVLCPlugin) { switch (kind) { case kEventVLCPluginShowFullscreen: ShowWindow (p_vout->p_sys->theWindow); SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar); //CGDisplayHideCursor(kCGDirectMainDisplay); break; case kEventVLCPluginHideFullscreen: HideWindow (p_vout->p_sys->theWindow); SetSystemUIMode( kUIModeNormal, 0); CGDisplayShowCursor(kCGDirectMainDisplay); //DisposeWindow( p_vout->p_sys->theWindow ); break; default: result = eventNotHandledErr; break; } } return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -