libfreerdp-core: improve bitmap codec negotiation
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Sun, 21 Sep 2014 19:40:27 +0000 (15:40 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Sun, 21 Sep 2014 19:40:27 +0000 (15:40 -0400)
include/freerdp/settings.h
libfreerdp/common/settings.c
libfreerdp/core/capabilities.c
libfreerdp/core/settings.c
server/shadow/shadow_client.c

index f1002e1..a18ce2b 100644 (file)
@@ -759,6 +759,9 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
 #define FreeRDP_NSCodec                                                3712
 #define FreeRDP_NSCodecId                                      3713
 #define FreeRDP_FrameAcknowledge                               3714
+#define FreeRDP_NSCodecColorLossLevel                          3715
+#define FreeRDP_NSCodecAllowSubsampling                                3716
+#define FreeRDP_NSCodecAllowDynamicColorFidelity               3717
 #define FreeRDP_JpegCodec                                      3776
 #define FreeRDP_JpegCodecId                                    3777
 #define FreeRDP_JpegQuality                                    3778
@@ -1271,7 +1274,10 @@ struct rdp_settings
        ALIGN64 BOOL NSCodec; /* 3712 */
        ALIGN64 UINT32 NSCodecId; /* 3713 */
        ALIGN64 UINT32 FrameAcknowledge; /* 3714 */
-       UINT64 padding3776[3776 - 3715]; /* 3715 */
+       ALIGN64 UINT32 NSCodecColorLossLevel; /* 3715 */
+       ALIGN64 BOOL NSCodecAllowSubsampling; /* 3716 */
+       ALIGN64 BOOL NSCodecAllowDynamicColorFidelity; /* 3717 */
+       UINT64 padding3776[3776 - 3718]; /* 3718 */
 
        /* JPEG */
        ALIGN64 BOOL JpegCodec; /* 3776 */
index 575ba2b..f93423a 100644 (file)
@@ -976,8 +976,11 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
                case FreeRDP_NSCodec:
                        return settings->NSCodec;
 
-               case FreeRDP_FrameAcknowledge:
-                       return settings->FrameAcknowledge;
+               case FreeRDP_NSCodecAllowSubsampling:
+                       return settings->NSCodecAllowSubsampling;
+
+               case FreeRDP_NSCodecAllowDynamicColorFidelity:
+                       return settings->NSCodecAllowDynamicColorFidelity;
 
                case FreeRDP_JpegCodec:
                        return settings->JpegCodec;
@@ -1464,8 +1467,12 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
                        settings->NSCodec = param;
                        break;
 
-               case FreeRDP_FrameAcknowledge:
-                       settings->FrameAcknowledge = param;
+               case FreeRDP_NSCodecAllowSubsampling:
+                       settings->NSCodecAllowSubsampling = param;
+                       break;
+
+               case FreeRDP_NSCodecAllowDynamicColorFidelity:
+                       settings->NSCodecAllowDynamicColorFidelity = param;
                        break;
 
                case FreeRDP_JpegCodec:
@@ -1788,6 +1795,12 @@ UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id)
                case FreeRDP_NSCodecId:
                        return settings->NSCodecId;
 
+               case FreeRDP_FrameAcknowledge:
+                       return settings->FrameAcknowledge;
+
+               case FreeRDP_NSCodecColorLossLevel:
+                       return settings->NSCodecColorLossLevel;
+
                case FreeRDP_JpegCodecId:
                        return settings->JpegCodecId;
 
@@ -2095,6 +2108,14 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param)
                        settings->NSCodecId = param;
                        break;
 
+               case FreeRDP_FrameAcknowledge:
+                       settings->FrameAcknowledge = param;
+                       break;
+
+               case FreeRDP_NSCodecColorLossLevel:
+                       settings->NSCodecColorLossLevel = param;
+                       break;
+
                case FreeRDP_JpegCodecId:
                        settings->JpegCodecId = param;
                        break;
index a02718e..09fb098 100644 (file)
@@ -2475,6 +2475,33 @@ BOOL rdp_print_surface_commands_capability_set(wStream* s, UINT16 length)
        return TRUE;
 }
 
