[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