This commit is contained in:
2026-02-13 13:06:50 +09:00
commit b54066842b
249 changed files with 69547 additions and 0 deletions

282
grd-rdp-sw-encoder-ca.c Normal file
View File

@@ -0,0 +1,282 @@
/*
* Copyright (C) 2024 Pascal Nowack
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "config.h"
#include "grd-rdp-sw-encoder-ca.h"
#include <gio/gio.h>
struct _GrdRdpSwEncoderCa
{
GObject parent;
GMutex encode_mutex;
RFX_CONTEXT *rfx_context;
};
G_DEFINE_TYPE (GrdRdpSwEncoderCa, grd_rdp_sw_encoder_ca, G_TYPE_OBJECT)
static void
rfx_progressive_write_message (RFX_MESSAGE *rfx_message,
wStream *s,
gboolean write_header)
{
const RFX_RECT *rfx_rects;
uint16_t n_rfx_rects = 0;
const UINT32 *quant_vals;
uint16_t n_quant_vals = 0;
const RFX_TILE **rfx_tiles;
uint16_t n_rfx_tiles = 0;
uint32_t block_len;
const uint32_t *qv;
const RFX_TILE *rfx_tile;
uint32_t tiles_data_size;
uint16_t i;
rfx_rects = rfx_message_get_rects (rfx_message, &n_rfx_rects);
quant_vals = rfx_message_get_quants (rfx_message, &n_quant_vals);
rfx_tiles = rfx_message_get_tiles (rfx_message, &n_rfx_tiles);
if (write_header)
{
/* RFX_PROGRESSIVE_SYNC */
block_len = 12;
if (!Stream_EnsureRemainingCapacity (s, block_len))
g_assert_not_reached ();
Stream_Write_UINT16 (s, 0xCCC0); /* blockType */
Stream_Write_UINT32 (s, block_len); /* blockLen */
Stream_Write_UINT32 (s, 0xCACCACCA); /* magic */
Stream_Write_UINT16 (s, 0x0100); /* version */
/* RFX_PROGRESSIVE_CONTEXT */
block_len = 10;
if (!Stream_EnsureRemainingCapacity (s, block_len))
g_assert_not_reached ();
Stream_Write_UINT16 (s, 0xCCC3); /* blockType */
Stream_Write_UINT32 (s, block_len); /* blockLen */
Stream_Write_UINT8 (s, 0); /* ctxId */
Stream_Write_UINT16 (s, 0x0040); /* tileSize */
Stream_Write_UINT8 (s, 0); /* flags */
}
/* RFX_PROGRESSIVE_FRAME_BEGIN */
block_len = 12;
if (!Stream_EnsureRemainingCapacity (s, block_len))
g_assert_not_reached ();
Stream_Write_UINT16 (s, 0xCCC1); /* blockType */
Stream_Write_UINT32 (s, block_len); /* blockLen */
Stream_Write_UINT32 (s, rfx_message_get_frame_idx (rfx_message)); /* frameIndex */
Stream_Write_UINT16 (s, 1); /* regionCount */
/* RFX_PROGRESSIVE_REGION */
block_len = 18;
block_len += n_rfx_rects * 8;
block_len += n_quant_vals * 5;
tiles_data_size = n_rfx_tiles * 22;
for (i = 0; i < n_rfx_tiles; i++)
{
rfx_tile = rfx_tiles[i];
tiles_data_size += rfx_tile->YLen + rfx_tile->CbLen + rfx_tile->CrLen;
}
block_len += tiles_data_size;
if (!Stream_EnsureRemainingCapacity (s, block_len))
g_assert_not_reached ();
Stream_Write_UINT16 (s, 0xCCC4); /* blockType */
Stream_Write_UINT32 (s, block_len); /* blockLen */
Stream_Write_UINT8 (s, 0x40); /* tileSize */
Stream_Write_UINT16 (s, n_rfx_rects); /* numRects */
Stream_Write_UINT8 (s, n_quant_vals); /* numQuant */
Stream_Write_UINT8 (s, 0); /* numProgQuant */
Stream_Write_UINT8 (s, 0); /* flags */
Stream_Write_UINT16 (s, n_rfx_tiles); /* numTiles */
Stream_Write_UINT32 (s, tiles_data_size); /* tilesDataSize */
for (i = 0; i < n_rfx_rects; i++)
{
/* TS_RFX_RECT */
Stream_Write_UINT16 (s, rfx_rects[i].x); /* x */
Stream_Write_UINT16 (s, rfx_rects[i].y); /* y */
Stream_Write_UINT16 (s, rfx_rects[i].width); /* width */
Stream_Write_UINT16 (s, rfx_rects[i].height); /* height */
}
/*
* The RFX_COMPONENT_CODEC_QUANT structure differs from the
* TS_RFX_CODEC_QUANT ([MS-RDPRFX] section 2.2.2.1.5) structure with respect
* to the order of the bands.
* 0 1 2 3 4 5 6 7 8 9
* RDPRFX: LL3, LH3, HL3, HH3, LH2, HL2, HH2, LH1, HL1, HH1
* RDPEGFX: LL3, HL3, LH3, HH3, HL2, LH2, HH2, HL1, LH1, HH1
*/
for (i = 0, qv = quant_vals; i < n_quant_vals; ++i, qv += 10)
{
/* RFX_COMPONENT_CODEC_QUANT */
Stream_Write_UINT8 (s, qv[0] + (qv[2] << 4)); /* LL3, HL3 */
Stream_Write_UINT8 (s, qv[1] + (qv[3] << 4)); /* LH3, HH3 */
Stream_Write_UINT8 (s, qv[5] + (qv[4] << 4)); /* HL2, LH2 */
Stream_Write_UINT8 (s, qv[6] + (qv[8] << 4)); /* HH2, HL1 */
Stream_Write_UINT8 (s, qv[7] + (qv[9] << 4)); /* LH1, HH1 */
}
for (i = 0; i < n_rfx_tiles; ++i)
{
/* RFX_PROGRESSIVE_TILE_SIMPLE */
rfx_tile = rfx_tiles[i];
block_len = 22 + rfx_tile->YLen + rfx_tile->CbLen + rfx_tile->CrLen;
Stream_Write_UINT16 (s, 0xCCC5); /* blockType */
Stream_Write_UINT32 (s, block_len); /* blockLen */
Stream_Write_UINT8 (s, rfx_tile->quantIdxY); /* quantIdxY */
Stream_Write_UINT8 (s, rfx_tile->quantIdxCb); /* quantIdxCb */
Stream_Write_UINT8 (s, rfx_tile->quantIdxCr); /* quantIdxCr */
Stream_Write_UINT16 (s, rfx_tile->xIdx); /* xIdx */
Stream_Write_UINT16 (s, rfx_tile->yIdx); /* yIdx */
Stream_Write_UINT8 (s, 0); /* flags */
Stream_Write_UINT16 (s, rfx_tile->YLen); /* YLen */
Stream_Write_UINT16 (s, rfx_tile->CbLen); /* CbLen */
Stream_Write_UINT16 (s, rfx_tile->CrLen); /* CrLen */
Stream_Write_UINT16 (s, 0); /* tailLen */
Stream_Write (s, rfx_tile->YData, rfx_tile->YLen); /* YData */
Stream_Write (s, rfx_tile->CbData, rfx_tile->CbLen); /* CbData */
Stream_Write (s, rfx_tile->CrData, rfx_tile->CrLen); /* CrData */
}
/* RFX_PROGRESSIVE_FRAME_END */
block_len = 6;
if (!Stream_EnsureRemainingCapacity (s, block_len))
g_assert_not_reached ();
Stream_Write_UINT16 (s, 0xCCC2); /* blockType */
Stream_Write_UINT32 (s, block_len); /* blockLen */
Stream_SealLength (s);
}
void
grd_rdp_sw_encoder_ca_encode_progressive_frame (GrdRdpSwEncoderCa *encoder_ca,
uint32_t surface_width,
uint32_t surface_height,
uint8_t *src_buffer,
uint32_t src_stride,
cairo_region_t *damage_region,
wStream *encode_stream,
gboolean write_header)
{
g_autoptr (GMutexLocker) locker = NULL;
g_autofree RFX_RECT *rfx_rects = NULL;
int n_rects;
RFX_MESSAGE *rfx_message;
int i;
locker = g_mutex_locker_new (&encoder_ca->encode_mutex);
rfx_context_set_mode (encoder_ca->rfx_context, RLGR1);
rfx_context_reset (encoder_ca->rfx_context, surface_width, surface_height);
n_rects = cairo_region_num_rectangles (damage_region);
rfx_rects = g_new0 (RFX_RECT, n_rects);
for (i = 0; i < n_rects; ++i)
{
RFX_RECT *rfx_rect = &rfx_rects[i];
cairo_rectangle_int_t cairo_rect;
cairo_region_get_rectangle (damage_region, i, &cairo_rect);
rfx_rect->x = cairo_rect.x;
rfx_rect->y = cairo_rect.y;
rfx_rect->width = cairo_rect.width;
rfx_rect->height = cairo_rect.height;
}
rfx_message = rfx_encode_message (encoder_ca->rfx_context,
rfx_rects, n_rects,
src_buffer,
surface_width, surface_height,
src_stride);
Stream_SetPosition (encode_stream, 0);
rfx_progressive_write_message (rfx_message, encode_stream, write_header);
rfx_message_free (encoder_ca->rfx_context, rfx_message);
}
GrdRdpSwEncoderCa *
grd_rdp_sw_encoder_ca_new (GError **error)
{
g_autoptr (GrdRdpSwEncoderCa) encoder_ca = NULL;
encoder_ca = g_object_new (GRD_TYPE_RDP_SW_ENCODER_CA, NULL);
encoder_ca->rfx_context = rfx_context_new (TRUE);
if (!encoder_ca->rfx_context)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create RFX context");
return NULL;
}
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
rfx_context_set_pixel_format (encoder_ca->rfx_context,
PIXEL_FORMAT_BGRX32);
#else
rfx_context_set_pixel_format (encoder_ca->rfx_context,
PIXEL_FORMAT_XRGB32);
#endif
return g_steal_pointer (&encoder_ca);
}
static void
grd_rdp_sw_encoder_ca_dispose (GObject *object)
{
GrdRdpSwEncoderCa *encoder_ca = GRD_RDP_SW_ENCODER_CA (object);
g_clear_pointer (&encoder_ca->rfx_context, rfx_context_free);
G_OBJECT_CLASS (grd_rdp_sw_encoder_ca_parent_class)->dispose (object);
}
static void
grd_rdp_sw_encoder_ca_finalize (GObject *object)
{
GrdRdpSwEncoderCa *encoder_ca = GRD_RDP_SW_ENCODER_CA (object);
g_mutex_clear (&encoder_ca->encode_mutex);
G_OBJECT_CLASS (grd_rdp_sw_encoder_ca_parent_class)->finalize (object);
}
static void
grd_rdp_sw_encoder_ca_init (GrdRdpSwEncoderCa *encoder_ca)
{
g_mutex_init (&encoder_ca->encode_mutex);
}
static void
grd_rdp_sw_encoder_ca_class_init (GrdRdpSwEncoderCaClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = grd_rdp_sw_encoder_ca_dispose;
object_class->finalize = grd_rdp_sw_encoder_ca_finalize;
}