[X2Go-Commits] [x2gokdrive] 01/01: - automatically decrease the jpeg quality when to many frames in queue. - update the screen with png frames when no data is transmitted.

git-admin at x2go.org git-admin at x2go.org
Fri Oct 7 19:51:45 CEST 2022


This is an automated email from the git hooks/post-receive script.

x2go pushed a commit to branch master
in repository x2gokdrive.

commit e1107f47d77eab648efae39322483ead4b6023a3
Author: Oleksandr Shneyder <o.shneyder at phoca-gmbh.de>
Date:   Fri Oct 7 12:51:28 2022 -0500

      - automatically decrease the jpeg quality when to many frames in queue. - update the screen with png frames when no data is transmitted.
---
 debian/changelog   |   2 +
 x2gokdriveremote.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++-------
 x2gokdriveremote.h |  30 +++++++--
 3 files changed, 186 insertions(+), 30 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index eeabf70..997128b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -34,6 +34,8 @@ x2gokdrive (0.0.0.1-0x2go1) UNRELEASED; urgency=medium
     - sending KEYRELEASE immediately after KEYPRESS to avoid the "key sticking".
     - set initial geometry form the -geometry command line option.
     - change from alder32 to crc32 to avoid collisions on small frames.
+    - automatically decrease the jpeg quality when to many frames in queue.
+    - update the screen with png frames when no data is transmitted.
 
   [ Mihai Moldovan ]
   * Initial release:
diff --git a/x2gokdriveremote.c b/x2gokdriveremote.c
index 04c47ca..bd1f558 100644
--- a/x2gokdriveremote.c
+++ b/x2gokdriveremote.c
@@ -1518,7 +1518,7 @@ void remote_send_win_updates(char* updateBuf, uint32_t bufSize)
     *((uint32_t*)buffer)=WINUPDATE;
     *((uint32_t*)buffer+1)=bufSize;
 
-    write(remoteVars.clientsock,buffer,56);
+    l=write(remoteVars.clientsock,buffer,56);
 
     while(sent<bufSize)
     {
@@ -1682,6 +1682,10 @@ static
 void *send_frame_thread (void *threadid)
 {
     enum SelectionType r;
+    int dirty_region;
+    unsigned int ms_to_wait=100;
+    struct timespec ts;
+    struct timeval tp;
 
 #ifdef EPHYR_WANT_DEBUG
     debug_sendThreadId=pthread_self();
@@ -1710,12 +1714,45 @@ void *send_frame_thread (void *threadid)
         }
 
 
-
         if(!remoteVars.first_sendqueue_element && !remoteVars.firstCursor && !remoteVars.selstruct.firstOutputChunk &&
             !remoteVars.cache_rebuilt && !remoteVars.windowsUpdated)
         {
-            /* sleep if frame queue is empty */
-            pthread_cond_wait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex);
+            gettimeofday(&tp, NULL);
+            /* Convert from timeval to timespec */
+            ts.tv_sec  = tp.tv_sec;
+            ts.tv_nsec = tp.tv_usec * 1000+ms_to_wait*1000000UL;//wait ms_to_wait miliseconds
+            if(ts.tv_nsec>=1000000000UL)
+            {
+                ts.tv_nsec-=1000000000UL;
+                ++ts.tv_sec;
+            }
+            /*sleep with timeout till signal from other thread is sent*/
+            switch(pthread_cond_timedwait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex, &ts))
+            {
+                case 0: //have a signal from other thread, continue execution
+                    ms_to_wait=100; //reset timer
+                    break;
+                case ETIMEDOUT: //timeout is ocured, we have nothing else to do, let's see if we need to update some screen regions
+                    dirty_region=getDirtyScreenRegion();
+                    if(dirty_region!=-1)
+                    {
+                        send_dirty_region(dirty_region);
+                        ms_to_wait=1; //we can start to repaint faster till we don't have any new data incoming
+                    }
+                    else
+                    {
+                        /* sleep till we have a signal from another thread if
+                         *frame, cursor ,selection queue is empty and all regions are updated*/
+                        ms_to_wait=100; //reset timer
+                        pthread_cond_wait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex);
+                    }
+                    break;
+                default:
+                    EPHYR_DBG("Error is occured in pthread_cond_timedwait");
+                    ms_to_wait=100; //reset timer
+                    break;
+            }
+
         }
 
         /* mutex is locked on this point */
