[vlc-commits] windowed Mac plugin: implement a CoreAnimation based vout using some code from the windowless base plugin
Felix Paul Kühne
git at videolan.org
Fri Jan 4 12:24:49 CET 2013
npapi-vlc | branch: master | Felix Paul Kühne <fkuehne at videolan.org> | Fri Jan 4 12:24:41 2013 +0100| [7470b60de2016ab536621da3efca992f527ac03d] | committer: Felix Paul Kühne
windowed Mac plugin: implement a CoreAnimation based vout using some code from the windowless base plugin
> http://git.videolan.org/gitweb.cgi/npapi-vlc.git/?a=commit;h=7470b60de2016ab536621da3efca992f527ac03d
---
npapi/vlcplugin_mac.h | 35 +++++++++-
npapi/vlcplugin_mac.mm | 169 ++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 197 insertions(+), 7 deletions(-)
diff --git a/npapi/vlcplugin_mac.h b/npapi/vlcplugin_mac.h
index dfe4b0c..7cc6d4f 100644
--- a/npapi/vlcplugin_mac.h
+++ b/npapi/vlcplugin_mac.h
@@ -34,6 +34,36 @@ public:
VlcPluginMac(NPP, NPuint16_t);
virtual ~VlcPluginMac();
+ /* video handling */
+ //for libvlc_video_set_format_callbacks
+ static unsigned video_format_proxy(void **opaque, char *chroma,
+ unsigned *width, unsigned *height,
+ unsigned *pitches, unsigned *lines)
+ { return reinterpret_cast<VlcPluginMac*>(*opaque)->video_format_cb(chroma,
+ width, height,
+ pitches, lines); }
+ static void video_cleanup_proxy(void *opaque)
+ { reinterpret_cast<VlcPluginMac*>(opaque)->video_cleanup_cb(); };
+
+ unsigned video_format_cb(char *chroma,
+ unsigned *width, unsigned *height,
+ unsigned *pitches, unsigned *lines);
+ void video_cleanup_cb();
+ //end (for libvlc_video_set_format_callbacks)
+
+ //for libvlc_video_set_callbacks
+ static void* video_lock_proxy(void *opaque, void **planes)
+ { return reinterpret_cast<VlcPluginMac*>(opaque)->video_lock_cb(planes); }
+ static void video_unlock_proxy(void *opaque, void *picture, void *const *planes)
+ { reinterpret_cast<VlcPluginMac*>(opaque)->video_unlock_cb(picture, planes); }
+ static void video_display_proxy(void *opaque, void *picture)
+ { reinterpret_cast<VlcPluginMac*>(opaque)->video_display_cb(picture); }
+
+ void* video_lock_cb(void **planes);
+ void video_unlock_cb(void *picture, void *const *planes);
+ void video_display_cb(void *picture);
+ //end (for libvlc_video_set_callbacks)
+
void toggle_fullscreen();
void set_fullscreen( int );
int get_fullscreen();
@@ -50,9 +80,12 @@ public:
bool handle_event(void *event);
NPError get_root_layer(void *value);
+ std::vector<char> m_frame_buf;
+ unsigned int m_media_width;
+ unsigned int m_media_height;
+
private:
void set_player_window();
-
};
#endif /* __VLCPLUGIN_MAC_H__ */
diff --git a/npapi/vlcplugin_mac.mm b/npapi/vlcplugin_mac.mm
index 4040f7e..3a9c239 100644
--- a/npapi/vlcplugin_mac.mm
+++ b/npapi/vlcplugin_mac.mm
@@ -36,6 +36,13 @@
@end
+ at interface VLCPlaybackLayer : CALayer {
+ VlcPluginMac *_cppPlugin;
+}
+ at property (readwrite) VlcPluginMac * cppPlugin;
+
+ at end
+
@interface VLCControllerLayer : CALayer {
CGImageRef _playImage;
CGImageRef _pauseImage;
@@ -77,6 +84,7 @@
@end
static CALayer * rootLayer;
+static VLCPlaybackLayer * playbackLayer;
static VLCNoMediaLayer * noMediaLayer;
static VLCControllerLayer * controllerLayer;
@@ -88,13 +96,79 @@ VlcPluginMac::VlcPluginMac(NPP instance, NPuint16_t mode) :
VlcPluginMac::~VlcPluginMac()
{
+ [playbackLayer release];
+ [noMediaLayer release];
[controllerLayer release];
[rootLayer release];
}
void VlcPluginMac::set_player_window()
{
- // XXX FIXME insert appropriate call here
+ libvlc_video_set_format_callbacks(getMD(),
+ video_format_proxy,
+ video_cleanup_proxy);
+ libvlc_video_set_callbacks(getMD(),
+ video_lock_proxy,
+ video_unlock_proxy,
+ video_display_proxy,
+ this);
+}
+
+unsigned VlcPluginMac::video_format_cb(char *chroma,
+ unsigned *width, unsigned *height,
+ unsigned *pitches, unsigned *lines)
+{
+ if ( p_browser ) {
+ float src_aspect = (float)(*width) / (*height);
+ float dst_aspect = (float)npwindow.width/npwindow.height;
+ if ( src_aspect > dst_aspect ) {
+ if( npwindow.width != (*width) ) { //don't scale if size equal
+ (*width) = npwindow.width;
+ (*height) = static_cast<unsigned>( (*width) / src_aspect + 0.5);
+ }
+ }
+ else {
+ if( npwindow.height != (*height) ) { //don't scale if size equal
+ (*height) = npwindow.height;
+ (*width) = static_cast<unsigned>( (*height) * src_aspect + 0.5);
+ }
+ }
+ }
+
+ m_media_width = (*width);
+ m_media_height = (*height);
+
+ memcpy(chroma, "RGBA", sizeof("RGBA")-1);
+ (*pitches) = m_media_width * 4;
+ (*lines) = m_media_height;
+
+ //+1 for vlc 2.0.3/2.1 bug workaround.
+ //They writes after buffer end boundary by some reason unknown to me...
+ m_frame_buf.resize( (*pitches) * ((*lines)+1) );
+
+ return 1;
+}
+
+void VlcPluginMac::video_cleanup_cb()
+{
+ m_frame_buf.resize(0);
+ m_media_width = 0;
+ m_media_height = 0;
+}
+
+void* VlcPluginMac::video_lock_cb(void **planes)
+{
+ (*planes) = m_frame_buf.empty()? 0 : &m_frame_buf[0];
+ return 0;
+}
+
+void VlcPluginMac::video_unlock_cb(void* /*picture*/, void *const * /*planes*/)
+{
+}
+
+void VlcPluginMac::video_display_cb(void * /*picture*/)
+{
+ [playbackLayer performSelectorOnMainThread:@selector(setNeedsDisplay) withObject: nil waitUntilDone:NO];
}
void VlcPluginMac::toggle_fullscreen()
@@ -139,6 +213,14 @@ void VlcPluginMac::update_controls()
[controllerLayer setIsPlaying: playlist_isplaying()];
[controllerLayer setIsFullscreen:this->get_fullscreen()];
+ if (player_has_vout()) {
+ [noMediaLayer setHidden: YES];
+ [playbackLayer setHidden: NO];
+ } else {
+ [noMediaLayer setHidden: NO];
+ [playbackLayer setHidden: YES];
+ }
+
[controllerLayer setNeedsDisplay];
}
@@ -164,6 +246,12 @@ NPError VlcPluginMac::get_root_layer(void *value)
noMediaLayer.opaque = 1.;
[rootLayer addSublayer: noMediaLayer];
+ playbackLayer = [[VLCPlaybackLayer alloc] init];
+ playbackLayer.opaque = 1.;
+ [rootLayer addSublayer: playbackLayer];
+ [playbackLayer setCppPlugin: this];
+ [playbackLayer setHidden: YES];
+
controllerLayer = [[VLCControllerLayer alloc] init];
controllerLayer.opaque = 1.;
[rootLayer addSublayer: controllerLayer];
@@ -261,6 +349,79 @@ bool VlcPluginMac::handle_event(void *event)
return VlcPluginBase::handle_event(event);
}
+ at implementation VLCPlaybackLayer
+ at synthesize cppPlugin = _cppPlugin;
+
+- (id)init
+{
+ if (self = [super init]) {
+ self.needsDisplayOnBoundsChange = YES;
+ self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
+ }
+
+ return self;
+}
+
+- (void)drawInContext:(CGContextRef)cgContext
+{
+ if (!cgContext)
+ return;
+
+ if (![self cppPlugin]->playlist_isplaying() || ![self cppPlugin]->player_has_vout())
+ return;
+
+ unsigned int media_width = [self cppPlugin]->m_media_width;
+ unsigned int media_height = [self cppPlugin]->m_media_height;
+
+ if (media_width == 0 || media_height == 0)
+ return;
+
+ CGContextSaveGState(cgContext);
+
+ /* Compute the position of the video */
+ CGSize layerSize = [self preferredFrameSize];
+ float left = (layerSize.width - media_width) / 2.;
+ float top = (layerSize.height - media_height) / 2.;
+ static const size_t kComponentsPerPixel = 4;
+ static const size_t kBitsPerComponent = sizeof(unsigned char) * 8;
+
+ /* render frame */
+ CFDataRef dataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
+ (const uint8_t *)&[self cppPlugin]->m_frame_buf[0],
+ sizeof([self cppPlugin]->m_frame_buf[0]),
+ kCFAllocatorNull);
+ CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(dataRef);
+ CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
+ CGImageRef image = CGImageCreate(media_width,
+ media_height,
+ kBitsPerComponent,
+ kBitsPerComponent * kComponentsPerPixel,
+ kComponentsPerPixel * media_width,
+ colorspace,
+ kCGBitmapByteOrder16Big,
+ dataProvider,
+ NULL,
+ true,
+ kCGRenderingIntentPerceptual);
+ if (!image) {
+ CGColorSpaceRelease(colorspace);
+ CGImageRelease(image);
+ CGDataProviderRelease(dataProvider);
+ CGContextRestoreGState(cgContext);
+ return;
+ }
+ CGRect rect = CGRectMake(left, top, media_width, media_height);
+ CGContextDrawImage(cgContext, rect, image);
+
+ CGColorSpaceRelease(colorspace);
+ CGImageRelease(image);
+ CGDataProviderRelease(dataProvider);
+
+ CGContextRestoreGState(cgContext);
+}
+
+ at end
+
@implementation VLCNoMediaLayer
- (id)init
@@ -508,8 +669,6 @@ static CGImageRef createImageNamed(NSString *name)
_wasPlayingBeforeMouseDown = self.isPlaying;
_isScrubbing = YES;
- self.cppPlugin->playlist_pause();
-
if (CGRectContainsPoint([self _sliderThumbRect], point))
_mouseDownXDelta = point.x - CGRectGetMidX([self _sliderThumbRect]);
else {
@@ -525,9 +684,7 @@ static CGImageRef createImageNamed(NSString *name)
_isScrubbing = NO;
_mouseDownXDelta = 0;
- if (_wasPlayingBeforeMouseDown)
- self.cppPlugin->playlist_play();
- return;
+ return;
}
if (CGRectContainsPoint([self _playPauseButtonRect], point)) {
More information about the vlc-commits
mailing list