+void rdp_print_bitmap_codec_guid(GUID* guid)
+{
+       WLog_INFO(TAG,  "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
+                         guid->Data1, guid->Data2, guid->Data3,
+                         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+                         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+}
+
+char* rdp_get_bitmap_codec_guid_name(GUID* guid)
+{
+       RPC_STATUS rpc_status;
+
+       if (UuidEqual(guid, &CODEC_GUID_REMOTEFX, &rpc_status))
+               return "CODEC_GUID_REMOTEFX";
+       else if (UuidEqual(guid, &CODEC_GUID_NSCODEC, &rpc_status))
+               return "CODEC_GUID_NSCODEC";
+       else if (UuidEqual(guid, &CODEC_GUID_IGNORE, &rpc_status))
+               return "CODEC_GUID_IGNORE";
+       else if (UuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX, &rpc_status))
+               return "CODEC_GUID_IMAGE_REMOTEFX";
+       else if (UuidEqual(guid, &CODEC_GUID_JPEG, &rpc_status))
+               return "CODEC_GUID_JPEG";
+
+       return "CODEC_GUID_UNKNOWN";
+}
+
+
 void rdp_read_bitmap_codec_guid(wStream* s, GUID* guid)
 {
        BYTE g[16];
@@ -2518,32 +2545,6 @@ void rdp_write_bitmap_codec_guid(wStream* s, GUID* guid)
        Stream_Write(s, g, 16);
 }
 
-void rdp_print_bitmap_codec_guid(GUID* guid)
-{
-       WLog_INFO(TAG,  "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
-                         guid->Data1, guid->Data2, guid->Data3,
-                         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
-                         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
-}
-
-char* rdp_get_bitmap_codec_guid_name(GUID* guid)
-{
-       RPC_STATUS rpc_status;
-
-       if (UuidEqual(guid, &CODEC_GUID_REMOTEFX, &rpc_status))
-               return "CODEC_GUID_REMOTEFX";
-       else if (UuidEqual(guid, &CODEC_GUID_NSCODEC, &rpc_status))
-               return "CODEC_GUID_NSCODEC";
-       else if (UuidEqual(guid, &CODEC_GUID_IGNORE, &rpc_status))
-               return "CODEC_GUID_IGNORE";
-       else if (UuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX, &rpc_status))
-               return "CODEC_GUID_IMAGE_REMOTEFX";
-       else if (UuidEqual(guid, &CODEC_GUID_JPEG, &rpc_status))
-               return "CODEC_GUID_JPEG";
-
-       return "CODEC_GUID_UNKNOWN";
-}
-
 /**
  * Read bitmap codecs capability set.\n
  * @msdn{dd891377}
@@ -2554,13 +2555,15 @@ char* rdp_get_bitmap_codec_guid_name(GUID* guid)
 
 BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSettings* settings)
 {
+       BYTE codecId;
        GUID codecGuid;
        RPC_STATUS rpc_status;
        BYTE bitmapCodecCount;
        UINT16 codecPropertiesLength;
        UINT16 remainingLength;
-       BOOL receivedRemoteFxCodec = FALSE;
-       BOOL receivedNSCodec = FALSE;
+       BOOL guidNSCodec = FALSE;
+       BOOL guidRemoteFx = FALSE;
+       BOOL guidRemoteFxImage = FALSE;
 
        if (length < 5)
                return FALSE;
@@ -2575,28 +2578,7 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting
 
                rdp_read_bitmap_codec_guid(s, &codecGuid); /* codecGuid (16 bytes) */
 
-               if (settings->ServerMode)
-               {
-                       if (UuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX, &rpc_status))
-                       {
-                               Stream_Read_UINT8(s, settings->RemoteFxCodecId);
-                               receivedRemoteFxCodec = TRUE;
-                       }
-                       else if (UuidEqual(&codecGuid, &CODEC_GUID_NSCODEC, &rpc_status))
-                       {
-                               Stream_Read_UINT8(s, settings->NSCodecId);
-                               receivedNSCodec = TRUE;
-                       }
-                       else
-                       {
-                               Stream_Seek_UINT8(s); /* codecID (1 byte) */
-                       }
-               }
-               else
-               {
-                       Stream_Seek_UINT8(s); /* codecID (1 byte) */
-               }
-
+               Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
                Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
                remainingLength -= 19;
 
