⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vnc-server.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:

/*****************************************************************************/
/** 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_NET
void frame_update(cyg_addrword_t data)
#else
static 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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -