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 + -
显示快捷键?