Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
  • abdsaber000/vlc
  • falbrechtskirchinger/vlc
  • b.sullender/vlc
  • hulxv/vlc
  • zyad-ayad/vlc
408 results
Show changes
Commits on Source (17)
......@@ -7,6 +7,8 @@
* Felix Paul Kühne <fkuehne at videolan dot org>
* Pierre d'Herbemont <pdherbemont at videolan dot org>
*
* Some of the code is based on mpv's video_layer.swift by "der richter"
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
......@@ -34,83 +36,152 @@
#include <vlc_plugin.h>
#include <vlc_vout_display.h>
#include <vlc_opengl.h>
#include <vlc_atomic.h>
#import <QuartzCore/QuartzCore.h>
#import <Cocoa/Cocoa.h>
#import <OpenGL/OpenGL.h>
#import <dlfcn.h> /* dlsym */
#import <dlfcn.h>
#include "opengl/renderer.h"
#include "opengl/vout_helper.h"
#define OSX_SIERRA_AND_HIGHER (NSAppKitVersionNumber >= 1485)
/*****************************************************************************
* Vout interface
*****************************************************************************/
static int Open(vout_display_t *vd, video_format_t *fmt, vlc_video_context *context);
static void Close(vout_display_t *vd);
vlc_module_begin()
set_description(N_("Core Animation OpenGL Layer (Mac OS X)"))
set_subcategory(SUBCAT_VIDEO_VOUT)
set_callback_display(Open, 0)
add_opengl_submodule_renderer()
vlc_module_end()
static void PictureRender (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture,
vlc_tick_t date);
static void PictureDisplay (vout_display_t *vd, picture_t *pic);
static int Control (vout_display_t *vd, int);
static void *OurGetProcAddress (vlc_gl_t *gl, const char *name);
static int OpenglLock (vlc_gl_t *gl);
static void OpenglUnlock (vlc_gl_t *gl);
static void OpenglSwap (vlc_gl_t *gl);
@protocol VLCCoreAnimationVideoLayerEmbedding <NSObject>
- (void)addVoutLayer:(CALayer *)aLayer;
- (void)removeVoutLayer:(CALayer *)aLayer;
- (CGSize)currentOutputSize;
/**
* Protocol declaration that drawable-nsobject should follow
*/
@protocol VLCOpenGLVideoViewEmbedding <NSObject>
- (void)addVoutSubview:(NSView *)view;
- (void)removeVoutSubview:(NSView *)view;
@end
/**
* Layer subclass that handles OpenGL video rendering
*/
@interface VLCCAOpenGLLayer : CAOpenGLLayer
{
NSLock *_displayLock;
vout_display_t *_voutDisplay; // All accesses to this must be @synchronized(self)
// unless you can be sure it won't be called in teardown
CGLContextObj _glContext;
}
@property (nonatomic, readwrite) vout_display_t* voutDisplay;
@property (nonatomic, readwrite) CGLContextObj glContext;
- (instancetype)initWithVoutDisplay:(vout_display_t *)vd;
- (void)displayFromVout;
- (void)reportCurrentLayerSize;
- (void)reportCurrentLayerSizeWithScale:(CGFloat)scale;
- (void)vlcClose;
@end
/**
* View subclass which is backed by a VLCCAOpenGLLayer
*/
#if __MAC_OS_X_VERSION_MAX_ALLOWED < 101400
// macOS SDKs lower than 10.14 did not have a NSViewLayerContentScaleDelegate
// protocol definition, but its not needed, it will work fine without it as the
// delegate method even existed before, just not the protocol.
@interface VLCVideoLayerView : NSView <CALayerDelegate>
#else
@interface VLCVideoLayerView : NSView <CALayerDelegate, NSViewLayerContentScaleDelegate>
#endif
{
vout_display_t *_vlc_vd; // All accesses to this must be @synchronized(self)
}
- (instancetype)initWithVoutDisplay:(vout_display_t *)vd;
- (void)vlcClose;
@end
typedef struct vout_display_sys_t {
CALayer <VLCCoreAnimationVideoLayerEmbedding> *container;
vout_window_t *embed;
VLCCAOpenGLLayer *cgLayer;
id<VLCOpenGLVideoViewEmbedding> container;
VLCVideoLayerView *videoView; // Layer-backed view that creates videoLayer
VLCCAOpenGLLayer *videoLayer; // Backing layer of videoView
vlc_gl_t *gl;
vout_display_opengl_t *vgl;
vout_display_place_t place;
vout_display_cfg_t cfg;
bool b_frame_available;
atomic_bool is_ready;
} vout_display_sys_t;
struct gl_sys
#pragma mark -
#pragma mark OpenGL context helpers
/**
* Create a new CGLContextObj for use by VLC
* This function may try various pixel formats until it finds a suitable/compatible
* one that works on the given hardware.
* \return CGLContextObj or NULL in case of error
*/
CGLContextObj vlc_CreateCGLContext()
{
CGLContextObj locked_ctx;
VLCCAOpenGLLayer *cgLayer;
CGLError err;
GLint npix = 0;
CGLPixelFormatObj pix;
CGLContextObj ctx;
CGLPixelFormatAttribute attribs[12] = {
kCGLPFAAllowOfflineRenderers,
kCGLPFADoubleBuffer,
kCGLPFAAccelerated,
kCGLPFANoRecovery,
kCGLPFAColorSize, 24,
kCGLPFAAlphaSize, 8,
kCGLPFADepthSize, 24,
0, // If ever extending this list, adjust the offset below!
0
};
if (@available(macOS 10.8, *)) {
// Enable automatic graphics switching support, important on Macs
// with dedicated GPUs, as it allows to not always use the dedicated
// GPU which has more power consumption
attribs[10] = kCGLPFASupportsAutomaticGraphicsSwitching;
}
err = CGLChoosePixelFormat(attribs, &pix, &npix);
if (err != kCGLNoError || pix == NULL) {
return NULL;
}
err = CGLCreateContext(pix, NULL, &ctx);
if (err != kCGLNoError || ctx == NULL) {
return NULL;
}
CGLDestroyPixelFormat(pix);
return ctx;
}
struct vlc_gl_sys
{
CGLContextObj cgl; // The CGL context managed by us
CGLContextObj cgl_prev; // The previously current CGL context, if any
};
static int SetViewpoint(vout_display_t *vd, const vlc_viewpoint_t *vp)
{
vout_display_sys_t *sys = vd->sys;
if (OpenglLock(sys->gl))
if (vlc_gl_MakeCurrent(sys->gl) != VLC_SUCCESS)
return VLC_EGENERIC;
int ret = vout_display_opengl_SetViewpoint(sys->vgl, vp);
OpenglUnlock(sys->gl);
vlc_gl_ReleaseCurrent(sys->gl);
return ret;
}
......@@ -118,6 +189,91 @@ static const struct vlc_display_operations ops = {
Close, PictureRender, PictureDisplay, Control, NULL, SetViewpoint,
};
/**
* Flush the OpenGL context
* In case of double-buffering swaps the back buffer with the front buffer.
* \note This function implicitly calls \c glFlush() before it returns.
*/
static void gl_cb_Swap(vlc_gl_t *vlc_gl)
{
struct vlc_gl_sys *sys = vlc_gl->sys;
// Copies a double-buffered contexts back buffer to front buffer, calling
// glFlush before this is not needed and discouraged for performance reasons.
// An implicit glFlush happens before CGLFlushDrawable returns.
CGLFlushDrawable(sys->cgl);
}
/**
* Make the OpenGL context the current one
* Makes the CGL context the current context, if it is not already the current one,
* and locks it.
*/
static int gl_cb_MakeCurrent(vlc_gl_t *vlc_gl)
{
CGLError err;
struct vlc_gl_sys *sys = vlc_gl->sys;
sys->cgl_prev = CGLGetCurrentContext();
if (sys->cgl_prev != sys->cgl) {
err = CGLSetCurrentContext(sys->cgl);
if (err != kCGLNoError) {
msg_Err(vlc_gl, "Failure setting current CGLContext: %s", CGLErrorString(err));
return VLC_EGENERIC;
}
}
err = CGLLockContext(sys->cgl);
if (err != kCGLNoError) {
msg_Err(vlc_gl, "Failure locking CGLContext: %s", CGLErrorString(err));
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
/**
* Make the OpenGL context no longer current one.
* Makes the previous context the current one and unlocks the CGL context.
*/
static void gl_cb_ReleaseCurrent(vlc_gl_t *vlc_gl)
{
CGLError err;
struct vlc_gl_sys *sys = vlc_gl->sys;
assert(CGLGetCurrentContext() == sys->cgl);
err = CGLUnlockContext(sys->cgl);
if (err != kCGLNoError) {
msg_Err(vlc_gl, "Failure unlocking CGLContext: %s", CGLErrorString(err));
abort();
}
if (sys->cgl_prev != sys->cgl) {
err = CGLSetCurrentContext(sys->cgl_prev);
if (err != kCGLNoError) {
msg_Err(vlc_gl, "Failure restoring previous CGLContext: %s", CGLErrorString(err));
abort();
}
}
sys->cgl_prev = NULL;
}
/**
* Look up OpenGL symbols by name
*/
static void *gl_cb_GetProcAddress(vlc_gl_t *vlc_gl, const char *name)
{
VLC_UNUSED(vlc_gl);
return dlsym(RTLD_DEFAULT, name);
}
#pragma mark -
#pragma mark Module functions
/*****************************************************************************
* Open: This function allocates and initializes the OpenGL vout method.
*****************************************************************************/
......@@ -125,111 +281,125 @@ static int Open (vout_display_t *vd,
video_format_t *fmt, vlc_video_context *context)
{
vout_display_sys_t *sys;
if (vd->cfg->window->type != VOUT_WINDOW_TYPE_NSOBJECT)
return VLC_EGENERIC;
/* Allocate structure */
vd->sys = sys = calloc(1, sizeof(vout_display_sys_t));
if (sys == NULL)
return VLC_EGENERIC;
@autoreleasepool {
id container = var_CreateGetAddress(vd, "drawable-nsobject");
if (!container) {
sys->embed = vd->cfg->window;
container = sys->embed->handle.nsobject;
vout_display_sys_t *sys;
vd->sys = sys = vlc_obj_calloc(vd, 1, sizeof(*sys));
if (sys == NULL)
return VLC_ENOMEM;
// Only use this video output on macOS 10.14 or higher
// currently, as it has some issues on at least macOS 10.7
// and the old NSView based output still works fine on old
// macOS versions.
if (@available(macOS 10.14, *)) {
// This is intentionally left empty, as the check
// can not be negated or combined with other conditions!
} else {
if (!vd->obj.force)
return VLC_EGENERIC;
}
if (!container) {
msg_Err(vd, "No drawable-nsobject found!");
goto bailout;
}
id container = vd->cfg->window->handle.nsobject;
if (!container) {
msg_Err(vd, "No drawable-nsobject found!");
goto error;
}
/* store for later, released in Close() */
// Retain container, released in Close
sys->container = [container retain];
[CATransaction begin];
sys->cgLayer = [[VLCCAOpenGLLayer alloc] init];
[sys->cgLayer setVoutDisplay:vd];
[sys->cgLayer performSelectorOnMainThread:@selector(display)
withObject:nil
waitUntilDone:YES];
if ([container respondsToSelector:@selector(addVoutLayer:)]) {
msg_Dbg(vd, "container implements implicit protocol");
[container addVoutLayer:sys->cgLayer];
} else if ([container respondsToSelector:@selector(addSublayer:)] ||
[container isKindOfClass:[CALayer class]]) {
msg_Dbg(vd, "container doesn't implement implicit protocol, fallback mode used");
[container addSublayer:sys->cgLayer];
} else {
msg_Err(vd, "Provided NSObject container isn't compatible");
[sys->cgLayer release];
sys->cgLayer = nil;
[CATransaction commit];
goto bailout;
// Create the CGL context
CGLContextObj cgl_ctx = vlc_CreateCGLContext();
if (cgl_ctx == NULL) {
msg_Err(vd, "Failure to create CGL context!");
goto error;
}
[CATransaction commit];
if (!sys->cgLayer)
goto bailout;
if (![sys->cgLayer glContext])
msg_Warn(vd, "we might not have an OpenGL context yet");
/* Initialize common OpenGL video display */
// Create a pseudo-context object which provides needed callbacks
// for VLC to deal with the CGL context. Usually this should be done
// by a proper opengl provider module, but we do not have that currently.
sys->gl = vlc_object_create(vd, sizeof(*sys->gl));
if (unlikely(!sys->gl))
goto bailout;
sys->gl->make_current = OpenglLock;
sys->gl->release_current = OpenglUnlock;
sys->gl->swap = OpenglSwap;
sys->gl->get_proc_address = OurGetProcAddress;
goto error;
sys->gl->make_current = gl_cb_MakeCurrent;
sys->gl->release_current = gl_cb_ReleaseCurrent;
sys->gl->swap = gl_cb_Swap;
sys->gl->get_proc_address = gl_cb_GetProcAddress;
sys->gl->api_type = VLC_OPENGL;
struct gl_sys *glsys = sys->gl->sys = malloc(sizeof(*glsys));
if (!sys->gl->sys)
goto bailout;
glsys->locked_ctx = NULL;
glsys->cgLayer = sys->cgLayer;
const vlc_fourcc_t *subpicture_chromas;
if (!OpenglLock(sys->gl)) {
sys->vgl = vout_display_opengl_New(fmt, &subpicture_chromas,
sys->gl, &vd->cfg->viewpoint, context);
OpenglUnlock(sys->gl);
} else
sys->vgl = NULL;
if (!sys->vgl) {
msg_Err(vd, "Error while initializing opengl display.");
goto bailout;
struct vlc_gl_sys *glsys = sys->gl->sys = malloc(sizeof(*glsys));
if (unlikely(!glsys)) {
Close(vd);
return VLC_ENOMEM;
}
glsys->cgl = cgl_ctx;
glsys->cgl_prev = NULL;
dispatch_sync(dispatch_get_main_queue(), ^{
// Reverse vertical alignment as the GL tex are Y inverted
sys->cfg = *vd->cfg;
if (sys->cfg.align.vertical == VLC_VIDEO_ALIGN_TOP)
sys->cfg.align.vertical = VLC_VIDEO_ALIGN_BOTTOM;
else if (sys->cfg.align.vertical == VLC_VIDEO_ALIGN_BOTTOM)
sys->cfg.align.vertical = VLC_VIDEO_ALIGN_TOP;
// Create video view
sys->videoView = [[VLCVideoLayerView alloc] initWithVoutDisplay:vd];
sys->videoLayer = (VLCCAOpenGLLayer*)[[sys->videoView layer] retain];
// Add video view to container
if ([container respondsToSelector:@selector(addVoutSubview:)]) {
[container addVoutSubview:sys->videoView];
} else if ([container isKindOfClass:[NSView class]]) {
NSView *containerView = container;
[containerView addSubview:sys->videoView];
[sys->videoView setFrame:containerView.bounds];
[sys->videoLayer reportCurrentLayerSize];
} else {
[sys->videoView release];
[sys->videoLayer release];
sys->videoView = nil;
sys->videoLayer = nil;
}
/* setup vout display */
vd->info.subpicture_chromas = subpicture_chromas;
vout_display_PlacePicture(&sys->place, vd->source, &sys->cfg);
});
vd->ops = &ops;
if (sys->videoView == nil) {
msg_Err(vd,
"Invalid drawable-nsobject object, must either be an NSView "
"or comply with the VLCOpenGLVideoViewEmbedding protocol");
goto error;
}
if (OSX_SIERRA_AND_HIGHER) {
/* request our screen's HDR mode (introduced in OS X 10.11, but correctly supported in 10.12 only) */
if ([sys->cgLayer respondsToSelector:@selector(setWantsExtendedDynamicRangeContent:)]) {
[sys->cgLayer setWantsExtendedDynamicRangeContent:YES];
}
// Initialize OpenGL video display
const vlc_fourcc_t *spu_chromas;
if (vlc_gl_MakeCurrent(sys->gl))
goto error;
sys->vgl = vout_display_opengl_New(fmt, &spu_chromas, sys->gl,
&vd->cfg->viewpoint, context);
vlc_gl_ReleaseCurrent(sys->gl);
if (sys->vgl == NULL) {
msg_Err(vd, "Error while initializing OpenGL display");
goto error;
}
/* setup initial state */
CGSize outputSize;
if ([container respondsToSelector:@selector(currentOutputSize)])
outputSize = [container currentOutputSize];
else
outputSize = [sys->container visibleRect].size;
vout_window_ReportSize(sys->embed, (int)outputSize.width, (int)outputSize.height);
vd->info.subpicture_chromas = spu_chromas;
vd->ops = &ops;
atomic_init(&sys->is_ready, false);
return VLC_SUCCESS;
bailout:
error:
Close(vd);
return VLC_EGENERIC;
}
......@@ -239,37 +409,45 @@ static void Close(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
if (sys->cgLayer) {
if ([sys->container respondsToSelector:@selector(removeVoutLayer:)])
[sys->container removeVoutLayer:sys->cgLayer];
else
[sys->cgLayer removeFromSuperlayer];
atomic_store(&sys->is_ready, false);
[sys->videoView vlcClose];
if ([sys->cgLayer glContext])
CGLReleaseContext([sys->cgLayer glContext]);
[sys->cgLayer release];
if (sys->vgl && !vlc_gl_MakeCurrent(sys->gl)) {
vout_display_opengl_Delete(sys->vgl);
vlc_gl_ReleaseCurrent(sys->gl);
}
if (sys->container)
[sys->container release];
if (sys->vgl != NULL && !OpenglLock(sys->gl)) {
vout_display_opengl_Delete(sys->vgl);
OpenglUnlock(sys->gl);
}
if (sys->gl) {
struct vlc_gl_sys *glsys = sys->gl->sys;
if (sys->gl != NULL)
{
if (sys->gl->sys != NULL)
{
assert(((struct gl_sys *)sys->gl->sys)->locked_ctx == NULL);
free(sys->gl->sys);
}
// It should never happen that the context is destroyed and we
// still have a previous context set, as it would mean non-balanced
// calls to MakeCurrent/ReleaseCurrent.
assert(glsys->cgl_prev == NULL);
CGLReleaseContext(glsys->cgl);
vlc_object_delete(sys->gl);
free(glsys);
}
free(sys);
// Copy pointers out of sys, as sys can be gone already
// when the dispatch_async block is run!
id container = sys->container;
VLCVideoLayerView *videoView = sys->videoView;
VLCCAOpenGLLayer *videoLayer = sys->videoLayer;
dispatch_async(dispatch_get_main_queue(), ^{
// Remove vout subview from container
if ([container respondsToSelector:@selector(removeVoutSubview:)]) {
[container removeVoutSubview:videoView];
}
[videoView removeFromSuperview];
[videoView release];
[container release];
[videoLayer release];
});
}
static void PictureRender (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture,
......@@ -278,16 +456,12 @@ static void PictureRender (vout_display_t *vd, picture_t *pic, subpicture_t *sub
VLC_UNUSED(date);
vout_display_sys_t *sys = vd->sys;
if (pic == NULL) {
msg_Warn(vd, "invalid pic, skipping frame");
return;
}
if (vlc_gl_MakeCurrent(sys->gl) == VLC_SUCCESS)
{
vout_display_opengl_Prepare(sys->vgl, pic, subpicture);
vlc_gl_ReleaseCurrent(sys->gl);
@synchronized (sys->cgLayer) {
if (!OpenglLock(sys->gl)) {
vout_display_opengl_Prepare(sys->vgl, pic, subpicture);
OpenglUnlock(sys->gl);
}
atomic_store(&sys->is_ready, true);
}
}
......@@ -296,15 +470,8 @@ static void PictureDisplay (vout_display_t *vd, picture_t *pic)
vout_display_sys_t *sys = vd->sys;
VLC_UNUSED(pic);
@synchronized (sys->cgLayer) {
sys->b_frame_available = YES;
/* Calling display on the non-main thread is not officially supported, but
* its suggested at several places and works fine here. Flush is thread-safe
* and makes sure the picture is actually displayed. */
[sys->cgLayer display];
[CATransaction flush];
}
[sys->videoLayer displayFromVout];
}
static int Control (vout_display_t *vd, int query)
......@@ -317,36 +484,34 @@ static int Control (vout_display_t *vd, int query)
switch (query)
{
case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
return VLC_SUCCESS;
case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
case VOUT_DISPLAY_CHANGE_ZOOM:
case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
{
/* we always use our current frame here */
vout_display_cfg_t cfg_tmp = *vd->cfg;
[CATransaction lock];
CGRect bounds = [sys->cgLayer visibleRect];
[CATransaction unlock];
cfg_tmp.display.width = bounds.size.width;
cfg_tmp.display.height = bounds.size.height;
/* Reverse vertical alignment as the GL tex are Y inverted */
if (cfg_tmp.align.vertical == VLC_VIDEO_ALIGN_TOP)
cfg_tmp.align.vertical = VLC_VIDEO_ALIGN_BOTTOM;
else if (cfg_tmp.align.vertical == VLC_VIDEO_ALIGN_BOTTOM)
cfg_tmp.align.vertical = VLC_VIDEO_ALIGN_TOP;
vout_display_place_t place;
vout_display_PlacePicture(&place, vd->source, &cfg_tmp);
if (unlikely(OpenglLock(sys->gl)))
// don't return an error or we need to handle reset_pictures
return VLC_SUCCESS;
vout_display_opengl_SetOutputSize(sys->vgl, place.width, place.height);
OpenglUnlock(sys->gl);
sys->place = place;
@synchronized(sys->videoLayer)
{
vout_display_cfg_t cfg = *vd->cfg;
cfg.display.width = sys->cfg.display.width;
cfg.display.height = sys->cfg.display.height;
// Reverse vertical alignment as the GL tex are Y inverted
if (cfg.align.vertical == VLC_VIDEO_ALIGN_TOP)
cfg.align.vertical = VLC_VIDEO_ALIGN_BOTTOM;
else if (cfg.align.vertical == VLC_VIDEO_ALIGN_BOTTOM)
cfg.align.vertical = VLC_VIDEO_ALIGN_TOP;
sys->cfg = cfg;
vout_display_PlacePicture(&sys->place, vd->source, &cfg);
}
// Note!
// No viewport or aspect ratio is set here, as that needs to be set
// when rendering. The viewport is always set to match the layer
// size by the OS right before the OpenGL render callback, so
// setting it here has no effect.
return VLC_SUCCESS;
}
......@@ -359,191 +524,408 @@ static int Control (vout_display_t *vd, int query)
}
#pragma mark -
#pragma mark OpenGL callbacks
#pragma mark VLCVideoLayerView
@implementation VLCVideoLayerView
static int OpenglLock (vlc_gl_t *gl)
- (instancetype)initWithVoutDisplay:(vout_display_t *)vd
{
struct gl_sys *sys = gl->sys;
assert(sys->locked_ctx == NULL);
self = [super init];
if (self) {
_vlc_vd = vd;
CGLContextObj ctx = [sys->cgLayer glContext];
if(!ctx) {
return 1;
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
self.wantsLayer = YES;
}
return self;
}
CGLError err = CGLLockContext(ctx);
if (kCGLNoError == err) {
sys->locked_ctx = ctx;
CGLSetCurrentContext(ctx);
return 0;
/**
* Invalidates VLC objects (notably _vlc_vd)
* This method must be called in VLCs module Close (or indirectly by the View)
* to ensure all critical VLC resources that might be gone when the module is
* closed are properly NULLed. This is necessary as dealloc is only called later
* as it has to be done async on the main thread, because NSView must be
* dealloc'ed on the main thread and the view own the layer, so the layer
* will stay valid until the view is gone, and might still use _vlc_vd
* even after the VLC module is gone and the resources would be invalid.
*/
- (void)vlcClose
{
@synchronized (self) {
[(VLCCAOpenGLLayer *)self.layer vlcClose];
_vlc_vd = NULL;
}
return 1;
}
static void OpenglUnlock (vlc_gl_t *gl)
- (void)viewWillStartLiveResize
{
struct gl_sys *sys = gl->sys;
CGLUnlockContext(sys->locked_ctx);
sys->locked_ctx = NULL;
[(VLCCAOpenGLLayer *)self.layer setAsynchronous:YES];
}
static void OpenglSwap (vlc_gl_t *gl)
- (void)viewDidEndLiveResize
{
glFlush();
[(VLCCAOpenGLLayer *)self.layer setAsynchronous:NO];
// After a live resize we need to tell the core about our new size
[(VLCCAOpenGLLayer *)self.layer reportCurrentLayerSize];
}
static void *OurGetProcAddress (vlc_gl_t *gl, const char *name)
- (CALayer *)makeBackingLayer
{
VLC_UNUSED(gl);
@synchronized(self) {
NSAssert(_vlc_vd != NULL, @"Cannot create backing layer without vout display!");
return dlsym(RTLD_DEFAULT, name);
VLCCAOpenGLLayer *layer = [[VLCCAOpenGLLayer alloc] initWithVoutDisplay:_vlc_vd];
layer.delegate = self;
return [layer autorelease];
}
}
/* Layer delegate method that ensures the layer always get the
* correct contentScale based on whether the view is on a HiDPI
* display or not, and when it is moved between displays.
*/
- (BOOL)layer:(CALayer *)layer
shouldInheritContentsScale:(CGFloat)newScale
fromWindow:(NSWindow *)window
{
// If the scale changes, from the OpenGL point of view
// the size changes, so we need to indicate a resize
if (layer == self.layer) {
[(VLCCAOpenGLLayer *)self.layer
reportCurrentLayerSizeWithScale:newScale];
// FIXME
// For a brief moment the old image with a wrong scale
// is still visible, thats because the resize event is not
// processed immediately. Ideally this would be handled similar
// to how the live resize is done, to avoid this.
}
return YES;
}
/*
* General properties
*/
- (BOOL)isOpaque
{
return YES;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (BOOL)mouseDownCanMoveWindow
{
return YES;
}
#pragma mark View mouse events
/* Left mouse button down */
- (void)mouseDown:(NSEvent *)event
{
@synchronized(self) {
if (!_vlc_vd) {
[super mouseDown:event];
return;
}
if (event.type == NSLeftMouseDown &&
!(event.modifierFlags & NSControlKeyMask) &&
event.clickCount == 1) {
vout_display_SendEventMousePressed(_vlc_vd, MOUSE_BUTTON_LEFT);
}
}
[super mouseDown:event];
}
/* Left mouse button up */
- (void)mouseUp:(NSEvent *)event
{
@synchronized(self) {
if (!_vlc_vd) {
[super mouseUp:event];
return;
}
if (event.type == NSLeftMouseUp) {
vout_display_SendEventMouseReleased(_vlc_vd, MOUSE_BUTTON_LEFT);
}
}
[super mouseUp:event];
}
/* Middle mouse button down */
- (void)otherMouseDown:(NSEvent *)event
{
@synchronized(self) {
if (_vlc_vd)
vout_display_SendEventMousePressed(_vlc_vd, MOUSE_BUTTON_CENTER);
}
[super otherMouseDown:event];
}
/* Middle mouse button up */
- (void)otherMouseUp:(NSEvent *)event
{
@synchronized(self) {
if (_vlc_vd)
vout_display_SendEventMouseReleased(_vlc_vd, MOUSE_BUTTON_CENTER);
}
[super otherMouseUp:event];
}
- (void)mouseMovedInternal:(NSEvent *)event
{
@synchronized(self) {
if (!_vlc_vd) {
return;
}
vout_display_sys_t *sys = _vlc_vd->sys;
// Convert window-coordinate point to view space
NSPoint pointInView = [self convertPoint:event.locationInWindow fromView:nil];
// Convert to pixels
NSPoint pointInBacking = [self convertPointToBacking:pointInView];
vout_display_SendMouseMovedDisplayCoordinates(_vlc_vd, pointInBacking.x, pointInBacking.y);
}
}
/* Mouse moved */
- (void)mouseMoved:(NSEvent *)event
{
[self mouseMovedInternal:event];
[super mouseMoved:event];
}
/* Mouse moved while clicked */
- (void)mouseDragged:(NSEvent *)event
{
[self mouseMovedInternal:event];
[super mouseDragged:event];
}
/* Mouse moved while center-clicked */
- (void)otherMouseDragged:(NSEvent *)event
{
[self mouseMovedInternal:event];
[super otherMouseDragged:event];
}
/* Mouse moved while right-clicked */
- (void)rightMouseDragged:(NSEvent *)event
{
[self mouseMovedInternal:event];
[super rightMouseDragged:event];
}
@end
#pragma mark -
#pragma mark CA layer
#pragma mark VLCCAOpenGLLayer
/*****************************************************************************
* @implementation VLCCAOpenGLLayer
*****************************************************************************/
@implementation VLCCAOpenGLLayer
- (id)init {
- (instancetype)initWithVoutDisplay:(vout_display_t *)vd
{
self = [super init];
if (self) {
_displayLock = [[NSLock alloc] init];
_voutDisplay = vd;
vout_display_sys_t *sys = vd->sys;
struct vlc_gl_sys *glsys = sys->gl->sys;
_glContext = CGLRetainContext(glsys->cgl);
[CATransaction lock];
self.needsDisplayOnBoundsChange = YES;
self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
self.asynchronous = NO;
self.opaque = 1.0;
self.hidden = NO;
[CATransaction unlock];
}
return self;
}
- (void)setVoutDisplay:(vout_display_t *)aVd
/**
* Invalidates VLC objects (notably _voutDisplay)
* This method must be called in VLCs module Close (or indirectly by the View).
*/
- (void)vlcClose
{
_voutDisplay = aVd;
@synchronized (self) {
_voutDisplay = NULL;
}
}
- (void)resizeWithOldSuperlayerSize:(CGSize)size
- (void)dealloc
{
[super resizeWithOldSuperlayerSize: size];
CGLReleaseContext(_glContext);
[_displayLock release];
[super dealloc];
}
CGSize boundsSize = self.visibleRect.size;
if (_voutDisplay)
{
vout_display_sys_t *sys = _voutDisplay->sys;
vout_window_ReportSize(sys->embed, boundsSize.width, boundsSize.height);
- (void)layoutSublayers
{
[super layoutSublayers];
if (self.asynchronous) {
// During live resize, the size is updated in the
// OpenGL draw callback, to ensure atomic size changes
// that are in sync with the real layer size.
// This bypasses the core but is needed for resizing
// without glitches or lags.
return;
}
[self reportCurrentLayerSize];
}
- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
- (void)reportCurrentLayerSizeWithScale:(CGFloat)scale
{
/* Only draw the frame if we have a frame that was previously rendered */
if (!_voutDisplay)
return false;
CGSize newSize = self.visibleRect.size;
vout_display_sys_t *sys = _voutDisplay->sys;
// Calculate pixel values
newSize.width *= scale;
newSize.height *= scale;
return sys->b_frame_available;
@synchronized(self) {
if (!_voutDisplay)
return;
vout_display_sys_t *sys = _voutDisplay->sys;
@synchronized(sys->videoLayer) {
sys->cfg.display.width = newSize.width;
sys->cfg.display.height = newSize.height;
}
}
}
- (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
- (void)reportCurrentLayerSize
{
if (!_voutDisplay)
return;
vout_display_sys_t *sys = _voutDisplay->sys;
if (!sys->vgl)
return;
CGFloat scale = self.contentsScale;
[self reportCurrentLayerSizeWithScale:scale];
}
CGRect bounds = [self visibleRect];
- (void)display
{
[_displayLock lock];
// x / y are top left corner, but we need the lower left one
vout_display_opengl_Viewport(sys->vgl, sys->place.x,
bounds.size.height - (sys->place.y + sys->place.height),
sys->place.width, sys->place.height);
[super display];
[CATransaction flush];
// flush is also done by this method, no need to call super
vout_display_opengl_Display(sys->vgl);
sys->b_frame_available = NO;
[_displayLock unlock];
}
-(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
- (void)displayFromVout
{
// The default is fine for this demonstration.
return [super copyCGLPixelFormatForDisplayMask:mask];
if (self.asynchronous) {
// During live resizing we do not take updates
// from the vout, as those would interfere with
// the rendering currently happening on the main
// thread for the resize. Rendering anyway happens
// triggered by the OS every display refresh, so
// forcing an update here would be useless anyway.
return;
}
[self display];
}
- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
pixelFormat:(CGLPixelFormatObj)pixelFormat
forLayerTime:(CFTimeInterval)timeInterval
displayTime:(const CVTimeStamp *)timeStamp
{
// Only one opengl context is allowed for the module lifetime
if(_glContext) {
msg_Dbg(_voutDisplay, "Return existing context: %p", _glContext);
return _glContext;
@synchronized(self) {
if (!_voutDisplay)
return NO;
vout_display_sys_t *sys = _voutDisplay->sys;
return (atomic_load(&sys->is_ready));
}
}
CGLContextObj context = [super copyCGLContextForPixelFormat:pixelFormat];
- (void)drawInCGLContext:(CGLContextObj)glContext
pixelFormat:(CGLPixelFormatObj)pixelFormat
forLayerTime:(CFTimeInterval)timeInterval
displayTime:(const CVTimeStamp *)timeStamp
{
@synchronized(self) {
if (!_voutDisplay)
return;
// Swap buffers only during the vertical retrace of the monitor.
//http://developer.apple.com/documentation/GraphicsImaging/
//Conceptual/OpenGL/chap5/chapter_5_section_44.html /
vout_display_sys_t *sys = _voutDisplay->sys;
GLint params = 1;
CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
&params );
if (vlc_gl_MakeCurrent(sys->gl))
return;
@synchronized (self) {
_glContext = context;
}
if (self.asynchronous) {
GLint dims[4] = { 0, 0, 0, 0 };
glGetIntegerv(GL_VIEWPORT, dims);
NSSize newSize = NSMakeSize(dims[2], dims[3]);
return context;
}
if (NSEqualSizes(newSize, NSZeroSize)) {
newSize = self.bounds.size;
CGFloat scale = self.contentsScale;
newSize.width *= scale;
newSize.height *= scale;
}
- (void)releaseCGLContext:(CGLContextObj)glContext
{
// do not release anything here, we do that when closing the module
}
@synchronized(sys->videoView)
{
sys->cfg.display.width = newSize.width;
sys->cfg.display.height = newSize.height;
- (void)mouseButtonDown:(int)buttonNumber
{
@synchronized (self) {
if (_voutDisplay) {
if (buttonNumber == 0)
vout_display_SendEventMousePressed (_voutDisplay, MOUSE_BUTTON_LEFT);
else if (buttonNumber == 1)
vout_display_SendEventMousePressed (_voutDisplay, MOUSE_BUTTON_RIGHT);
else
vout_display_SendEventMousePressed (_voutDisplay, MOUSE_BUTTON_CENTER);
vout_display_PlacePicture(&sys->place, _voutDisplay->source, &sys->cfg);
}
}
// Ensure viewport and aspect ratio is correct
vout_display_opengl_Viewport(sys->vgl, sys->place.x, sys->place.y,
sys->place.width, sys->place.height);
vout_display_opengl_SetOutputSize(sys->vgl, sys->place.width, sys->place.height);
vout_display_opengl_Display(sys->vgl);
vlc_gl_ReleaseCurrent(sys->gl);
}
}
- (void)mouseButtonUp:(int)buttonNumber
- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
{
@synchronized (self) {
if (_voutDisplay) {
if (buttonNumber == 0)
vout_display_SendEventMouseReleased (_voutDisplay, MOUSE_BUTTON_LEFT);
else if (buttonNumber == 1)
vout_display_SendEventMouseReleased (_voutDisplay, MOUSE_BUTTON_RIGHT);
else
vout_display_SendEventMouseReleased (_voutDisplay, MOUSE_BUTTON_CENTER);
}
}
CGLPixelFormatObj fmt = CGLGetPixelFormat(_glContext);
return (fmt) ? CGLRetainPixelFormat(fmt) : NULL;
}
- (void)mouseMovedToX:(double)xValue Y:(double)yValue
- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
{
@synchronized (self) {
if (_voutDisplay) {
vout_display_SendMouseMovedDisplayCoordinates (_voutDisplay,
xValue,
yValue);
}
}
return CGLRetainContext(_glContext);
}
@end
/*
* Module descriptor
*/
vlc_module_begin()
set_description(N_("Core Animation OpenGL Layer (Mac OS X)"))
set_subcategory(SUBCAT_VIDEO_VOUT)
set_callback_display(Open, 300)
add_opengl_submodule_renderer()
vlc_module_end()
......@@ -75,7 +75,7 @@ vlc_module_begin ()
set_shortname ("Mac OS X")
set_description (N_("Mac OS X OpenGL video output"))
set_subcategory (SUBCAT_VIDEO_VOUT)
set_callback_display(Open, 300)
set_callback_display(Open, 250)
add_shortcut ("macosx", "vout_macosx")
add_glopts ()
......
......@@ -580,6 +580,30 @@ int Open(vout_window_t *wnd)
}
}
static void DrawableClose(vout_window_t *wnd)
{
id drawable = (__bridge_transfer id)wnd->handle.nsobject;
wnd->handle.nsobject = nil;
(void)drawable;
}
static const struct vout_window_operations drawable_ops =
{
.destroy = DrawableClose,
};
static int DrawableOpen(vout_window_t *wnd)
{
id drawable = (__bridge id)
var_InheritAddress(wnd, "drawable-nsobject");
if (drawable == nil)
return VLC_EGENERIC;
wnd->ops = &drawable_ops;
wnd->handle.nsobject = (__bridge_retained void*)drawable;
return VLC_SUCCESS;
}
/*
* Module declaration
*/
......@@ -587,4 +611,11 @@ vlc_module_begin()
set_description("macOS Video Output Window")
set_capability("vout window", 1000)
set_callback(Open)
add_submodule()
set_shortname(N_("NSObject Drawable"))
set_subcategory(SUBCAT_VIDEO_VOUT)
set_capability("vout window", 10000)
set_callback(DrawableOpen)
add_shortcut("embed-nsobject")
vlc_module_end()