@@ -1817,7 +1854,17 @@ void *send_frame_thread (void *threadid)
             {
                 remoteVars.maxfr=elems;
             }
-            //                EPHYR_DBG("have %d max frames in queue, current %d", remoteVars.,elems);
+//             EPHYR_DBG(" frames in queue %d, quality %d", elems, remoteVars.jpegQuality);
+            if(elems > 3)
+            {
+                if(remoteVars.jpegQuality >10)
+                    remoteVars.jpegQuality-=10;
+            }
+            if(elems <3)
+            {
+                if(remoteVars.jpegQuality <remoteVars.initialJpegQuality)
+                    remoteVars.jpegQuality+=10;
+            }
             frame=remoteVars.first_sendqueue_element->frame;
 
             /* delete first element from frame queue */
@@ -1845,18 +1892,17 @@ void *send_frame_thread (void *threadid)
 
                 /* unlock sendqueue for main thread */
 
+                markDirtyRegions(x, y, frame_width, frame_height, remoteVars.jpegQuality, winId);
                 pthread_mutex_unlock(&remoteVars.sendqueue_mutex);
                 send_frame(frame_width, frame_height, x, y, crc, frame->regions, winId);
             }
             else
             {
 //                 EPHYR_DBG("Sending main image or screen update");
-
+                markDirtyRegions(x, y, width, height, remoteVars.jpegQuality, winId);
                 pthread_mutex_unlock(&remoteVars.sendqueue_mutex);
                 sendMainImageFromSendThread(width, height, x, y, winId);
             }
-
-
             pthread_mutex_lock(&remoteVars.sendqueue_mutex);
             if(frame)
             {
@@ -1877,30 +1923,23 @@ void *send_frame_thread (void *threadid)
                     frame->regions[i].rect.size.width=0;
                 }
             }
-
             if(remoteVars.cache_size>CACHEMAXELEMENTS)
             {
                 clear_frame_cache(CACHEMAXELEMENTS);
             }
-
             if(remoteVars.first_deleted_elements)
             {
                 send_deleted_elements();
             }
-
             if(remoteVars.first_deleted_cursor)
             {
                 send_deleted_cursors();
             }
-
-
             pthread_mutex_unlock(&remoteVars.sendqueue_mutex);
             remoteVars.framenum++;
         }
         else
         {
-
-
             pthread_mutex_unlock(&remoteVars.sendqueue_mutex);
         }
     }
@@ -3146,6 +3185,8 @@ void terminateServer(int exitStatus)
     {
         free(remoteVars.main_img);
         free(remoteVars.second_buffer);
+        EPHYR_DBG("free screen regions");
+        free(remoteVars.screen_regions);
     }
 
 
@@ -3188,7 +3229,14 @@ void processConfigFileSetting(char* key, char* value)
                 remoteVars.compression=JPEG;
                 EPHYR_DBG("Using JPEG Compression");
             }
-            remoteVars.jpegQuality=(quality-'0')*10+9;
+            remoteVars.initialJpegQuality=(quality-'0')*10+9;
+            if(remoteVars.initialJpegQuality > JPG_QUALITY)
+            {
+                //x2goclient can set by default quality 90, but it doesn't really makes sence, Maybe we could think about overreiding it in the future
+                EPHYR_DBG("JPEG quality %d is requested, x2gokdrive will override it to %d",remoteVars.initialJpegQuality, JPG_QUALITY);
+                remoteVars.initialJpegQuality=JPG_QUALITY;
+            }
+            remoteVars.jpegQuality=remoteVars.initialJpegQuality;
             EPHYR_DBG("Image quality: %d", remoteVars.jpegQuality);
         }
     }
@@ -3283,18 +3331,17 @@ void readOptionsFromFile(void)
 int
 remote_init(void)
 {
-
-    EPHYR_DBG("Setting initial arguments");
     char* displayVar = NULL;
 
     /*init it in OsInit*/
+    EPHYR_DBG("Setting initial arguments");
 
     fclose(stdout);
     fclose(stdin);
 
     remoteVars.serversock=-1;
 
-    remoteVars.jpegQuality=JPG_QUALITY;
+    remoteVars.initialJpegQuality=remoteVars.jpegQuality=JPG_QUALITY;
     remoteVars.compression=DEFAULT_COMPRESSION;
     remoteVars.selstruct.selectionMode = CLIP_BOTH;
     if(!strlen(remote_get_init_geometry()))
@@ -4531,12 +4578,12 @@ uint32_t calculate_crc(uint32_t width, uint32_t height, int32_t dx, int32_t dy)
     return crc;
 }
 
