[vlc-devel] Screen capture module for Mac OS X
Pierre d'Herbemont
pdherbemont at free.fr
Sun Apr 6 21:47:09 CEST 2008
Hi!
Thanks for your patch.
Could you resend it using git-format-patch in order to preserve the
authorship of the patch?
http://wiki.videolan.org/Git#Submitting_patches_to_the_vlc-devel
Pierre.
On Apr 6, 2008, at 9:01 PM, arai wrote:
> Hello all,
>
> I've written Screen capture module for Mac OS X, using OpenGL
> instead of QuickDraw.
> I hope it helps someone who want to do desktop streaming with Mac OS
> X.
>
> This patch needs "-I/usr/X11/include" flag for compiling,
> and "-framework OpenGL" flag for linking.
> I'm not good at automake, could anyone make patch for those?
>
> Best Regards.
>
> arai
> diff --git a/vlc-0.8.6f/modules/access/screen/mac.c b/
> vlc-0.8.6f.original/modules/access/screen/mac.c
> index 6f70b96..fac7fbd 100644
> --- a/vlc-0.8.6f/modules/access/screen/mac.c
> +++ b/vlc-0.8.6f.original/modules/access/screen/mac.c
> @@ -29,259 +29,152 @@
> #include <vlc/vlc.h>
> #include <vlc/input.h>
>
> -#import <OpenGL/OpenGL.h>
> -#include <GL/gl.h>
> +#include <Carbon/Carbon.h>
> #include <ApplicationServices/ApplicationServices.h>
>
> typedef int CGSConnectionRef;
> -extern CGError CGSNewConnection( void *, CGSConnectionRef * );
> -extern CGError CGSReleaseConnection( CGSConnectionRef );
> -extern CGError CGSGetGlobalCursorDataSize( CGSConnectionRef, int * );
> -extern CGError CGSGetGlobalCursorData( CGSConnectionRef, unsigned
> char *,
> - int *, int *, CGRect *,
> CGPoint *,
> - int *, int *, int * );
> -extern CGError CGSGetCurrentCursorLocation( CGSConnectionRef,
> CGPoint * );
> +extern CGError CGSNewConnection(void* unknown, CGSConnectionRef*
> newConnection);
> +extern CGError CGSReleaseConnection(CGSConnectionRef connection);
>
> #include "screen.h"
>
> struct screen_data_t
> {
> - CGLContextObj screen;
> -
> - CGLContextObj scaled;
> - char *scaled_image;
> -
> - GLuint texture;
> - char *texture_image;
> -
> - GLuint cursor_texture;
> -
> - int left;
> - int top;
> - int src_width;
> - int src_height;
> -
> - int dest_width;
> - int dest_height;
> -
> - int screen_width;
> - int screen_height;
> -
> - CGSConnectionRef connection;
> + RGBColor oldForeColor, oldBackColor;
> + PenState oldState;
> + CGDirectDisplayID displayID;
> + CGSConnectionRef gConnection;
> + GDHandle gMainDevice;
> + char gDeviceState;
> + PixMapHandle gDevicePix;
> + GWorldPtr LocalBufferGW;
> + PixMapHandle LocalBufferPix;
> };
>
> int screen_InitCapture( demux_t *p_demux )
> {
> demux_sys_t *p_sys = p_demux->p_sys;
> screen_data_t *p_data;
> - CGLPixelFormatAttribute attribs[4];
> - CGLPixelFormatObj pix;
> - GLint npix;
> - GLint viewport[4];
> -
> + int i_chroma, i_bbp, i_offset;
> +
> + i_chroma = i_bbp = i_offset = 0;
> +
> p_sys->p_data = p_data =
> - ( screen_data_t * )malloc( sizeof( screen_data_t ) );
> -
> - attribs[0] = kCGLPFAFullScreen;
> - attribs[1] = kCGLPFADisplayMask;
> - attribs[2] = CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() );
> - attribs[3] = 0;
> -
> - CGLChoosePixelFormat( attribs, &pix, &npix );
> - CGLCreateContext( pix, NULL, &( p_data->screen ) );
> - CGLDestroyPixelFormat( pix );
> + (screen_data_t *)malloc( sizeof( screen_data_t ) );
>
> - CGLSetCurrentContext( p_data->screen );
> - CGLSetFullScreen( p_data->screen );
> -
> - glGetIntegerv( GL_VIEWPORT, viewport );
> -
> - p_data->screen_width = viewport[2];
> - p_data->screen_height = viewport[3];
> -
> - p_data->left = 0;
> - p_data->top = 0;
> - p_data->src_width = p_data->screen_width;
> - p_data->src_height = p_data->screen_height;
> - p_data->dest_width = p_data->src_width;
> - p_data->dest_height = p_data->src_height;
> -
> - attribs [0] = kCGLPFAOffScreen;
> - attribs [1] = kCGLPFAColorSize;
> - attribs [2] = 32;
> - attribs [3] = 0;
> -
> - CGLChoosePixelFormat( attribs, &pix, &npix );
> - CGLCreateContext( pix, NULL, &( p_data->scaled ) );
> - CGLDestroyPixelFormat( pix );
> + p_data->gConnection = nil;
> + p_data->gMainDevice = NULL;
> + p_data->gDevicePix = NULL;
> + p_data->gDeviceState = nil;
> + p_data->LocalBufferGW = NULL;
> + p_data->LocalBufferPix = NULL;
>
> - CGLSetCurrentContext( p_data->scaled );
> - p_data->scaled_image = ( char * )malloc( p_data->dest_width
> - * p_data->dest_height *
> 4 );
> - CGLSetOffScreen( p_data->scaled, p_data->dest_width, p_data-
> >dest_height,
> - p_data->dest_width * 4, p_data->scaled_image );
> -
> - es_format_Init( &p_sys->fmt, VIDEO_ES,
> VLC_FOURCC( 'R','V','3','2' ) );
> -
> - p_sys->fmt.video.i_width = p_data->dest_width;
> - p_sys->fmt.video.i_visible_width = p_data->dest_width;
> - p_sys->fmt.video.i_height = p_data->dest_height;
> - p_sys->fmt.video.i_bits_per_pixel = 32;
> -
> - glGenTextures( 1, &( p_data->texture ) );
> - glBindTexture( GL_TEXTURE_2D, p_data->texture );
> -
> - p_data->texture_image
> - = ( char * )malloc( p_data->src_width * p_data->src_height *
> 4 );
> -
> - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
> GL_NEAREST );
> - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
> GL_NEAREST );
> - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
> - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
> + p_data->displayID = CGMainDisplayID();
> + (void) GetMainDevice();
>
> - glGenTextures( 1, &( p_data->cursor_texture ) );
> - glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
> -
> - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
> GL_NEAREST );
> - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
> GL_NEAREST );
> - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
> - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
> -
> - CGSNewConnection( NULL, &( p_data->connection ) );
> + if( CGDisplaySamplesPerPixel(p_data->displayID) != 3 )
> + {
> + msg_Err( p_demux, "screenformat not supported" );
> + }
>
> + switch( CGDisplaySamplesPerPixel(p_data->displayID) *
> CGDisplayBitsPerSample(p_data->displayID) )
> + {
> + /* TODO figure out 256 colors (who uses it anyways) */
> + case 15: /* TODO this is not RV16, but BGR16 */
> + i_chroma = VLC_FOURCC('R','V','1','6');
> + i_bbp = 16;
> + i_offset = 8;
> + break;
> + case 24:
> + case 32:
> + i_chroma = VLC_FOURCC('R','V','3','2');
> + i_bbp = 32;
> + i_offset = 4;
> + break;
> + default:
> + msg_Err( p_demux, "unknown screen depth: %d", (int)
> (CGDisplaySamplesPerPixel(p_data->displayID) *
> CGDisplayBitsPerSample(p_data->displayID)) );
> + return VLC_EGENERIC;
> + }
> +
> + GetBackColor(&p_data->oldBackColor);
> + GetPenState(&p_data->oldState);
> + ForeColor(blackColor);
> + BackColor(whiteColor);
> +
> + p_data->gMainDevice = GetMainDevice();
> + p_data->gDeviceState = HGetState((Handle)p_data->gMainDevice);
> + HLock((Handle)p_data->gMainDevice);
> + p_data->gDevicePix = (**p_data->gMainDevice).gdPMap;
> +
> + NewGWorld(&p_data->LocalBufferGW, (**p_data-
> >gDevicePix).pixelSize, &(**p_data->gDevicePix).bounds, (**p_data-
> >gDevicePix).pmTable, NULL, 0);
> + p_data->LocalBufferPix = GetGWorldPixMap(p_data->LocalBufferGW);
> + LockPixels(p_data->LocalBufferPix);
> +
> + es_format_Init( &p_sys->fmt, VIDEO_ES, i_chroma );
> + p_sys->fmt.video.i_width = CGDisplayPixelsWide(p_data-
> >displayID) + i_offset;
> + p_sys->fmt.video.i_visible_width = CGDisplayPixelsWide(p_data-
> >displayID);
> + p_sys->fmt.video.i_height = CGDisplayPixelsHigh(p_data-
> >displayID);
> + p_sys->fmt.video.i_bits_per_pixel = i_bbp;
> +
> + GetForeColor(&p_data->oldForeColor);
> +
> + HSetState( (Handle)p_data->gMainDevice, p_data->gDeviceState );
> + SetPenState( &p_data->oldState);
> + RGBForeColor( &p_data->oldForeColor );
> + RGBBackColor( &p_data->oldBackColor );
> +
> return VLC_SUCCESS;
> }
>
> int screen_CloseCapture( demux_t *p_demux )
> {
> - screen_data_t *p_data = ( screen_data_t * )p_demux->p_sys-
> >p_data;
> -
> - CGSReleaseConnection( p_data->connection );
> -
> - CGLSetCurrentContext( NULL );
> - CGLClearDrawable( p_data->screen );
> - CGLDestroyContext( p_data->screen );
> -
> + screen_data_t *p_data = (screen_data_t *)p_demux->p_sys->p_data;
> +
> + if(p_data->LocalBufferPix) UnlockPixels(p_data-
> >LocalBufferPix); p_data->LocalBufferPix = NULL;
> + if(p_data->LocalBufferGW) DisposeGWorld(p_data->LocalBufferGW);
> p_data->LocalBufferGW = NULL;
> +
> return VLC_SUCCESS;
> }
>
> block_t *screen_Capture( demux_t *p_demux )
> {
> demux_sys_t *p_sys = p_demux->p_sys;
> - screen_data_t *p_data = ( screen_data_t * )p_sys->p_data;
> + screen_data_t *p_data = (screen_data_t *)p_sys->p_data;
> block_t *p_block;
> int i_size;
> -
> - i_size = p_sys->fmt.video.i_height * p_sys->fmt.video.i_width *
> 4;
> -
> +
> + i_size = p_sys->fmt.video.i_height * p_sys->fmt.video.i_width *
> 32 / 8;
> +
> if( !( p_block = block_New( p_demux, i_size ) ) )
> {
> msg_Warn( p_demux, "cannot get block" );
> return 0;
> }
> -
> - CGLSetCurrentContext( p_data->screen );
> - glReadPixels( p_data->left,
> - p_data->screen_height - p_data->top - p_data-
> >src_height,
> - p_data->src_width,
> - p_data->src_height,
> - GL_RGBA, GL_UNSIGNED_BYTE,
> - p_data->texture_image );
> -
> - CGLSetCurrentContext( p_data->scaled );
> - glEnable( GL_TEXTURE_2D );
> - glBindTexture( GL_TEXTURE_2D, p_data->texture );
> - glTexImage2D( GL_TEXTURE_2D, 0,
> - GL_RGBA8, p_data->src_width, p_data->src_height, 0,
> - GL_RGBA, GL_UNSIGNED_BYTE, p_data->texture_image );
> -
> - glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
> - glClear( GL_COLOR_BUFFER_BIT );
> - glColor3f( 1.0f, 1.0f, 1.0f );
> - glEnable( GL_TEXTURE_2D );
> - glBindTexture( GL_TEXTURE_2D, p_data->texture );
> - glBegin( GL_POLYGON );
> - glTexCoord2f( 0.0, 1.0 ); glVertex2f( -1.0, -1.0 );
> - glTexCoord2f( 1.0, 1.0 ); glVertex2f( 1.0, -1.0 );
> - glTexCoord2f( 1.0, 0.0 ); glVertex2f( 1.0, 1.0 );
> - glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, 1.0 );
> - glEnd();
> - glDisable( GL_TEXTURE_2D );
> -
> - CGPoint cursor_pos;
> - int size;
> - int tmp1, tmp2, tmp3, tmp4;
> - unsigned char *cursor_image;
> - CGRect cursor_rect;
> - CGPoint cursor_hot;
> -
> - cursor_pos.x = 0;
> - cursor_pos.y = 0;
> -
> - if( CGSGetCurrentCursorLocation( p_data->connection,
> &cursor_pos )
> - == kCGErrorSuccess
> - && CGSGetGlobalCursorDataSize( p_data->connection, &size )
> - == kCGErrorSuccess )
> - {
> - cursor_image = ( unsigned char* )malloc( size );
> - if( CGSGetGlobalCursorData( p_data->connection,
> - cursor_image, &size,
> - &tmp1,
> - &cursor_rect, &cursor_hot,
> - &tmp2, &tmp3, &tmp4 )
> - == kCGErrorSuccess )
> - {
> - glEnable( GL_TEXTURE_2D );
> - glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
> - glTexImage2D( GL_TEXTURE_2D, 0,
> - GL_RGBA8,
> - ( int )( cursor_rect.size.width ),
> - ( int )( cursor_rect.size.height ), 0,
> - GL_RGBA, GL_UNSIGNED_BYTE,
> - ( char * )cursor_image );
> -
> - cursor_rect.origin.x = cursor_pos.x - p_data->left -
> cursor_hot.x;
> - cursor_rect.origin.y = cursor_pos.y - p_data->top -
> cursor_hot.y;
> -
> - cursor_rect.origin.x
> - = 2.0 * cursor_rect.origin.x / p_data->src_width - 1.0;
> - cursor_rect.origin.y
> - = 2.0 * cursor_rect.origin.y / p_data->src_height -
> 1.0;
> - cursor_rect.size.width
> - = 2.0 * cursor_rect.size.width / p_data->src_width;
> - cursor_rect.size.height
> - = 2.0 * cursor_rect.size.height / p_data->src_height;
> -
> - glColor3f( 1.0f, 1.0f, 1.0f );
> - glEnable( GL_TEXTURE_2D );
> - glEnable( GL_BLEND );
> - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
> - glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
> - glBegin( GL_POLYGON );
> - glTexCoord2f( 0.0, 0.0 );
> glVertex2f( cursor_rect.origin.x,
> -
> cursor_rect.origin.y );
> - glTexCoord2f( 1.0, 0.0 );
> glVertex2f( cursor_rect.origin.x
> - +
> cursor_rect.size.width,
> -
> cursor_rect.origin.y );
> - glTexCoord2f( 1.0, 1.0 );
> glVertex2f( cursor_rect.origin.x
> - +
> cursor_rect.size.width,
> -
> cursor_rect.origin.y
> - +
> cursor_rect.size.height );
> - glTexCoord2f( 0.0, 1.0 );
> glVertex2f( cursor_rect.origin.x,
> -
> cursor_rect.origin.y
> - +
> cursor_rect.size.height );
> - glEnd();
> - glDisable( GL_BLEND );
> - glDisable( GL_TEXTURE_2D );
> - }
> - free( cursor_image );
> - }
> -
> - glReadPixels( 0, 0,
> - p_data->dest_width,
> - p_data->dest_height,
> - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
> - p_block->p_buffer );
> -
> +
> + GetForeColor(&p_data->oldForeColor);
> + GetBackColor(&p_data->oldBackColor);
> + GetPenState(&p_data->oldState);
> + ForeColor(blackColor);
> + BackColor(whiteColor);
> +
> + assert(CGSNewConnection(NULL, &p_data->gConnection) ==
> kCGErrorSuccess);
> + p_data->gMainDevice = GetMainDevice();
> + p_data->gDeviceState = HGetState((Handle)p_data->gMainDevice);
> + HLock((Handle)p_data->gMainDevice);
> + p_data->gDevicePix = (**p_data->gMainDevice).gdPMap;
> +
> + CopyBits(( BitMap*)*p_data->gDevicePix, (BitMap*)*p_data-
> >LocalBufferPix,
> + &(**p_data->gDevicePix).bounds, &(**p_data-
> >gDevicePix).bounds,
> + srcCopy, NULL );
> +
> + HSetState( (Handle)p_data->gMainDevice, p_data->gDeviceState );
> + SetPenState( &p_data->oldState );
> + RGBForeColor( &p_data->oldForeColor );
> + RGBBackColor( &p_data->oldBackColor );
> +
> + assert(CGSReleaseConnection(p_data->gConnection) ==
> kCGErrorSuccess);
> + memcpy( p_block->p_buffer, (**p_data->LocalBufferPix).baseAddr,
> i_size );
> +
> return p_block;
> }
> +
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> http://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list