tizen 2.3 release
[framework/system/swap-probe.git] / helper / dacapture.c
1 /*
2  *  DA probe
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  *
8  * Jaewon Lim <jaewon81.lim@samsung.com>
9  * Woojin Jung <woojin2.jung@samsung.com>
10  * Juyoung Kim <j0.kim@samsung.com>
11  * Anastasia Lyupa <a.lyupa@samsung.com>
12  *
13  * This library is free software; you can redistribute it and/or modify it under
14  * the terms of the GNU Lesser General Public License as published by the
15  * Free Software Foundation; either version 2.1 of the License, or (at your option)
16  * any later version.
17  *
18  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
19  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
21  * License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License
24  * along with this library; if not, write to the Free Software Foundation, Inc., 51
25  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26  *
27  * Contributors:
28  * - S-Core Co., Ltd
29  * - Samsung RnD Institute Russia
30  *
31  */
32 /*
33  * We refer to the Evas example source code with BSD
34  * (Evas/src/examples/evas-buffer-simple.c)
35  *
36  */
37
38 #include <stdlib.h>             // for system
39 #include <sys/types.h>          // for stat, getpid
40 #include <sys/stat.h>           // fot stat, chmod
41 #include <unistd.h>             // fot stat, getpid
42 #include <sys/shm.h>            // for shmget, shmat
43 #include <pthread.h>            // for mutex
44
45 #include <X11/Xlib.h>
46 #include <X11/Xutil.h>
47 #include <X11/extensions/XShm.h>
48
49 #include <Ecore.h>
50 #include <Evas.h>
51 #include <Evas_Engine_Buffer.h>
52
53 #include "real_functions.h"
54 #include "daprobe.h"
55 #include "dahelper.h"
56
57 #include "binproto.h"
58
59 #define MAX_HEIGHT      720
60 #define CAPTURE_TIMEOUT         2.0
61
62 typedef struct _screenshot_data
63 {
64         XImage*                 ximage;
65         Display*                dpy;
66         XShmSegmentInfo x_shm_info;
67 } screenshot_data;
68
69 /*
70 int convert_image(      void* srcbuf, void* dstbuf,
71                                         pixman_format_code_t src_format,
72                                         pixman_format_code_t dst_format,
73                                         int src_width, int src_height,
74                                         int dst_width, int dst_height,
75                                         int     rotate)
76 {
77         pixman_image_t *   src_img;
78         pixman_image_t *   dst_img;
79         pixman_transform_t transform;
80
81         int                src_stride, dst_stride;
82         int                src_bpp;
83         int                dst_bpp;
84         pixman_op_t        op;
85         int                rotate_step;
86         int                ret = False;
87
88         return_val_if_fail (srcbuf != NULL, False);
89         return_val_if_fail (dstbuf != NULL, False);
90         return_val_if_fail (rotate <= 360 && rotate >= -360, False);
91
92         op = PIXMAN_OP_SRC;
93
94         src_bpp = PIXMAN_FORMAT_BPP (src_format) / 8;
95         return_val_if_fail (src_bpp > 0, False);
96
97         dst_bpp = PIXMAN_FORMAT_BPP (dst_format) / 8;
98         return_val_if_fail (dst_bpp > 0, False);
99
100         rotate_step = (rotate + 360) / 90 % 4;
101
102         src_stride = src_width * src_bpp;
103         dst_stride = dst_width * dst_bpp;
104
105         src_img = pixman_image_create_bits (src_format, src_width, src_height, srcbuf, src_stride);
106         dst_img = pixman_image_create_bits (dst_format, dst_width, dst_height, dstbuf, dst_stride);
107
108         goto_if_fail (src_img != NULL, CANT_CONVERT);
109         goto_if_fail (dst_img != NULL, CANT_CONVERT);
110
111         pixman_transform_init_identity (&transform);
112
113         if (rotate_step > 0)
114         {
115                 int c, s, tx = 0, ty = 0;
116                 switch (rotate_step)
117                 {
118                 case 1:
119                         // 270 degrees
120                         c = 0;
121                         s = -pixman_fixed_1;
122                         ty = pixman_int_to_fixed (dst_width);
123                         break;
124                 case 2:
125                         // 180 degrees
126                         c = -pixman_fixed_1;
127                         s = 0;
128                         tx = pixman_int_to_fixed (dst_width);
129                         ty = pixman_int_to_fixed (dst_height);
130                         break;
131                 case 3:
132                         // 90 degrees
133                         c = 0;
134                         s = pixman_fixed_1;
135                         tx = pixman_int_to_fixed (dst_height);
136                         break;
137                 default:
138                         // 0 degrees
139                         c = 0;
140                         s = 0;
141                         break;
142                 }
143                 pixman_transform_rotate (&transform, NULL, c, s);
144                 pixman_transform_translate (&transform, NULL, tx, ty);
145         }
146
147         pixman_image_set_transform (src_img, &transform);
148
149         pixman_image_composite (op, src_img, NULL, dst_img,
150                                 0, 0, 0, 0, 0, 0, dst_width, dst_height);
151
152         ret = True;
153
154 CANT_CONVERT:
155         if (src_img)
156                 pixman_image_unref (src_img);
157         if (dst_img)
158                 pixman_image_unref (dst_img);
159
160         return ret;
161 }
162 */
163
164 static char* captureScreenShotX(int* pwidth, int* pheight, screenshot_data* sdata)
165 {
166         Window                  root;
167 //      Atom                    atom_rotation;
168
169         sdata->dpy = XOpenDisplay(NULL);
170         if(unlikely(sdata->dpy == NULL))
171         {
172                 // XOpenDisplay failed!
173                 return NULL;
174         }
175
176         *pwidth = DisplayWidth(sdata->dpy, DefaultScreen(sdata->dpy));
177         *pheight = DisplayHeight(sdata->dpy, DefaultScreen(sdata->dpy));
178
179         root = RootWindow(sdata->dpy, DefaultScreen(sdata->dpy));
180
181         sdata->ximage = XShmCreateImage(sdata->dpy, DefaultVisualOfScreen (DefaultScreenOfDisplay (sdata->dpy)), 24,
182                                         ZPixmap, NULL, &sdata->x_shm_info, (unsigned int)*pwidth, (unsigned int)*pheight);
183
184         if(sdata->ximage != NULL)
185         {
186                 sdata->x_shm_info.shmid = shmget(IPC_PRIVATE, sdata->ximage->bytes_per_line * sdata->ximage->height, IPC_CREAT | 0777);
187                 sdata->x_shm_info.shmaddr = sdata->ximage->data = shmat(sdata->x_shm_info.shmid, 0, 0);
188                 sdata->x_shm_info.readOnly = False;
189
190                 if(XShmAttach(sdata->dpy, &sdata->x_shm_info))
191                 {
192                         if(XShmGetImage(sdata->dpy, root, sdata->ximage, 0, 0, AllPlanes))
193                         {
194                                 XSync (sdata->dpy, False);
195                                 return sdata->ximage->data;
196                         }
197                         else
198                         {
199                                 ; // XShmGetImage failed !
200                         }
201
202                         XShmDetach (sdata->dpy, &sdata->x_shm_info);
203                 }
204                 else
205                 {
206                         ; // XShmAttach failed !
207                 }
208
209                 shmdt (sdata->x_shm_info.shmaddr);
210                 shmctl (sdata->x_shm_info.shmid, IPC_RMID, NULL);
211                 XDestroyImage(sdata->ximage);
212                 sdata->ximage = NULL;
213         }
214         else
215         {
216                 ; // XShmCreateImage failed!
217         }
218
219         return NULL;
220 }
221
222 static void releaseScreenShotX(screenshot_data* sdata)
223 {
224         if(sdata->ximage)
225         {
226                 XShmDetach (sdata->dpy, &sdata->x_shm_info);
227                 shmdt (sdata->x_shm_info.shmaddr);
228                 shmctl (sdata->x_shm_info.shmid, IPC_RMID, NULL);
229                 XDestroyImage(sdata->ximage);
230         }
231         else { }
232
233         if(sdata->dpy)
234         {
235                 XCloseDisplay(sdata->dpy);
236         }
237 }
238
239 static Evas* create_canvas(int width, int height)
240 {
241         Evas *canvas;
242         Evas_Engine_Info_Buffer *einfo;
243         int method;
244         void *pixels;
245
246         method = evas_render_method_lookup("buffer");
247         if (unlikely(method <= 0))
248         {
249                 //fputs("ERROR: evas was not compiled with 'buffer' engine!\n", stderr);
250                 return NULL;
251         }
252
253         canvas = evas_new();
254         if (unlikely(canvas == NULL))
255         {
256                 //fputs("ERROR: could not instantiate new evas canvas.\n", stderr);
257                 return NULL;
258         }
259
260         evas_output_method_set(canvas, method);
261         evas_output_size_set(canvas, width, height);
262         evas_output_viewport_set(canvas, 0, 0, width, height);
263
264         einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
265         if (unlikely(einfo == NULL))
266         {
267                 //fputs("ERROR: could not get evas engine info!\n", stderr);
268                 evas_free(canvas);
269                 return NULL;
270         }
271
272         // ARGB32 is sizeof(int), that is 4 bytes, per pixel
273         pixels = real_malloc(width * height * sizeof(int));
274         if (unlikely(pixels == NULL)) {
275                 //fputs("ERROR: could not allocate canvas pixels!\n", stderr);
276                 evas_free(canvas);
277                 return NULL;
278         }
279
280         einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
281         einfo->info.dest_buffer = pixels;
282         einfo->info.dest_buffer_row_bytes = width * sizeof(int);
283         einfo->info.use_color_key = 0;
284         einfo->info.alpha_threshold = 0;
285         einfo->info.func.new_update_region = NULL;
286         einfo->info.func.free_update_region = NULL;
287
288         if (unlikely(evas_engine_info_set(canvas,(Evas_Engine_Info*)einfo) == EINA_FALSE)) {
289                 PRINTMSG("ERROR: could not set evas engine info!\n");
290                 evas_free(canvas);
291                 return NULL;
292         }
293
294         return canvas;
295 }
296
297 static void destroy_canvas(Evas* canvas)
298 {
299         Evas_Engine_Info_Buffer *einfo;
300
301         einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
302         if (unlikely(einfo == NULL))
303         {
304                 //fputs("ERROR: could not get evas engine info!\n", stderr);
305                 evas_free(canvas);
306                 return;
307         }
308
309         free(einfo->info.dest_buffer);
310         evas_free(canvas);
311 }
312
313 int captureScreen()
314 {
315         char dstpath[MAX_PATH_LENGTH];
316         char* scrimage;
317         int width, height;
318         Evas* ev = NULL;
319         Evas_Object* img;
320         screenshot_data sdata;
321         probeInfo_t     probeInfo;
322         int ret = 0;
323         static pthread_mutex_t captureScreenLock = PTHREAD_MUTEX_INITIALIZER;
324
325         pthread_mutex_lock(&captureScreenLock);
326
327         probeBlockStart();
328
329         setProbePoint(&probeInfo);
330         sdata.ximage = NULL;
331         scrimage = captureScreenShotX(&width, &height, &sdata);
332         if(scrimage != NULL)
333         {
334                 ev = create_canvas(width, height);
335                 if(likely(ev != NULL))
336                 {
337                         snprintf(dstpath, sizeof(dstpath),
338                                  SCREENSHOT_DIRECTORY "/%d_%d.png", getpid(),
339                                  probeInfo.eventIndex);
340
341                         // make image buffer
342                         if((img = evas_object_image_add(ev)) != NULL)
343                         {
344                                 //image buffer set
345                                 evas_object_image_data_set(img, NULL);
346                                 evas_object_image_size_set(img, width, height);
347                                 evas_object_image_data_set(img, scrimage);
348
349                                 // resize image
350                                 if(height > MAX_HEIGHT)
351                                 {
352                                         width = width * MAX_HEIGHT / height;
353                                         height = MAX_HEIGHT;
354                                         evas_object_resize(img, width, height);
355                                         evas_object_image_fill_set(img, 0, 0, width, height);
356                                 }
357                                 evas_object_image_data_update_add(img, 0, 0, width, height);
358
359                                 //save file
360                                 if(evas_object_image_save(img, dstpath, NULL, "compress=5") != 0)
361                                 {
362                                         chmod(dstpath, 0777);
363
364                                         /* welcome to the hell */
365                                         log_t log;
366                                         PREPARE_LOCAL_BUF_THOUGH((char *)&log);
367
368                                         /* skip header */
369                                         LOCAL_BUF += offsetof(log_t, data);
370                                         /* pack screenshot name */
371                                         BUF_PTR = pack_string(LOCAL_BUF, dstpath); /* file name */
372                                         LOCAL_BUF = BUF_PTR;
373
374                                         /* pack probe */
375                                         PACK_COMMON_BEGIN(MSG_PROBE_SCREENSHOT, API_ID_captureScreen, "", 0);
376                                         PACK_COMMON_END('d', 0, 0, 0);
377                                         PACK_SCREENSHOT(dstpath, getOrientation());
378                                         SET_MSG_LEN();
379                                         log.length = GET_MSG_LEN() + MSG_LEN_OFFSET + strlen(dstpath) + 1;
380
381                                         /* send all message */
382                                         printLog(&log, MSG_IMAGE);
383                                 }
384                                 else
385                                 {
386                                         // captureScreen : evas_object_image_save failed
387                                         ret = -1;
388                                 }
389                         }
390                         else
391                         {
392                                 // captureScreen : evas_object_image_add failed
393                                 ret = -1;
394                         }
395                 }
396                 else
397                 {
398                         // captureScreen : create canvas failed
399                         ret = -1;
400                 }
401         }
402         else
403         {
404                 // captureScreen : captureScreenShotX failed
405                 ret = -1;
406         }
407
408         // release resources
409         releaseScreenShotX(&sdata);
410         if(ev)
411                 destroy_canvas(ev);
412
413         probeBlockEnd();
414
415         pthread_mutex_unlock(&captureScreenLock);
416         return ret;
417 }
418
419 int initialize_screencapture()
420 {
421         // remove all previous screenshot in dir
422 //      remove_indir(SCREENSHOT_DIRECTORY);
423
424         // make screenshot directory
425 //      mkdir(SCREENSHOT_DIRECTORY, 0777);
426
427         return 0;
428 }
429
430 int finalize_screencapture()
431 {
432         return 0;
433 }
434
435 // =======================================================================
436 // screen shot manipulation functions
437 // =======================================================================
438
439 static Eina_Bool _captureTimer(void __unused * data)
440 {
441         probeBlockStart();
442         SCREENSHOT_TIMEOUT();
443         probeBlockEnd();
444
445         return ECORE_CALLBACK_CANCEL;
446 }
447
448 int activateCaptureTimer()
449 {
450         ecore_timer_add(CAPTURE_TIMEOUT, _captureTimer, NULL);
451         return 0;
452 }
453
454 void _cb_render_post(void __unused * data, Evas __unused * e,
455                      void __unused * eventinfo)
456 {
457         probeBlockStart();
458         SCREENSHOT_DONE();
459         probeBlockEnd();
460 }