-const char* remote_get_init_geometry()
+const char* remote_get_init_geometry(void)
 {
     return remoteVars.initGeometry;
 }
 
-void remote_set_init_geometry(char* geometry)
+void remote_set_init_geometry ( const char* geometry )
 {
     if(strlen(geometry)>128)
     {
@@ -4598,6 +4645,7 @@ remote_screen_init(KdScreenInfo *screen,
     if(remoteVars.main_img)
     {
         free(remoteVars.main_img);
+        free(remoteVars.screen_regions);
 
         EPHYR_DBG("FREE DBF");
         free(remoteVars.second_buffer);
@@ -4608,8 +4656,15 @@ remote_screen_init(KdScreenInfo *screen,
     EPHYR_DBG("TRYING TO ALLOC  DOUBLE BUF %d", width*height*XSERVERBPP);
     remoteVars.second_buffer=malloc(width*height*XSERVERBPP);
 
-    memset(remoteVars.main_img,0, width*height*XSERVERBPP);
-    memset(remoteVars.second_buffer,0, width*height*XSERVERBPP);
+    remoteVars.reg_horiz=width/SCREEN_REG_WIDTH;
+    if(width%SCREEN_REG_WIDTH)
+        ++remoteVars.reg_horiz;
+    remoteVars.reg_vert=height/SCREEN_REG_HEIGHT;
+    if(height%SCREEN_REG_HEIGHT)
+        ++remoteVars.reg_vert;
+    EPHYR_DBG("Initializing %dx%d screen regions", remoteVars.reg_horiz, remoteVars.reg_vert);
+    remoteVars.screen_regions=malloc(remoteVars.reg_horiz*remoteVars.reg_vert*sizeof(screen_region));
+
     EPHYR_DBG("ALL INITIALIZED");
 
     if(!remoteVars.main_img)
@@ -4623,6 +4678,16 @@ remote_screen_init(KdScreenInfo *screen,
         exit(-1);
     }
 
+    if(!remoteVars.second_buffer)
+    {
+        EPHYR_DBG("failed to init screen regions");
+        exit(-1);
+    }
+
+    memset(remoteVars.screen_regions, 0, remoteVars.reg_horiz*remoteVars.reg_vert*sizeof(screen_region));
+    memset(remoteVars.main_img,0, width*height*XSERVERBPP);
+    memset(remoteVars.second_buffer,0, width*height*XSERVERBPP);
+
     remoteVars.main_img_width=width;
     remoteVars.main_img_height=height;
 
@@ -4655,3 +4720,76 @@ void rebuild_caches(void)
     pthread_cond_signal(&remoteVars.have_sendqueue_cond);
     pthread_mutex_unlock(&remoteVars.sendqueue_mutex);
 }
+
+void markDirtyRegions(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint8_t jpegQuality, uint32_t winId)
+{
+    int first_horiz, last_horiz;
+    int first_vert, last_vert;
+    int i,j;
+// #warning for debugging
+//     int marked=0;
+    first_horiz=x/SCREEN_REG_WIDTH;
+    first_vert=y/SCREEN_REG_HEIGHT;
+    last_horiz=(x+width)/SCREEN_REG_WIDTH-1;
+    last_vert=(y+height)/SCREEN_REG_HEIGHT-1;
+    if((x+width)%SCREEN_REG_WIDTH)
+        ++last_horiz;
+    if((y+height)%SCREEN_REG_HEIGHT)
+        ++last_vert;
+//     EPHYR_DBG("marking regions at %d,%d for %dx%d, first %dx%d, last %dx%d", x,y,width, height, first_horiz, first_vert, last_horiz, last_vert);
+    for(i=first_vert;i<=last_vert;++i)
+        for(j=first_horiz;j<=last_horiz;++j)
+        {
+//             ++marked;
+            if((remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality == 0)||(remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality>jpegQuality))
+                remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality=jpegQuality;
+            remoteVars.screen_regions[i*remoteVars.reg_horiz+j].winId=winId;
+        }
+//     EPHYR_DBG("Marked %d regions",marked);
+}
+
+int getDirtyScreenRegion(void)
+{
+    int i;
+    int worst_reg=-1;
+    for(i=0;i<remoteVars.reg_horiz*remoteVars.reg_vert;++i)
+    {
+        if(remoteVars.screen_regions[i].quality)
+        {
+            if((worst_reg == -1)||(remoteVars.screen_regions[worst_reg].quality>remoteVars.screen_regions[i].quality))
+            {
+                worst_reg=i;
+            }
+        }
+    }
+    return worst_reg;
+}
+
+void send_dirty_region(int index)
+{
+    //remoteVars.sendqueue_mutex is locked
+    int width, height, x, y, winId;
+    unsigned char compression;
+    if(index==-1)
+        return;
+    x=(index%remoteVars.reg_horiz)*SCREEN_REG_WIDTH;
+    y=(index/remoteVars.reg_horiz)*SCREEN_REG_HEIGHT;
+    if(x+SCREEN_REG_WIDTH > remoteVars.main_img_width)
+        width=remoteVars.main_img_width-x;
+    else
+        width=SCREEN_REG_WIDTH;
+    if(y+SCREEN_REG_HEIGHT > remoteVars.main_img_height)
+        height=remoteVars.main_img_height-y;
+    else
+        height=SCREEN_REG_HEIGHT;
+
+    winId=remoteVars.screen_regions[index].winId;
+    remoteVars.screen_regions[index].quality=0;
+    pthread_mutex_unlock(&remoteVars.sendqueue_mutex);
+//     EPHYR_DBG("SEND REGION UPDATE %d,%d %dx%d", x,y,width,height);
+    compression=remoteVars.compression;
+    remoteVars.compression=PNG;
+    sendMainImageFromSendThread(width, height, x, y, winId);
+    remoteVars.compression=compression;
+    pthread_mutex_lock(&remoteVars.sendqueue_mutex);
+}
diff --git a/x2gokdriveremote.h b/x2gokdriveremote.h
index c10e86c..a5d4580 100644
--- a/x2gokdriveremote.h
+++ b/x2gokdriveremote.h
@@ -116,9 +116,7 @@
 //it define how close should be two pages to search common regions (see find_best_match)
 #define MAX_MATCH_VAL 51
 
-#define JPG_QUALITY 80
-
-
+#define JPG_QUALITY 70
 
 //always 4
 #define XSERVERBPP 4
@@ -171,6 +169,18 @@ enum WinState{WIN_UNCHANGED, WIN_DELETED, WIN_ICONIFIED};
 
 #define EVLENGTH 41
 
+//width of screen region
+#define SCREEN_REG_WIDTH 40
+
+//height of screen region
+#define SCREEN_REG_HEIGHT 40
+
+//represents the screen regions for updates
+typedef struct
+{
+    uint8_t quality;
+    uint32_t winId;
+} screen_region;
 
 typedef struct
 {
@@ -395,7 +405,7 @@ struct _remoteHostVars
     char displayName[256];
     char initGeometry[128];
     int listenPort;
-    int jpegQuality;
+    int jpegQuality, initialJpegQuality;
     uint32_t framenum;
     uint32_t framenum_sent;
     uint32_t eventnum;
@@ -428,6 +438,10 @@ struct _remoteHostVars
     int clientsock, serversock;
     BOOL rootless;
 
+    //array of screen regions
+    screen_region* screen_regions;
+    int reg_horiz, reg_vert;
+
 
     struct cache_elem* first_cache_element;
     struct cache_elem* last_cache_element;
@@ -556,8 +570,8 @@ remote_paint_rect(KdScreenInfo *screen,
 void request_selection_from_client(enum SelectionType selection);
 void rebuild_caches(void);
 void remote_set_rootless(void);
-void remote_set_init_geometry(char* geometry);
-const char*  remote_get_init_geometry();
+void remote_set_init_geometry(const char* geometry);
+const char*  remote_get_init_geometry(void);
 void remote_check_windowstree(WindowPtr root);
 void remote_check_window(WindowPtr win);
 struct remoteWindow* remote_find_window(WindowPtr win);
@@ -569,5 +583,7 @@ void client_win_change(char* buff);
 void client_win_close(uint32_t winId);
 void client_win_iconify(uint32_t winId);
 void remote_check_rootless_windows_for_updates(KdScreenInfo *screen);
-
+void markDirtyRegions(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint8_t jpegQuality, uint32_t winId);
+int getDirtyScreenRegion(void);
+void send_dirty_region(int index);
 #endif /* X2GOKDRIVE_REMOTE_H */

--
Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2gokdrive.git


More information about the x2go-commits mailing list