@@ -2605,21 +2587,154 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting
 
                if (settings->ServerMode)
                {
+                       UINT32 beg;
+                       UINT32 end;
+
+                       beg = (UINT32) Stream_GetPosition(s);
+                       end = beg + codecPropertiesLength;
+
                        if (UuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX, &rpc_status))
                        {
-                               Stream_Seek_UINT32(s); /* length */
-                               Stream_Read_UINT32(s, settings->RemoteFxCaptureFlags); /* captureFlags */
-                               Stream_Rewind(s, 8);
+                               UINT32 rfxCapsLength;
+                               UINT32 rfxPropsLength;
+                               UINT32 captureFlags;
+
+                               guidRemoteFx = TRUE;
+                               settings->RemoteFxCodecId = codecId;
+
+                               Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
+                               Stream_Read_UINT32(s, captureFlags); /* captureFlags (4 bytes) */
+                               Stream_Read_UINT32(s, rfxCapsLength); /* capsLength (4 bytes) */
 
-                               if (settings->RemoteFxCaptureFlags & CARDP_CAPS_CAPTURE_NON_CAC)
+                               settings->RemoteFxCaptureFlags = captureFlags;
+                               settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? TRUE : FALSE;
+
+                               if (rfxCapsLength)
                                {
-                                       settings->RemoteFxOnly = TRUE;
+                                       UINT16 blockType;
+                                       UINT32 blockLen;
+                                       UINT16 numCapsets;
+                                       BYTE rfxCodecId;
+                                       UINT16 capsetType;
+                                       UINT16 numIcaps;
+                                       UINT16 icapLen;
+
+                                       /* TS_RFX_CAPS */
+
+                                       Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
+                                       Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */
+                                       Stream_Read_UINT16(s, numCapsets); /* numCapsets (2 bytes) */
+
+                                       if (blockType != 0xCBC0)
+                                               return FALSE;
+
+                                       if (blockLen != 8)
+                                               return FALSE;
+
+                                       if (numCapsets != 1)
+                                               return FALSE;
+
+                                       /* TS_RFX_CAPSET */
+
+                                       Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
+                                       Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */
+                                       Stream_Read_UINT8(s, rfxCodecId); /* codecId (1 byte) */
+                                       Stream_Read_UINT16(s, capsetType); /* capsetType (2 bytes) */
+                                       Stream_Read_UINT16(s, numIcaps); /* numIcaps (2 bytes) */
+                                       Stream_Read_UINT16(s, icapLen); /* icapLen (2 bytes) */
+
+                                       if (blockType != 0xCBC1)
+                                               return FALSE;
+
+                                       if (rfxCodecId != 1)
+                                               return FALSE;
+
+                                       if (capsetType != 0xCFC0)
+                                               return FALSE;
+
+                                       while (numIcaps--)
+                                       {
+                                               UINT16 version;
+                                               UINT16 tileSize;
+                                               BYTE codecFlags;
+                                               BYTE colConvBits;
+                                               BYTE transformBits;
+                                               BYTE entropyBits;
+
+                                               /* TS_RFX_ICAP */
+
+                                               Stream_Read_UINT16(s, version); /* version (2 bytes) */
+                                               Stream_Read_UINT16(s, tileSize); /* tileSize (2 bytes) */
+                                               Stream_Read_UINT8(s, codecFlags); /* flags (1 byte) */
+                                               Stream_Read_UINT8(s, colConvBits); /* colConvBits (1 byte) */
+                                               Stream_Read_UINT8(s, transformBits); /* transformBits (1 byte) */
+                                               Stream_Read_UINT8(s, entropyBits); /* entropyBits (1 byte) */
+
+                                               if (version != 0x0100)
+                                                       return FALSE;
+
+                                               if (tileSize != 0x0040)
+                                                       return FALSE;
+
+                                               if (colConvBits != 1)
+                                                       return FALSE;
+
+                                               if (transformBits != 1)
+                                                       return FALSE;
+                                       }
                                }
                        }
-               }
+                       else if (UuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX, &rpc_status))
+                       {
+                               guidRemoteFxImage = TRUE;
+                               Stream_Seek(s, codecPropertiesLength); /* codecProperties */
+                       }
+                       else if (UuidEqual(&codecGuid, &CODEC_GUID_NSCODEC, &rpc_status))
+                       {
+                               BYTE colorLossLevel;
+                               BYTE fAllowSubsampling;
+                               BYTE fAllowDynamicFidelity;
 
-               Stream_Seek(s, codecPropertiesLength); /* codecProperties */
-               remainingLength -= codecPropertiesLength;
+                               guidNSCodec = TRUE;
+                               settings->NSCodecId = codecId;
+
+                               Stream_Read_UINT8(s, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
+                               Stream_Read_UINT8(s, fAllowSubsampling); /* fAllowSubsampling (1 byte) */
+                               Stream_Read_UINT8(s, colorLossLevel); /* colorLossLevel (1 byte) */
+
+                               if (colorLossLevel < 1)
+                                       colorLossLevel = 1;
+
+                               if (colorLossLevel > 7)
+                                       colorLossLevel = 7;
+
+                               settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
+                               settings->NSCodecAllowSubsampling = fAllowSubsampling;
+                               settings->NSCodecColorLossLevel = colorLossLevel;
+                       }
+                       else if (UuidEqual(&codecGuid, &CODEC_GUID_IGNORE, &rpc_status))
+                       {
+                               Stream_Seek(s, codecPropertiesLength); /* codecProperties */
+                       }
+                       else
+                       {
+                               Stream_Seek(s, codecPropertiesLength); /* codecProperties */
+                       }
+
+                       if (Stream_GetPosition(s) != end)
+                       {
+                               fprintf(stderr, "error while reading codec properties: actual offset: %d expected offset: %d\n",
+                                               Stream_GetPosition(s), end);
+                               Stream_SetPosition(s, end);
+                       }
+
+                       remainingLength -= codecPropertiesLength;
+               }
+               else
+               {
+                       Stream_Seek(s, codecPropertiesLength); /* codecProperties */
+                       remainingLength -= codecPropertiesLength;
+               }
 
                bitmapCodecCount--;
        }
