npapi-vlc | branch: master | Felix Paul Kühne <fkue...@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 +@interface VLCPlaybackLayer : CALayer { + VlcPluginMac *_cppPlugin; +} +@property (readwrite) VlcPluginMac * cppPlugin; + +@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); } +@implementation VLCPlaybackLayer +@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); +} + +@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)) { _______________________________________________ vlc-commits mailing list vlc-commits@videolan.org http://mailman.videolan.org/listinfo/vlc-commits