vnc-server.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,754 行 · 第 1/4 页
C
1,754 行
/*****************************************************************************//** Frame update thread. * * @param data Ignored * * This thread handles the sending of all frame update data to the client and * sends the 'ring bell' message to the client when required. * *****************************************************************************/#ifdef CYGPKG_NETvoid frame_update(cyg_addrword_t data)#elsestatic void frame_update(void *data)#endif{ int i, j; int x_pos, y_pos; int packet_length; int num_updated_tiles; cyg_uint16 *ptr_to_uint16; static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; /* These are declared static so they don't use thread stack memory */ static cyg_uint8 FramebufferUpdate_msg[4 + 12 + TILE_SIZE*TILE_SIZE*BITS_PER_PIXEL/8 + 1460]; static int FrameBufferPtr; /* Pointer to next space in buffer */ static int tile_updated_local[NUM_TILES_Y_AXIS][NUM_TILES_X_AXIS]; while(1) { /* Wait until client sends a frame update request */ wait_for_client: cyg_mutex_lock(&client_active_lock); /* Lock the mutex */ while( update_req == 0 ) /* Wait until the client is active */ { cyg_cond_wait(&client_active_wait); } cyg_mutex_unlock(&client_active_lock); /* Copy tile_updated array to local version and clear copied tiles */ cyg_scheduler_lock(); num_updated_tiles = 0; for (i = 0; i < NUM_TILES_Y_AXIS; i++) { for (j = 0; j < NUM_TILES_X_AXIS; j++) { if (tile_updated[i][j]) { tile_updated_local[i][j] = 1; tile_updated[i][j] = 0; num_updated_tiles++; /* Keep count of the updated tiles */ } } } cyg_scheduler_unlock(); if (num_updated_tiles) { /* Fill in constant parts of FramebufferUpdate Message */ FramebufferUpdate_msg[0] = 0; /* Message-type */ FramebufferUpdate_msg[1] = 0; /* Padding */ ptr_to_uint16 = (cyg_uint16 *) &(FramebufferUpdate_msg[2]); *ptr_to_uint16 = htons(num_updated_tiles); /* Number-of-rectangles */ FrameBufferPtr = 4; for (y_pos = 0; y_pos < NUM_TILES_Y_AXIS; y_pos++) { for (x_pos = 0; x_pos < NUM_TILES_X_AXIS; x_pos++) { if (tile_updated_local[y_pos][x_pos]) { if (update_req) { cyg_mutex_lock(&client_active_lock); /* Lock the mutex */ update_req = 0; /* Cancel the update request flag */ cyg_mutex_unlock(&client_active_lock); /* Unlock the mutex */ } /* Send current square data to client */ /* x-position */ FramebufferUpdate_msg[FrameBufferPtr+0] = (x_pos * TILE_SIZE) / 256; FramebufferUpdate_msg[FrameBufferPtr+1] = (x_pos * TILE_SIZE) % 256; /* y-position */ FramebufferUpdate_msg[FrameBufferPtr+2] = (y_pos * TILE_SIZE) / 256; FramebufferUpdate_msg[FrameBufferPtr+3] = (y_pos * TILE_SIZE) % 256; /* Set width of tile in packet */ if (x_pos == (NUM_TILES_X_AXIS -1)) { /* Last tile in X-axis */ FramebufferUpdate_msg[FrameBufferPtr+4] = LAST_TILE_WIDTH / 256; FramebufferUpdate_msg[FrameBufferPtr+5] = LAST_TILE_WIDTH % 256; } else { FramebufferUpdate_msg[FrameBufferPtr+4] = TILE_SIZE / 256; FramebufferUpdate_msg[FrameBufferPtr+5] = TILE_SIZE % 256; } if (y_pos == (NUM_TILES_Y_AXIS -1)) { /* Last tile in Y-axis */ FramebufferUpdate_msg[FrameBufferPtr+6] = LAST_TILE_HEIGHT / 256; FramebufferUpdate_msg[FrameBufferPtr+7] = LAST_TILE_HEIGHT % 256; } else { FramebufferUpdate_msg[FrameBufferPtr+6] = TILE_SIZE / 256; FramebufferUpdate_msg[FrameBufferPtr+7] = TILE_SIZE % 256; } /* Generate the packet data for this tile */ packet_length = GenTileUpdateData(&(FramebufferUpdate_msg[FrameBufferPtr])); /* Send the packet data for this tile to the client */ FrameBufferPtr += packet_length; if (FrameBufferPtr > 1460) { /* Send the data to the client */ if (send(client_sock, FramebufferUpdate_msg, FrameBufferPtr, 0) != FrameBufferPtr) { goto wait_for_client; } FrameBufferPtr = 0; } tile_updated_local[y_pos][x_pos] = 0; /* Clear the update bit for this square */ } } } if (FrameBufferPtr > 0) { /* Last data for this update, send it to the client */ if (send(client_sock, FramebufferUpdate_msg, FrameBufferPtr, 0) != FrameBufferPtr) { goto wait_for_client; } FrameBufferPtr = 0; } } else /* if (num_updated_tiles) */ { /* There was no new display data to send to the client */ /* Sleep for 1/20th second before checking again */ cyg_thread_delay(rtc_resolution[1]/20); } /* Check for sound bell event */ cyg_mutex_lock(&SoundBell_lock); if (SoundBellCount) { --SoundBellCount; cyg_mutex_unlock(&SoundBell_lock); if (send(client_sock, sound_bell, 1, 0) != 1) { goto wait_for_client; } } else { cyg_mutex_unlock(&SoundBell_lock); } }}/*****************************************************************************//** Generate tile update data function * * @param *packet_buffer Buffer to store tile data * * @return Length of generated data in bytes * * This function is called by the frame_update thread to generate the message * data for a tile to send to the client. This function expects the * x-position, y-position, width and height fields of the buffer to be filled * in before it is called. * * The format of the buffer is: * packet_buffer[0:1] - x-position of tile * packet_buffer[2:3] - y-position of tile * packet_buffer[4:5] - width of tile * packet_buffer[6:7] - height of tile * packet_buffer[8 onwards] - Pixel data for the tile * * The pixel data will be encoded with CoRRE encoding (if the CDL option is * enabled and the client can handle it) or RAW encoding if that is smaller * than CoRRE encoding for that particular tile. * *****************************************************************************/static int GenTileUpdateData(cyg_uint8 *packet_buffer){ cyg_uint16 x_pos, y_pos; int i, j; int packet_length; int tile_width, tile_height;#ifdef CYGNUM_VNC_SERVER_USE_CORRE_ENCODING static vnc_colour_t tile_buffer[TILE_SIZE][TILE_SIZE]; /* Buffer to hold tile to be encoded */ vnc_colour_t pixel_colour; vnc_colour_t bg_colour; int no_of_subrects, subrect_width, subrect_height; int k, l; no_of_subrects = 0; /* Set to no sub-rectangles to start with */#endif /* CYGNUM_VNC_SERVER_USE_CORRE_ENCODING */ packet_length = 20-4+(BITS_PER_PIXEL/8); /* Set to minimum packet length to start with */ /* Get the X and Y positions of this tile from the packet buffer */ x_pos = packet_buffer[0] * 256 + packet_buffer[1]; y_pos = packet_buffer[2] * 256 + packet_buffer[3]; /* Get the tile width and height from the packet buffer */ tile_width = packet_buffer[4] * 256 + packet_buffer[5]; tile_height = packet_buffer[6] * 256 + packet_buffer[7];#ifdef CYGNUM_VNC_SERVER_USE_CORRE_ENCODING /* Set the encoding type to RRE */ if (!encoding_type.corre) { /* CoRRE encoding is not supported - just use raw encoding */ goto use_raw_encoding; } /* Set encoding type to CoRRE encoding in packet buffer */ packet_buffer[8+0] = 0; packet_buffer[8+1] = 0; packet_buffer[8+2] = 0; packet_buffer[8+3] = 4; /* Copy tile from the main frame buffer to the local tile buffer */ for (i = 0; i < tile_height; i++) { for (j = 0; j < tile_width; j++) { tile_buffer[i][j] = frame_buffer[y_pos + i][x_pos + j]; } } /* Find the background colour */ /* We just assume the (0, 0) pixel in the tile is the bgcolour */ /* Its quick!!! */ bg_colour = frame_buffer[y_pos][x_pos]; /* Set the background colour in the packet buffer */#if BITS_PER_PIXEL == 8 packet_buffer[16] = (vnc_colour_t) bg_colour;#endif#if BITS_PER_PIXEL == 16 packet_buffer[16] = COLOUR2BYTE0(bg_colour); packet_buffer[16+1] = COLOUR2BYTE1(bg_colour);#endif#ifdef CYGNUM_VNC_SERVER_CORRE_ENCODING_HACK /* Add an initial sub-rectangle to paint the background the background colour */ /* This is required because of a known bug in the VNC viewer (x86 version) */#if BITS_PER_PIXEL == 8 packet_buffer[packet_length] = (vnc_colour_t) bg_colour; packet_length++;#endif#if BITS_PER_PIXEL == 16 packet_buffer[packet_length] = packet_buffer[16]; packet_buffer[packet_length+1] = packet_buffer[16+1]; packet_length += 2;#endif packet_buffer[packet_length] = (cyg_uint8) 0; /* Sub-rect x-pos */ packet_buffer[packet_length+1] = (cyg_uint8) 0; /* Sub-rect y-pos*/ packet_buffer[packet_length+2] = (cyg_uint8) tile_width; /* Sub-rect width*/ packet_buffer[packet_length+3] = (cyg_uint8) tile_height; /* Sub-rect height*/ packet_length += 4; no_of_subrects++; /* Increment sub-rectangle count */#endif /* Scan trough tile and find sub-rectangles */ for (i = 0; i < tile_height; i++) { for (j = 0; j < tile_width; j++) { if (tile_buffer[i][j] != bg_colour) { /* This is a non-background pixel */ subrect_width = 1; pixel_colour = tile_buffer[i][j]; /* Extend the sub-rectangle to its maximum width */ for (subrect_width = 1; subrect_width <= tile_width-j-1; subrect_width++) { if (tile_buffer[i][j+subrect_width] != pixel_colour) { goto got_subrect_width; } } got_subrect_width: /* Extend the sub-rectangle to its maximum height */ for (subrect_height=1; subrect_height <= tile_height-i-1; subrect_height++) { for (k = j; k < j+subrect_width; k++) { if (tile_buffer[i+subrect_height][k] != pixel_colour) { goto got_subrect_height; } } } got_subrect_height: /* Delete the pixels for the sub-rectangle from the sub-rectangle */ for (k = i; k < i+subrect_height; k++) { for (l = j; l < j+subrect_width; l++) { tile_buffer[k][l] = bg_colour; } } /* Append new sub-rectangle data to the packet buffer */#if BITS_PER_PIXEL == 8 packet_buffer[packet_length] = (vnc_colour_t) pixel_colour; packet_length++;#endif#if BITS_PER_PIXEL == 16 packet_buffer[packet_length] = COLOUR2BYTE0(pixel_colour); packet_buffer[packet_length+1] = COLOUR2BYTE1(pixel_colour); packet_length += 2;#endif packet_buffer[packet_length] = (cyg_uint8) j; /* Sub-rect x-pos */ packet_length++; packet_buffer[packet_length] = (cyg_uint8) i; /* Sub-rect y-pos*/ packet_length++; packet_buffer[packet_length] = (cyg_uint8) subrect_width; /* Sub-rect width*/ packet_length++; packet_buffer[packet_length] = (cyg_uint8) subrect_height; /* Sub-rect height*/ packet_length++; no_of_subrects++; /* Increment sub-rectangle count */ if (packet_length >= 12 + tile_height*tile_width*(BITS_PER_PIXEL/8) - 6) { /* The next sub-rectangle will make the packet size */ /* larger than a rew encoded packet - so just use raw */ goto use_raw_encoding; } } } } /* Fill in no_of_sub-rectangles field in packet buffer */ packet_buffer[12+0] = 0; packet_buffer[12+1] = 0; packet_buffer[12+2] = no_of_subrects / 256; packet_buffer[12+3] = no_of_subrects % 256; /* CoRRE data encoding for tile complete */ return packet_length; use_raw_encoding:#endif /* CYGNUM_VNC_SERVER_USE_CORRE_ENCODING */ /* Create packet data using RAW encoding */ for (i = 0; i < tile_height; i++) { for (j = 0; j < tile_width; j++) {#if BITS_PER_PIXEL == 8 packet_buffer[12 + tile_width * i + j] = frame_buffer[y_pos + i][x_pos + j];#endif#if BITS_PER_PIXEL == 16 packet_buffer[12 + 2 * tile_width * i + 2*j] = COLOUR2BYTE0(frame_buffer[y_pos + i][x_pos + j]); packet_buffer[12 + 2 * tile_width * i + 2*j+ 1] = COLOUR2BYTE1(frame_buffer[y_pos + i][x_pos + j]);#endif } } /* Set the encoding type to raw */ packet_buffer[8+0] = 0; packet_buffer[8+1] = 0; packet_buffer[8+2] = 0; packet_buffer[8+3] = 0; return (12 + tile_width*tile_height*(BITS_PER_PIXEL/8));}/*****************************************************************************//** Get message data function * * @param socket_fd File descriptor of the socket to get the data from. * @param *buffer Buffer to store received data in. * @param num_bytes Number of bytes to attempt to get. * * @return 1 on sucessfull completion - 0 on error. * * This function is called by the client_handler thread to get data from the * client's socket. * *****************************************************************************/static int GetMessageData(int socket_fd, char *buffer, int num_bytes){ int bytes_rxd; int message_len = 0; while (message_len < num_bytes) { if ((bytes_rxd = recv(socket_fd, buffer, num_bytes, 0)) <= 0) { return 0; } message_len += bytes_rxd; } return 1;}/* Driver functions */vnc_frame_format_t* VncGetInfo(void){ return &frame_format;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?