@@ -2627,8 +2742,9 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting
        if (settings->ServerMode)
        {
                /* only enable a codec if we've announced/enabled it before */
-               settings->RemoteFxCodec = settings->RemoteFxCodec && receivedRemoteFxCodec;
-               settings->NSCodec = settings->NSCodec && receivedNSCodec;
+               settings->RemoteFxCodec = settings->RemoteFxCodec && guidRemoteFx;
+               settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && guidRemoteFxImage;
+               settings->NSCodec = settings->NSCodec && guidNSCodec;
                settings->JpegCodec = FALSE;
        }
 
@@ -2699,9 +2815,9 @@ void rdp_write_nsc_client_capability_container(wStream* s, rdpSettings* settings
        Stream_Write_UINT16(s, 3); /* codecPropertiesLength */
 
        /* TS_NSCODEC_CAPABILITYSET */
-       Stream_Write_UINT8(s, 1);  /* fAllowDynamicFidelity */
-       Stream_Write_UINT8(s, 1);  /* fAllowSubsampling */
-       Stream_Write_UINT8(s, 3);  /* colorLossLevel */
+       Stream_Write_UINT8(s, settings->NSCodecAllowDynamicColorFidelity);  /* fAllowDynamicFidelity */
+       Stream_Write_UINT8(s, settings->NSCodecAllowSubsampling);  /* fAllowSubsampling */
+       Stream_Write_UINT8(s, settings->NSCodecColorLossLevel);  /* colorLossLevel */
 }
 
 void rdp_write_jpeg_client_capability_container(wStream* s, rdpSettings* settings)
@@ -2765,9 +2881,6 @@ void rdp_write_bitmap_codecs_capability_set(wStream* s, rdpSettings* settings)
        bitmapCodecCount = 0;
 
        if (settings->RemoteFxCodec)
-               settings->RemoteFxImageCodec = TRUE;
-
-       if (settings->RemoteFxCodec)
                bitmapCodecCount++;
        if (settings->NSCodec)
                bitmapCodecCount++;
index 3c07082..f20699b 100644 (file)
@@ -402,6 +402,10 @@ rdpSettings* freerdp_settings_new(DWORD flags)
                settings->FrameAcknowledge = 2;
                settings->MouseMotion = TRUE;
 
+               settings->NSCodecColorLossLevel = 3;
+               settings->NSCodecAllowSubsampling = TRUE;
+               settings->NSCodecAllowDynamicColorFidelity = TRUE;
+
                settings->AutoReconnectionEnabled = FALSE;
                settings->AutoReconnectMaxRetries = 20;
 
@@ -584,6 +588,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
                _settings->RemoteFxCaptureFlags = settings->RemoteFxCaptureFlags; /* 3653 */
                _settings->NSCodecId = settings->NSCodecId; /* 3713 */
                _settings->FrameAcknowledge = settings->FrameAcknowledge; /* 3714 */
+               _settings->NSCodecColorLossLevel = settings->NSCodecColorLossLevel; /* 3715 */
                _settings->JpegCodecId = settings->JpegCodecId; /* 3777 */
                _settings->JpegQuality = settings->JpegQuality; /* 3778 */
                _settings->BitmapCacheV3CodecId = settings->BitmapCacheV3CodecId; /* 3904 */
@@ -708,6 +713,8 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
                _settings->RemoteFxCodec = settings->RemoteFxCodec; /* 3649 */
                _settings->RemoteFxImageCodec = settings->RemoteFxImageCodec; /* 3652 */
                _settings->NSCodec = settings->NSCodec; /* 3712 */
+               _settings->NSCodecAllowSubsampling = settings->NSCodecAllowSubsampling; /* 3716 */
+               _settings->NSCodecAllowDynamicColorFidelity = settings->NSCodecAllowDynamicColorFidelity; /* 3717 */
                _settings->JpegCodec = settings->JpegCodec; /* 3776 */
                _settings->GfxThinClient = settings->GfxThinClient; /* 3840 */
                _settings->GfxSmallCache = settings->GfxSmallCache; /* 3841 */
index a8f34ed..cc46b5a 100644 (file)
@@ -159,6 +159,12 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
        if (settings->ColorDepth == 24)
                settings->ColorDepth = 16; /* disable 24bpp */
 
+       if (settings->ColorDepth < 32)
+       {
+               settings->NSCodec = FALSE;
+               settings->RemoteFxCodec = FALSE;
+       }
+
        WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)",
                        peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);