]> git.sesse.net Git - vlc/blob - modules/access/screen/mac.c
056170ceda251f8539be6abc566a4fb504710d33
[vlc] / modules / access / screen / mac.c
1 /*****************************************************************************
2  * mac.c: Screen capture module for the Mac.
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <vlc/vlc.h>
29
30 #include <Carbon/Carbon.h>
31 #include <ApplicationServices/ApplicationServices.h>
32
33 typedef int CGSConnectionRef;
34 extern CGError CGSNewConnection(void* unknown, CGSConnectionRef* newConnection);
35 extern CGError CGSReleaseConnection(CGSConnectionRef connection);
36
37 #include "screen.h"
38
39 struct screen_data_t
40 {
41     RGBColor          oldForeColor, oldBackColor;
42     PenState          oldState;
43     CGDirectDisplayID displayID;
44     CGSConnectionRef  gConnection;
45     GDHandle          gMainDevice;
46     char              gDeviceState;
47     PixMapHandle      gDevicePix;
48     GWorldPtr         LocalBufferGW;
49     PixMapHandle      LocalBufferPix;
50 };
51
52 int screen_InitCapture( demux_t *p_demux )
53 {
54     demux_sys_t   *p_sys = p_demux->p_sys;
55     screen_data_t *p_data;
56     int            i_chroma, i_bbp, i_offset;
57
58     i_chroma = i_bbp = i_offset = 0;
59
60     p_sys->p_data = p_data =
61         (screen_data_t *)malloc( sizeof( screen_data_t ) );
62
63     p_data->gConnection = nil;
64     p_data->gMainDevice = NULL;
65     p_data->gDevicePix = NULL;
66     p_data->gDeviceState = nil;
67     p_data->LocalBufferGW = NULL;
68     p_data->LocalBufferPix = NULL;
69
70     p_data->displayID = CGMainDisplayID();
71     (void) GetMainDevice();
72
73     if( CGDisplaySamplesPerPixel(p_data->displayID) != 3 )
74     {
75         msg_Err( p_demux, "screenformat not supported" );
76     } 
77     
78     switch( CGDisplaySamplesPerPixel(p_data->displayID) * CGDisplayBitsPerSample(p_data->displayID) )
79     {
80     /* TODO figure out 256 colors (who uses it anyways) */
81     case 15: /* TODO this is not RV16, but BGR16 */
82         i_chroma = VLC_FOURCC('R','V','1','6');
83         i_bbp = 16;
84         i_offset = 8;
85         break;
86     case 24:
87     case 32:
88         i_chroma = VLC_FOURCC('R','V','3','2');
89         i_bbp = 32;
90         i_offset = 4;
91         break;
92     default:
93         msg_Err( p_demux, "unknown screen depth: %d", (int)(CGDisplaySamplesPerPixel(p_data->displayID) * CGDisplayBitsPerSample(p_data->displayID)) );
94         return VLC_EGENERIC;
95     }
96
97     GetBackColor(&p_data->oldBackColor);
98     GetPenState(&p_data->oldState);
99     ForeColor(blackColor);
100     BackColor(whiteColor);
101     
102     p_data->gMainDevice = GetMainDevice();
103     p_data->gDeviceState = HGetState((Handle)p_data->gMainDevice);
104     HLock((Handle)p_data->gMainDevice);
105     p_data->gDevicePix = (**p_data->gMainDevice).gdPMap;
106
107     NewGWorld(&p_data->LocalBufferGW, (**p_data->gDevicePix).pixelSize, &(**p_data->gDevicePix).bounds, (**p_data->gDevicePix).pmTable, NULL, 0);
108     p_data->LocalBufferPix = GetGWorldPixMap(p_data->LocalBufferGW);
109     LockPixels(p_data->LocalBufferPix);
110     
111     es_format_Init( &p_sys->fmt, VIDEO_ES, i_chroma );
112     p_sys->fmt.video.i_width  = CGDisplayPixelsWide(p_data->displayID) + i_offset;
113     p_sys->fmt.video.i_visible_width  = CGDisplayPixelsWide(p_data->displayID);
114     p_sys->fmt.video.i_height = CGDisplayPixelsHigh(p_data->displayID);
115     p_sys->fmt.video.i_bits_per_pixel = i_bbp;
116
117     GetForeColor(&p_data->oldForeColor);
118
119     HSetState( (Handle)p_data->gMainDevice, p_data->gDeviceState );
120     SetPenState( &p_data->oldState);
121     RGBForeColor( &p_data->oldForeColor );
122     RGBBackColor( &p_data->oldBackColor );
123
124     return VLC_SUCCESS;
125 }
126
127 int screen_CloseCapture( demux_t *p_demux )
128 {
129     screen_data_t *p_data = (screen_data_t *)p_demux->p_sys->p_data;
130
131     if(p_data->LocalBufferPix) UnlockPixels(p_data->LocalBufferPix); p_data->LocalBufferPix = NULL;
132     if(p_data->LocalBufferGW) DisposeGWorld(p_data->LocalBufferGW); p_data->LocalBufferGW = NULL;
133
134     return VLC_SUCCESS;
135 }
136
137 block_t *screen_Capture( demux_t *p_demux )
138 {
139     demux_sys_t *p_sys = p_demux->p_sys;
140     screen_data_t *p_data = (screen_data_t *)p_sys->p_data;
141     block_t *p_block;
142     int i_size;
143  
144     i_size = p_sys->fmt.video.i_height * p_sys->fmt.video.i_width * 32 / 8; 
145
146     if( !( p_block = block_New( p_demux, i_size ) ) )
147     {
148         msg_Warn( p_demux, "cannot get block" );
149         return 0;
150     }
151
152     GetForeColor(&p_data->oldForeColor);
153     GetBackColor(&p_data->oldBackColor);
154     GetPenState(&p_data->oldState);
155     ForeColor(blackColor);
156     BackColor(whiteColor);
157
158     assert(CGSNewConnection(NULL, &p_data->gConnection) == kCGErrorSuccess);
159     p_data->gMainDevice = GetMainDevice();
160     p_data->gDeviceState = HGetState((Handle)p_data->gMainDevice);
161     HLock((Handle)p_data->gMainDevice);
162     p_data->gDevicePix = (**p_data->gMainDevice).gdPMap;
163
164     CopyBits(( BitMap*)*p_data->gDevicePix, (BitMap*)*p_data->LocalBufferPix,
165              &(**p_data->gDevicePix).bounds, &(**p_data->gDevicePix).bounds,
166              srcCopy, NULL );
167
168     HSetState( (Handle)p_data->gMainDevice, p_data->gDeviceState );
169     SetPenState( &p_data->oldState );
170     RGBForeColor( &p_data->oldForeColor );
171     RGBBackColor( &p_data->oldBackColor );
172
173     assert(CGSReleaseConnection(p_data->gConnection) == kCGErrorSuccess);
174     memcpy( p_block->p_buffer, (**p_data->LocalBufferPix).baseAddr, i_size );
175
176     return p_block;
177 }
178