source: trunk/src/testing/app/qshare/capturewindow.cpp @ 4

Revision 4, 14.3 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1#include "capturewindow.h"
2
3#if defined(__linux__)
4
5#include <X11/Xutil.h>
6#include <sys/shm.h>
7#include <X11/extensions/XShm.h>
8#include <X11/extensions/Xfixes.h>
9
10struct x11_grab
11{
12    int frame_size;          /* Size in bytes of a grabbed frame */
13    int height;              /* Height of the grab frame */
14    int width;               /* Width of the grab frame */
15    int x_off;               /* Horizontal top-left corner coordinate */
16    int y_off;               /* Vertical top-left corner coordinate */
17
18    Display *dpy;            /* X11 display from which x11grab grabs frames */
19    XImage *image;           /* X11 image holding the grab */
20    int use_shm;             /* !0 when using XShm extension */
21    XShmSegmentInfo shminfo; /* When using XShm, keeps track of XShm infos */
22    int nomouse;
23};
24
25struct x11_grab *x11grab;
26
27#endif
28
29#if defined(WIN32)
30HWND    hDesktopWnd;
31HDC     hDesktopDC;
32HDC     hCaptureDC;
33HBITMAP hCaptureBitmap;
34void*   pBits = NULL;
35#endif
36
37// headers for SAGE
38#include "sail.h"
39#include "misc.h"
40
41// Compression
42#include "libdxt.h"
43
44// headers for SAGE
45GLubyte *rgbBuffer = NULL;
46GLubyte *dxtBuffer = NULL;
47sail sageInf;
48sailConfig scfg;
49
50
51CaptureWindow::CaptureWindow(QWidget *parent) :
52        QMainWindow(parent)
53{
54    dxt_aInitialize();
55
56    // Build the UI
57    ui.setupUi(this);
58    ui.statusBar->showMessage(QString("Desktop capture"), 0);
59
60        // Disable DXT for now
61        ui.checkBox->setEnabled(false);
62
63    // Get dimensions
64    QDesktopWidget *desktop = QApplication::desktop();
65    WW = desktop->width();
66    HH = desktop->height();
67    sage::printLog("QSHARE> Desktop width %d height %d", WW, HH);
68
69    // Set private variable
70    fps = 25;
71    started = false;
72    dxt = false;
73    count = 0;
74    showcursor = true;
75
76#if defined(__APPLE__)
77    /////////////////////////
78    // Get the OpenGL context
79    CGLPixelFormatObj pixelFormatObj ;
80    GLint numPixelFormats ;
81    CGDirectDisplayID displayId = CGMainDisplayID();
82    CGRect dRect = CGDisplayBounds( displayId );
83    WW = dRect.size.width;
84    HH = dRect.size.height;
85    CGOpenGLDisplayMask displayMask = CGDisplayIDToOpenGLDisplayMask(displayId);
86
87    CGLPixelFormatAttribute attribs[] =
88    {
89        (CGLPixelFormatAttribute)kCGLPFAFullScreen,
90        (CGLPixelFormatAttribute)kCGLPFADisplayMask,
91        (CGLPixelFormatAttribute)displayMask,
92        (CGLPixelFormatAttribute)0
93    };
94    CGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats );
95    CGLCreateContext( pixelFormatObj, NULL, &glContextObj ) ;
96    CGLDestroyPixelFormat( pixelFormatObj ) ;
97    CGLSetCurrentContext( glContextObj ) ;
98    glReadBuffer(GL_FRONT);
99    CGLSetFullScreen( glContextObj ) ;///UUUUUUUUUUnbelievable
100    CGLSetCurrentContext( NULL );
101    qDebug() << "W " << WW << "  H" << HH;
102    /////////////////////////
103#endif
104
105#if defined(__linux__)
106    //
107    // Initialize x11 frame grabber
108    //
109    Display *dpy;
110    XImage *image;
111    int use_shm;
112
113    x11grab = (struct x11_grab*)malloc(sizeof(struct x11_grab));
114    memset(x11grab, 0, sizeof(struct x11_grab));
115
116    dpy = XOpenDisplay(0);
117    if(!dpy) {
118        sage::printLog("QSHARE> Could not open X display");
119    }
120 
121    use_shm = XShmQueryExtension(dpy);
122    sage::printLog("QSHARE> shared memory extension %s found", use_shm ? "" : "not");
123
124    if(use_shm) {
125        int scr = XDefaultScreen(dpy);
126        image = XShmCreateImage(dpy,
127                                DefaultVisual(dpy, scr),
128                                DefaultDepth(dpy, scr),
129                                ZPixmap,
130                                NULL,
131                                &x11grab->shminfo,
132                                WW, HH);
133        sage::printLog("QSHARE> Image: widht %d  height %d bytes_per_line %d, depth %d", image->width,image->height,image->bytes_per_line, DefaultDepth(dpy, scr));
134        x11grab->shminfo.shmid = shmget(IPC_PRIVATE,
135                                        image->bytes_per_line * image->height,
136                                        IPC_CREAT|0777);
137        if (x11grab->shminfo.shmid == -1) {
138            sage::printLog("QSHARE> Fatal: Can't get shared memory!");
139        }
140        x11grab->shminfo.shmaddr = image->data = (char*)shmat(x11grab->shminfo.shmid, 0, 0);
141        x11grab->shminfo.readOnly = False;
142
143        if (!XShmAttach(dpy, &x11grab->shminfo)) {
144            sage::printLog("QSHARE> Fatal: Failed to attach shared memory!");
145        }
146    } else {
147        image = XGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)),
148                          0, 0, WW, HH,
149                          AllPlanes, ZPixmap);
150    }
151
152    switch (image->bits_per_pixel) {
153    case 8:
154        sage::printLog("QSHARE> 8 bit palette");
155        //input_pixfmt = PIX_FMT_PAL8;
156        break;
157    case 16:
158        if (       image->red_mask   == 0xf800 &&
159                   image->green_mask == 0x07e0 &&
160                   image->blue_mask  == 0x001f ) {
161            sage::printLog("QSHARE> 16 bit RGB565");
162            //input_pixfmt = PIX_FMT_RGB565;
163        } else if (image->red_mask   == 0x7c00 &&
164                   image->green_mask == 0x03e0 &&
165                   image->blue_mask  == 0x001f ) {
166            sage::printLog("QSHARE> 16 bit RGB555");
167            //input_pixfmt = PIX_FMT_RGB555;
168        } else {
169            sage::printLog("QSHARE> RGB ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
170            sage::printLog("QSHARE> color masks: r 0x%.6lx g 0x%.6lx b 0x%.6lx\n", image->red_mask, image->green_mask, image->blue_mask);
171        }
172        break;
173    case 24:
174        if (        image->red_mask   == 0xff0000 &&
175                    image->green_mask == 0x00ff00 &&
176                    image->blue_mask  == 0x0000ff ) {
177            sage::printLog("QSHARE> 24 bit BGR24");
178            //input_pixfmt = PIX_FMT_BGR24;
179        } else if ( image->red_mask   == 0x0000ff &&
180                    image->green_mask == 0x00ff00 &&
181                    image->blue_mask  == 0xff0000 ) {
182            sage::printLog("QSHARE> 24 bit RGB24");
183            //input_pixfmt = PIX_FMT_RGB24;
184       } else {
185            sage::printLog("QSHARE> rgb ordering at image depth %i not supported ... aborting", image->bits_per_pixel);
186            sage::printLog("QSHARE> color masks: r 0x%.6lx g 0x%.6lx b 0x%.6lx", image->red_mask, image->green_mask, image->blue_mask);
187        }
188        break;
189    case 32:
190        sage::printLog("QSHARE> 32 bit RGB32");
191        //input_pixfmt = PIX_FMT_RGB32;
192        break;
193    default:
194        sage::printLog("QSHARE> image depth %i not supported ... aborting", image->bits_per_pixel);
195    }
196    x11grab->nomouse = 1;
197    x11grab->frame_size = WW * HH * image->bits_per_pixel/8;
198    x11grab->dpy = dpy;
199    x11grab->width = WW;
200    x11grab->height = HH;
201    x11grab->x_off = 0;
202    x11grab->y_off = 0;
203    x11grab->image = image;
204    x11grab->use_shm = use_shm;   
205#endif
206
207#if defined(WIN32)
208    BITMAPINFO  bmpInfo;
209    ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
210    bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
211    bmpInfo.bmiHeader.biBitCount=24;//BITSPERPIXEL;
212    bmpInfo.bmiHeader.biCompression = BI_RGB;
213    bmpInfo.bmiHeader.biWidth=WW;
214    bmpInfo.bmiHeader.biHeight=HH;
215    bmpInfo.bmiHeader.biPlanes=1;
216    bmpInfo.bmiHeader.biSizeImage=abs(bmpInfo.bmiHeader.biHeight)*bmpInfo.bmiHeader.biWidth*bmpInfo.bmiHeader.biBitCount/8;
217
218    hDesktopWnd = GetDesktopWindow();
219    hDesktopDC = GetDC(hDesktopWnd);
220    hCaptureDC = CreateCompatibleDC(hDesktopDC);
221    hCaptureBitmap = CreateDIBSection(hDesktopDC,&bmpInfo,DIB_RGB_COLORS,&pBits,NULL,0);
222    SelectObject(hCaptureDC,hCaptureBitmap);
223#endif
224
225    // Enables buttons
226    ui.pushButton->setEnabled(true);
227    ui.pushButton_2->setEnabled(false);
228    ui.pushButton_3->setEnabled(false);
229
230    // Load the pointer
231    cursor_icon = new QImage("arrow2.png");
232
233    // Load SAIL config
234    scfg.init((char*)"qshare.conf");
235    scfg.setAppName((char*)"qshare");
236
237    fsip = QString(scfg.fsIP);
238    qDebug() << "FSIP " << fsip;
239    ui.lineEdit->setText(fsip);
240
241    // Timer setup
242    timer = new QTimer(this);
243    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
244}
245
246void CaptureWindow::closeEvent(QCloseEvent *event)
247{
248#if defined(__linux__)
249    //
250    // Close x11 frame grabber
251    //
252               
253    // Detach cleanly from shared mem
254    // if (x11grab && x11grab->use_shm) {
255    //  XShmDetach(x11grab->dpy, &x11grab->shminfo);
256    //  shmdt(x11grab->shminfo.shmaddr);
257    //  shmctl(x11grab->shminfo.shmid, IPC_RMID, NULL);
258    // }
259               
260    // Destroy X11 image
261    // if (x11grab && x11grab->image) {
262    //  XDestroyImage(x11grab->image);
263    //  x11grab->image = NULL;
264    // }
265               
266    // Free X11 display
267    // if (x11grab)
268    //  XCloseDisplay(x11grab->dpy);
269#endif
270    onStop();
271    event->accept();
272}
273
274void CaptureWindow::frameRate(int f)
275{
276    fps = f;
277    qDebug() << "framerate " << fps;
278    timer->setInterval(1000/fps);
279}
280
281
282void CaptureWindow::fsIP(QString f)
283{
284    fsip = f;
285    qDebug() << "FSIP changed" << fsip;
286}
287
288void CaptureWindow::update()
289{
290    if (started) {
291
292        // Capture the desktop pixels
293        capture((char*)rgbBuffer,0,0,WW,HH);
294
295        if (showcursor) {
296            // Get mouse position
297            QPoint pt = QCursor::pos();
298
299            // Flip the Y value
300            int adjust = HH - pt.y();
301            if (adjust < 0) adjust = 0;
302            pt.setY(adjust);
303           
304            // Compute boundaries
305            int startx = MAX(0,pt.x());
306            // int starty = MAX(0, pt.y()-cursor_icon->height());
307            int starty = pt.y()-cursor_icon->height();
308           
309            // Compose desktop with cursor
310            QImage resultImage = QImage((uchar*)rgbBuffer, WW, HH, QImage::Format_RGB888);
311            QPainter painter(&resultImage);
312            painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
313            painter.drawImage(startx, starty, *cursor_icon);
314            painter.end();
315            // rgbBuffer is filled after that point
316        }
317
318        if (dxt)
319        {
320            CompressDXT(rgbBuffer, dxtBuffer, WW, HH, FORMAT_DXT1, 1);
321            sageInf.swapBuffer();
322            dxtBuffer = (GLubyte *)sageInf.getBuffer();
323        }
324        else
325        {
326            sageInf.swapBuffer();
327            rgbBuffer = (GLubyte *)sageInf.getBuffer();
328        }
329
330        sageMessage msg;
331        if (sageInf.checkMsg(msg, false) > 0) {
332            switch (msg.getCode()) {
333            case APP_QUIT:
334                exit(1);
335                break;
336            }
337        }
338
339
340        QString str;
341        double nowt = dxt_aTime();
342        //qDebug() << "now " << nowt << "   startt" << startt;
343        double dfps = 1.0 / (nowt - startt);
344        str = QString("%1 ms / %2 fps/ # %3 / DXT %4 / %5x%6").arg(nowt-startt,5,'f',1).arg(dfps,5,'f',1).arg(count++).arg(dxt).arg(WW).arg(HH);
345        ui.statusBar->showMessage( str, 0 );
346
347#if 1
348        if (dfps < fps) {
349            timer->start( MAX(0, (2*(1000/fps)-(1000/dfps) ) ) );
350        }
351        else
352            timer->start(1000/fps);
353#else
354        timer->start(0);
355#endif
356        startt = nowt;
357    }
358}
359
360void CaptureWindow::capture(char* m_pFrameRGB,int x,int y,int cx,int cy)
361{
362#if defined(__APPLE__)
363    CGLSetCurrentContext( glContextObj ) ;
364    //CGLSetFullScreen( glContextObj ) ;///UUUUUUUUUUnbelievable
365    //glReadBuffer(GL_FRONT);
366
367    if (dxt)
368        glReadPixels(x,y,cx,cy,GL_RGBA,GL_UNSIGNED_BYTE,m_pFrameRGB);
369    else
370        glReadPixels(x,y,cx,cy,GL_RGB,GL_UNSIGNED_BYTE,m_pFrameRGB);
371
372    CGLSetCurrentContext( NULL );
373#endif
374
375#if defined(__linux__)
376    if (x11grab->use_shm) {
377        if (!XShmGetImage(x11grab->dpy, RootWindow(x11grab->dpy, DefaultScreen(x11grab->dpy)),
378                          x11grab->image, 0, 0, AllPlanes)) {
379            sage::printLog("QSHARE> XShmGetImage() failed");
380        }
381        else {
382            // Upside-down and RGBA-to-RGB conversion
383            for (int i = 0 ; i < cy; i++) {
384                for (int j = 0 ; j < cx; j++) {
385                    m_pFrameRGB [ (i*cx+j) * 3 + 0 ] = x11grab->image->data [ ((cy-i-1)*cx+j) * 4 + 2 ];
386                    m_pFrameRGB [ (i*cx+j) * 3 + 1 ] = x11grab->image->data [ ((cy-i-1)*cx+j) * 4 + 1 ];
387                    m_pFrameRGB [ (i*cx+j) * 3 + 2 ] = x11grab->image->data [ ((cy-i-1)*cx+j) * 4 + 0 ];
388                }
389            }
390        }
391    }
392#endif
393
394#if defined(WIN32)
395        BitBlt(hCaptureDC,0,0,WW,HH,hDesktopDC,0,0,SRCCOPY|CAPTUREBLT);
396        memcpy(m_pFrameRGB, pBits, WW*HH*3);
397#endif
398}
399
400void CaptureWindow::onStart()
401{
402    if (! started) {
403        ui.pushButton->setEnabled(false);
404        ui.pushButton_2->setEnabled(true);
405        ui.pushButton_3->setEnabled(true);
406        ui.lineEdit->setEnabled(false);
407        ui.spinBox->setEnabled(true);
408        ui.checkBox->setEnabled(false);
409
410        qDebug() << "On Start";
411
412        sageRect ishareImageMap;
413        ishareImageMap.left = 0.0;
414        ishareImageMap.right = 1.0;
415        ishareImageMap.bottom = 0.0;
416        ishareImageMap.top = 1.0;
417
418        scfg.rank = 0;
419        scfg.resX = WW;
420        scfg.resY = HH;
421        scfg.winWidth  = WW;
422        scfg.winHeight = HH;
423        scfg.imageMap = ishareImageMap;
424       
425        // Copy back the text box into the SAGE variable
426        memset(scfg.fsIP, 0, SAGE_IP_LEN);
427        strncpy(scfg.fsIP, fsip.toAscii().constData(), SAGE_IP_LEN);
428
429        if (dxt)
430            scfg.pixFmt = PIXFMT_DXT;
431        else
432#if defined(WIN32)
433                        scfg.pixFmt = PIXFMT_888_INV; // for some reasons, win32 is BGR
434#else
435                        scfg.pixFmt = PIXFMT_888;
436#endif
437
438        scfg.rowOrd = BOTTOM_TO_TOP;
439        scfg.master = true;
440
441        sageInf.init(scfg);
442
443        if (dxt) {
444            dxtBuffer = (GLubyte *)sageInf.getBuffer();
445            if (rgbBuffer) delete [] rgbBuffer;
446            rgbBuffer = (byte*)memalign(16, WW*HH*4);
447            memset(rgbBuffer, 0,  WW*HH*4);
448        }
449        else {
450            rgbBuffer = (GLubyte *)sageInf.getBuffer();
451        }
452
453
454        started = true;
455        timer->setSingleShot(true);
456        timer->start(1000/fps);
457        //timer->start();
458
459        startt = dxt_aTime();
460    }
461}
462
463void CaptureWindow::compression(int c)
464{
465    dxt = c;
466}
467
468void CaptureWindow::cursor(int c)
469{
470    showcursor = c;
471}
472
473void CaptureWindow::onStop()
474{
475    qDebug() << "On Stop";
476    started = false;
477    timer->stop();
478    ui.pushButton->setEnabled(true);
479    ui.pushButton_2->setEnabled(false);
480    ui.pushButton_3->setEnabled(false);
481    ui.lineEdit->setEnabled(true);
482    ui.spinBox->setEnabled(true);
483    ui.checkBox->setEnabled(true);
484    sageInf.shutdown();
485}
486
487void CaptureWindow::onPause()
488{
489    if (started) {
490        qDebug() << "Pause";
491        started = false;
492        timer->stop();
493    }
494    else {
495        qDebug() << "UnPause";
496        started = true;
497        timer->start(1000/fps);
498    }
499}
500
501
502/////////////////////////////////////////////////////////////////////////
503
Note: See TracBrowser for help on using the repository browser.