initial commit
[goodguy/history.git] / cinelerra-5.0 / guicast / bccapture.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bccapture.h"
23 #include "bcresources.h"
24 #include "bcwindowbase.h"
25 #include "bccmodels.h"
26 #include "language.h"
27 #include "vframe.h"
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <X11/Xutil.h>
31
32
33
34
35
36 // Byte orders:
37 // 24 bpp packed:         bgr
38 // 24 bpp unpacked:       0bgr
39
40
41 BC_Capture::BC_Capture(int w, int h, const char *display_path)
42 {
43         this->w = w;
44         this->h = h;
45
46         data = 0;
47         use_shm = 1;
48         init_window(display_path);
49         allocate_data();
50 }
51
52
53 BC_Capture::~BC_Capture()
54 {
55         delete_data();
56         XCloseDisplay(display);
57 }
58
59 int BC_Capture::init_window(const char *display_path)
60 {
61         int bits_per_pixel;
62         if(display_path && display_path[0] == 0) display_path = NULL;
63         if((display = XOpenDisplay(display_path)) == NULL)
64         {
65                 printf(_("cannot connect to X server.\n"));
66                 if(getenv("DISPLAY") == NULL)
67                 printf(_("'DISPLAY' environment variable not set.\n"));
68                 exit(-1);
69                 return 1;
70         }
71
72         screen = DefaultScreen(display);
73         rootwin = RootWindow(display, screen);
74         vis = DefaultVisual(display, screen);
75         default_depth = DefaultDepth(display, screen);
76         client_byte_order = (*(const u_int32_t*)"a   ") & 0x00000001;
77         server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
78         char *data = 0;
79         XImage *ximage;
80         ximage = XCreateImage(display,
81                                         vis,
82                                         default_depth,
83                                         ZPixmap,
84                                         0,
85                                         data,
86                                         16,
87                                         16,
88                                         8,
89                                         0);
90         bits_per_pixel = ximage->bits_per_pixel;
91         XDestroyImage(ximage);
92         bitmap_color_model = BC_WindowBase::evaluate_color_model(client_byte_order, server_byte_order, bits_per_pixel);
93
94 // test shared memory
95 // This doesn't ensure the X Server is on the local host
96     if(use_shm && !XShmQueryExtension(display))
97     {
98         use_shm = 0;
99     }
100         return 0;
101 }
102
103
104 int BC_Capture::allocate_data()
105 {
106 // try shared memory
107         if(!display) return 1;
108     if(use_shm)
109         {
110             ximage = XShmCreateImage(display, vis, default_depth, ZPixmap, (char*)NULL, &shm_info, w, h);
111
112                 shm_info.shmid = shmget(IPC_PRIVATE, h * ximage->bytes_per_line, IPC_CREAT | 0600);
113                 if(shm_info.shmid == -1)
114                 {
115                         perror("BC_Capture::allocate_data shmget");
116                         abort();
117                 }
118                 data = (unsigned char *)shmat(shm_info.shmid, NULL, 0);
119                 shmctl(shm_info.shmid, IPC_RMID, 0);
120                 ximage->data = shm_info.shmaddr = (char*)data;  // setting ximage->data stops BadValue
121                 shm_info.readOnly = 0;
122
123 // Crashes here if remote server.
124                 BC_Resources::error = 0;
125                 XShmAttach(display, &shm_info);
126         XSync(display, False);
127                 if(BC_Resources::error)
128                 {
129                         XDestroyImage(ximage);
130                         shmdt(shm_info.shmaddr);
131                         use_shm = 0;
132                 }
133         }
134
135         if(!use_shm)
136         {
137 // need to use bytes_per_line for some X servers
138                 data = 0;
139                 ximage = XCreateImage(display, vis, default_depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
140                 data = (unsigned char*)malloc(h * ximage->bytes_per_line);
141                 XDestroyImage(ximage);
142
143                 ximage = XCreateImage(display, vis, default_depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
144         }
145
146         row_data = new unsigned char*[h];
147         for(int i = 0; i < h; i++)
148         {
149                 row_data[i] = &data[i * ximage->bytes_per_line];
150         }
151 // This differs from the depth parameter of the top_level.
152         bits_per_pixel = ximage->bits_per_pixel;
153         return 0;
154 }
155
156 int BC_Capture::delete_data()
157 {
158         if(!display) return 1;
159         if(data)
160         {
161                 if(use_shm)
162                 {
163                         XShmDetach(display, &shm_info);
164                         XDestroyImage(ximage);
165                         shmdt(shm_info.shmaddr);
166                 }
167                 else
168                 {
169                         XDestroyImage(ximage);
170                 }
171
172 // data is automatically freed by XDestroyImage
173                 data = 0;
174                 delete row_data;
175         }
176         return 0;
177 }
178
179
180 int BC_Capture::get_w() { return w; }
181 int BC_Capture::get_h() { return h; }
182
183 // Capture a frame from the screen
184 #define CAPTURE_FRAME_HEAD \
185         for(int i = 0; i < h; i++) \
186         { \
187                 unsigned char *input_row = row_data[i]; \
188                 unsigned char *output_row = (unsigned char*)frame->get_rows()[i]; \
189                 for(int j = 0; j < w; j++) \
190                 {
191
192 #define CAPTURE_FRAME_TAIL \
193                 } \
194         }
195
196
197
198 int BC_Capture::capture_frame(VFrame *frame, int &x1, int &y1)
199 {
200         if(!display) return 1;
201         if(x1 < 0) x1 = 0;
202         if(y1 < 0) y1 = 0;
203         if(x1 > get_top_w() - w) x1 = get_top_w() - w;
204         if(y1 > get_top_h() - h) y1 = get_top_h() - h;
205
206
207 // Read the raw data
208         if(use_shm)
209                 XShmGetImage(display, rootwin, ximage, x1, y1, 0xffffffff);
210         else
211                 XGetSubImage(display, rootwin, x1, y1, w, h, 0xffffffff, ZPixmap, ximage, 0, 0);
212
213         BC_CModels::transfer(frame->get_rows(), row_data,
214                 frame->get_y(), frame->get_u(), frame->get_v(), 0,
215                 0, 0, 0, 0, w, h, 0, 0,
216                 frame->get_w(), frame->get_h(),
217                 bitmap_color_model, frame->get_color_model(),
218                 0, frame->get_w(), w);
219
220         return 0;
221 }
222
223 int BC_Capture::get_top_w()
224 {
225         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
226         return WidthOfScreen(screen_ptr);
227 }
228
229 int BC_Capture::get_top_h()
230 {
231         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
232         return HeightOfScreen(screen_ptr);
233 }