private void SendOutOfRects(OperationalMode mode)
        {
            #region Test Description
            /*
            Step 1: [RDPBCGR] establishing the connection.
            Step 2: [RDPBCGR] send Frame Maker Command (Begin) to SUT.
            Step 3: [RDPRFX] Send Encode Header Messages to SUT.
            Step 4: [RDPRFX] Send one frame of Encode Data Messages (encoded with RLGR1) to SUT, when some tiles are out of the rectangle in TS_RFX_REGION.
            Step 5: [RDPBCGR] send Frame Maker Command (End) to SUT.
            Step 6: [RDPRFX] Expect SUT sends a TS_FRAME_ACKNOWLEDGE_PDU.
            */
            #endregion

            #region Test Sequence

            //Start RDP listening.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Starting RDP listening.");
            this.rdpbcgrAdapter.StartRDPListening(transportProtocol);

            #region Trigger client to connect
            //Trigger client to connect.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Triggering SUT to initiate a RDP connection to server.");
            triggerClientRDPConnect(transportProtocol, true);
            #endregion

            #region RDPBCGR Connection

            //Waiting for the transport level connection request.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Expecting the transport layer connection request.");
            this.rdpbcgrAdapter.ExpectTransportConnection(RDPSessionType.Normal);

            //Set Server Capability with RomoteFX codec supported.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Setting Server Capability.");
            setServerCapabilitiesWithRemoteFxSupported();

            //Waiting for the RDP connection sequence.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Establishing RDP connection.");
            this.rdpbcgrAdapter.EstablishRDPConnection(selectedProtocol, enMethod, enLevel, true, false, rdpServerVersion);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Sending Server Save Session Info PDU to SUT to notify user has logged on.");
            this.rdpbcgrAdapter.ServerSaveSessionInfo(LogonNotificationType.UserLoggedOn, ErrorNotificationType_Values.LOGON_FAILED_OTHER);

            #endregion

            //Initial the RDPRFX adapter context.
            rdprfxAdapter.Accept(this.rdpbcgrAdapter.ServerStack, this.rdpbcgrAdapter.SessionContext);

            receiveAndLogClientRfxCapabilites();

            uint frameId = 0; //The index of the sending frame.
            OperationalMode opMode = mode;
            EntropyAlgorithm enAlgorithm = EntropyAlgorithm.CLW_ENTROPY_RLGR1;
            ushort destLeft = 0; //the left bound of the frame.
            ushort destTop = 0; //the top bound of the frame.

            //Check if the above setting is supported by client.
            if (!this.rdprfxAdapter.CheckIfClientSupports(opMode, enAlgorithm))
            {
                this.TestSite.Log.Add(LogEntryKind.Comment, "the input pair of Operational Mode ({0}) / Entropy Algorithm ({1}) is not supported by client, so stop running this test case.", opMode, enAlgorithm);
                return;
            }

            this.TestSite.Log.Add(LogEntryKind.Comment, "Sending Frame Marker Command (Begin) with frameID: {0}.", frameId);
            rdpbcgrAdapter.SendFrameMarkerCommand(frameAction_Values.SURFACECMD_FRAMEACTION_BEGIN, frameId);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Start to send encoded bitmap data to client. Operational Mode = {0}, Entropy Algorithm = {1}, destLeft = {2}, destTop = {3}.",
                opMode, enAlgorithm, destLeft, destTop);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Create rectangles whose height is TileSize/2, this rectangle is used for TS_RFX_REGION structure to clip the bitmap.");
            Rectangle clipRect = new Rectangle(64, 64, RgbTile.TileSize, RgbTile.TileSize);
            Rectangle[] rects = new Rectangle[] { clipRect };

            rdprfxAdapter.SendTsRfxSync();
            rdprfxAdapter.SendTsRfxCodecVersions();
            rdprfxAdapter.SendTsRfxChannels(RgbTile.TileSize * 2, RgbTile.TileSize * 2);
            rdprfxAdapter.SendTsRfxContext(opMode, enAlgorithm);

            rdprfxAdapter.SendTsRfxFrameBegin(0);
            rdprfxAdapter.SendTsRfxRegion(rects);
            TILE_POSITION[] positions = new TILE_POSITION[4]{
                new TILE_POSITION{ xIdx = 0, yIdx = 0 },
                new TILE_POSITION{ xIdx = 0, yIdx = 1 },
                new TILE_POSITION{ xIdx = 1, yIdx = 0 },
                new TILE_POSITION{ xIdx = 1, yIdx = 1 }
            };
            rdprfxAdapter.SendTsRfxTileSet(
                opMode,
                enAlgorithm,
                new Image[] { image_64X64, image_64X64, image_64X64, image_64X64 },
                positions);
            rdprfxAdapter.SendTsRfxFrameEnd();
            rdprfxAdapter.FlushEncodedData(destLeft, destTop, RgbTile.TileSize * 2, RgbTile.TileSize * 2);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Sending Frame Marker Command (End) with frameID: {0}.", frameId);
            rdpbcgrAdapter.SendFrameMarkerCommand(frameAction_Values.SURFACECMD_FRAMEACTION_END, frameId);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Expecting TS_FRAME_ACKNOWLEDGE_PDU.");
            rdprfxAdapter.ExpectTsFrameAcknowledgePdu(frameId, waitTime);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Verify output on SUT Display if the verifySUTDisplay entry in PTF config is true.");
            Rectangle compareRect = new Rectangle(destLeft, destTop, RgbTile.TileSize * 2, RgbTile.TileSize * 2);
            this.VerifySUTDisplay(true, compareRect);

            #endregion
        }
        private void NegtiveTest_DuplicatedTile(OperationalMode mode)
        {
            #region Test Description
            /*
            Step 1: [RDPBCGR] establishing the connection.
            Step 2: [RDPBCGR] send Frame Maker Command (Begin) to SUT.
            Step 3: [RDPRFX] Send Encode Header Messages to SUT.
            Step 4: [RDPRFX] Send one frame of Encode Data Messages (encoded with RLGR1) to SUT, the TS_RFX_REGION structure contains rectangular which contains a duplicated tile.
            Step 5: [RDPRFX] Expect the client terminates the RDP connection.
            */
            #endregion

            #region Test Sequence

            //Start RDP listening.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Starting RDP listening.");
            this.rdpbcgrAdapter.StartRDPListening(transportProtocol);

            #region Trigger client to connect
            //Trigger client to connect.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Triggering SUT to initiate a RDP connection to server.");
            triggerClientRDPConnect(transportProtocol, true);
            #endregion

            #region RDPBCGR Connection

            //Waiting for the transport level connection request.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Expecting the transport layer connection request.");
            this.rdpbcgrAdapter.ExpectTransportConnection(RDPSessionType.Normal);

            //Set Server Capability with RomoteFX codec supported.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Setting Server Capability.");
            setServerCapabilitiesWithRemoteFxSupported();

            //Waiting for the RDP connection sequence.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Establishing RDP connection.");
            this.rdpbcgrAdapter.EstablishRDPConnection(selectedProtocol, enMethod, enLevel, true, false, rdpServerVersion);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Sending Server Save Session Info PDU to SUT to notify user has logged on.");
            this.rdpbcgrAdapter.ServerSaveSessionInfo(LogonNotificationType.UserLoggedOn, ErrorNotificationType_Values.LOGON_FAILED_OTHER);

            #endregion

            //Initial the RDPRFX adapter context.
            rdprfxAdapter.Accept(this.rdpbcgrAdapter.ServerStack, this.rdpbcgrAdapter.SessionContext);

            receiveAndLogClientRfxCapabilites();

            uint frameId = 0; //The index of the sending frame.
            OperationalMode opMode = mode;
            EntropyAlgorithm enAlgorithm = EntropyAlgorithm.CLW_ENTROPY_RLGR1;
            ushort destLeft = 0; //the left bound of the frame.
            ushort destTop = 0; //the top bound of the frame.

            //Check if the above setting is supported by client.
            if (!this.rdprfxAdapter.CheckIfClientSupports(opMode, enAlgorithm))
            {
                this.TestSite.Log.Add(LogEntryKind.Comment, "the input pair of Operational Mode ({0}) / Entropy Algorithm ({1}) is not supported by client, so stop running this test case.", opMode, enAlgorithm);
                return;
            }

            this.TestSite.Log.Add(LogEntryKind.Comment, "Sending Frame Marker Command (Begin) with frameID: {0}.", frameId);
            rdpbcgrAdapter.SendFrameMarkerCommand(frameAction_Values.SURFACECMD_FRAMEACTION_BEGIN, frameId);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Start to send encoded bitmap data to client. Operational Mode = {0}, Entropy Algorithm = {1}, destLeft = {2}, destTop = {3}.",
                opMode, enAlgorithm, destLeft, destTop);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Create rectangles list, this rectangle list is used for TS_RFX_REGION structure to clip the bitmap.");
            Rectangle clipRect1 = new Rectangle(0, 0, RgbTile.TileSize * 2, RgbTile.TileSize * 2);

            Rectangle[] rects = new Rectangle[] { clipRect1 };

            rdprfxAdapter.SendTsRfxSync();
            rdprfxAdapter.SendTsRfxCodecVersions();
            rdprfxAdapter.SendTsRfxChannels(RgbTile.TileSize * 2, RgbTile.TileSize * 2);
            rdprfxAdapter.SendTsRfxContext(opMode, enAlgorithm);

            var bitmapBlue = new Bitmap(RgbTile.TileSize, RgbTile.TileSize);
            Graphics graphics = Graphics.FromImage(bitmapBlue);
            graphics.FillRectangle(Brushes.Blue, new Rectangle(0, 0, RgbTile.TileSize, RgbTile.TileSize));
            var bitmapRed = new Bitmap(RgbTile.TileSize, RgbTile.TileSize);
            graphics = Graphics.FromImage(bitmapRed);
            graphics.FillRectangle(Brushes.Red, new Rectangle(0, 0, RgbTile.TileSize, RgbTile.TileSize));

            rdprfxAdapter.SendTsRfxFrameBegin(0);
            rdprfxAdapter.SendTsRfxRegion(rects);

            TILE_POSITION[] positions = new TILE_POSITION[5]{
                new TILE_POSITION{ xIdx = 1, yIdx = 1 },
                new TILE_POSITION{ xIdx = 0, yIdx = 0 },
                new TILE_POSITION{ xIdx = 1, yIdx = 0 },
                new TILE_POSITION{ xIdx = 0, yIdx = 1 },
                new TILE_POSITION{ xIdx = 1, yIdx = 1 },
            };

            rdprfxAdapter.SendTsRfxTileSet(
                opMode,
                enAlgorithm,
                new Image[] { bitmapRed, bitmapBlue, bitmapBlue, bitmapBlue, bitmapBlue },
                positions);
            rdprfxAdapter.SendTsRfxFrameEnd();
            rdprfxAdapter.FlushEncodedData(destLeft, destTop, RgbTile.TileSize * 2, RgbTile.TileSize * 2);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Expecting the client terminates the RDP connection.");
            bool bDisconnected = rdpbcgrAdapter.WaitForDisconnection(waitTime);

            this.TestSite.Assert.IsTrue(bDisconnected, "Client is expected to drop the connection if received duplicated tiles in Video Mode when Image Mode is in effect.");

            #endregion
        }
        public void Rdprfx_VideoMode_PositiveTest_Differencing()
        {
            #region Test Description
            /*
            Step 1: [RDPBCGR] establishing the connection.
            Step 2: [RDPBCGR] send Frame Maker Command (Begin) to SUT.
            Step 3: [RDPRFX] Send Encode Header Messages to SUT.
            Step 4: [RDPRFX] Send multiple frames of Encode Data Messages (encoded with RLGR1) to SUT.
            Step 4: [RDPRFX] Send multiple frames with one frame no changes (encoded with RLGR1) to SUT.
            Step 5: [RDPBCGR] send Frame Maker Command (End) to SUT.
            Step 6: [RDPRFX] Expect SUT sends a TS_FRAME_ACKNOWLEDGE_PDU.
            */
            #endregion

            #region Test Sequence

            //Start RDP listening.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Starting RDP listening.");
            this.rdpbcgrAdapter.StartRDPListening(transportProtocol);

            #region Trigger client to connect
            //Trigger client to connect.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Triggering SUT to initiate a RDP connection to server.");
            triggerClientRDPConnect(transportProtocol, true);
            #endregion

            #region RDPBCGR Connection

            //Waiting for the transport level connection request.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Expecting the transport layer connection request.");
            this.rdpbcgrAdapter.ExpectTransportConnection(RDPSessionType.Normal);

            //Set Server Capability with RomoteFX codec supported.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Setting Server Capability.");
            setServerCapabilitiesWithRemoteFxSupported();

            //Waiting for the RDP connection sequence.
            this.TestSite.Log.Add(LogEntryKind.Comment, "Establishing RDP connection.");
            this.rdpbcgrAdapter.EstablishRDPConnection(selectedProtocol, enMethod, enLevel, true, false, rdpServerVersion);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Sending Server Save Session Info PDU to SUT to notify user has logged on.");
            this.rdpbcgrAdapter.ServerSaveSessionInfo(LogonNotificationType.UserLoggedOn, ErrorNotificationType_Values.LOGON_FAILED_OTHER);

            #endregion

            //Initial the RDPRFX adapter context.
            rdprfxAdapter.Accept(this.rdpbcgrAdapter.ServerStack, this.rdpbcgrAdapter.SessionContext);

            receiveAndLogClientRfxCapabilites();

            uint frameId = 0; //The index of the sending frame.
            OperationalMode opMode = OperationalMode.VideoMode;
            // OperationalMode opMode = OperationalMode.ImageMode; // This also works. Strange. Because in TD it mentions that When operating in image mode, the Encode Headers messages (section 2.2.2.2) MUST always precede an encoded frame. When operating in video mode, the header messages MUST be present at the beginning of the stream and MAY be present elsewhere.
            EntropyAlgorithm enAlgorithm = EntropyAlgorithm.CLW_ENTROPY_RLGR1;
            ushort destLeft = 0; //the left bound of the frame.
            ushort destTop = 0; //the top bound of the frame.

            //Check if the above setting is supported by client.
            if (!this.rdprfxAdapter.CheckIfClientSupports(opMode, enAlgorithm))
            {
                this.TestSite.Log.Add(LogEntryKind.Comment, "the input pair of Operational Mode ({0}) / Entropy Algorithm ({1}) is not supported by client, so stop running this test case.", opMode, enAlgorithm);
                return;
            }

            this.TestSite.Log.Add(LogEntryKind.Comment, "Sending Frame Marker Command (Begin) with frameID: {0}.", frameId);
            rdpbcgrAdapter.SendFrameMarkerCommand(frameAction_Values.SURFACECMD_FRAMEACTION_BEGIN, frameId);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Create a rectangle whose width and height is TileSize * 2.");
            Rectangle clipRect = new Rectangle(destLeft, destTop, RgbTile.TileSize * 2, RgbTile.TileSize * 2);
            Rectangle[] rects = new Rectangle[] { clipRect };

            uint surfFrameId = 0;

            rdprfxAdapter.SendTsRfxSync();
            rdprfxAdapter.SendTsRfxCodecVersions();
            rdprfxAdapter.SendTsRfxChannels(RgbTile.TileSize * 2, RgbTile.TileSize * 2);
            rdprfxAdapter.SendTsRfxContext(opMode, enAlgorithm);

            rdprfxAdapter.SendTsRfxFrameBegin(surfFrameId++);
            rdprfxAdapter.SendTsRfxRegion(rects);

            TILE_POSITION[] positions = new TILE_POSITION[4]{
                new TILE_POSITION{ xIdx = 0, yIdx = 0 },
                new TILE_POSITION{ xIdx = 0, yIdx = 1 },
                new TILE_POSITION{ xIdx = 1, yIdx = 0 },
                new TILE_POSITION{ xIdx = 1, yIdx = 1 }
            };

            var bitmapBlue = new Bitmap(RgbTile.TileSize, RgbTile.TileSize);
            Graphics graphics = Graphics.FromImage(bitmapBlue);
            graphics.FillRectangle(Brushes.Blue, new Rectangle(0, 0, RgbTile.TileSize, RgbTile.TileSize));
            var bitmapRed = new Bitmap(RgbTile.TileSize, RgbTile.TileSize);
            graphics = Graphics.FromImage(bitmapRed);
            graphics.FillRectangle(Brushes.Red, new Rectangle(0, 0, RgbTile.TileSize, RgbTile.TileSize));

            rdprfxAdapter.SendTsRfxTileSet(
                opMode,
                enAlgorithm,
                new Image[] { bitmapBlue, bitmapBlue, bitmapBlue, bitmapBlue },
                positions);
            rdprfxAdapter.SendTsRfxFrameEnd();
            rdprfxAdapter.FlushEncodedData(destLeft, destTop, RgbTile.TileSize * 2, RgbTile.TileSize * 2);

            System.Threading.Thread.Sleep(1000);

            rdprfxAdapter.SendTsRfxFrameBegin(surfFrameId++);
            rdprfxAdapter.SendTsRfxRegion(rects);
            positions = new TILE_POSITION[3]{
                new TILE_POSITION{ xIdx = 0, yIdx = 1 },
                new TILE_POSITION{ xIdx = 1, yIdx = 0 },
                new TILE_POSITION{ xIdx = 1, yIdx = 1 }
            };

            rdprfxAdapter.SendTsRfxTileSet(
                opMode,
                enAlgorithm,
                new Image[] { bitmapRed, bitmapRed, bitmapRed },
                positions);
            rdprfxAdapter.SendTsRfxFrameEnd();
            rdprfxAdapter.FlushEncodedData(destLeft, destTop, RgbTile.TileSize * 2, RgbTile.TileSize * 2);

            System.Threading.Thread.Sleep(1000);

            rdprfxAdapter.SendTsRfxFrameBegin(surfFrameId++);
            rdprfxAdapter.SendTsRfxRegion(rects);

            positions = new TILE_POSITION[1]{
                new TILE_POSITION{ xIdx = 0, yIdx = 0 }
            };

            rdprfxAdapter.SendTsRfxTileSet(
                opMode,
                enAlgorithm,
                new Image[] { bitmapRed },
                positions);
            rdprfxAdapter.SendTsRfxFrameEnd();
            rdprfxAdapter.FlushEncodedData(destLeft, destTop, RgbTile.TileSize * 2, RgbTile.TileSize * 2);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Sending Frame Marker Command (End) with frameID: {0}.", frameId);
            rdpbcgrAdapter.SendFrameMarkerCommand(frameAction_Values.SURFACECMD_FRAMEACTION_END, frameId);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Expecting TS_FRAME_ACKNOWLEDGE_PDU.");
            rdprfxAdapter.ExpectTsFrameAcknowledgePdu(frameId, waitTime);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Verify output on SUT Display if the verifySUTDisplay entry in PTF config is true.");
            Rectangle compareRect = new Rectangle(destLeft, destTop, RgbTile.TileSize * 2, RgbTile.TileSize * 2);
            this.VerifySUTDisplay(true, compareRect);

            #endregion
        }
        /// <summary>
        /// Method to send TS_RFX_TILESET to client.
        /// </summary>
        /// <param name="opMode">Indicates the operational mode.</param>
        /// <param name="entropy">Indicates the entropy algorithm.</param>
        /// <param name="tileImages">The image array for tiles to be sent. The width and height must be less than or equals with 64.</param>
        /// <param name="positions">A TILE_POSITION array indicating the positions of each tile images</param>
        /// <param name="codecQuantVals">Quant values array</param>
        /// <param name="quantIdxYs">Index array of Y component in Quant value array</param>
        /// <param name="quantIdxCbs">Index array of Cb component in Quant value array</param>
        /// <param name="quantIdxCrs">Index array of Cr component in Quant value array</param>
        public void SendTsRfxTileSet(OperationalMode opMode, EntropyAlgorithm entropy, Image[] tileImages, TILE_POSITION[] positions,
            TS_RFX_CODEC_QUANT[] codecQuantVals = null, byte[] quantIdxYs = null, byte[] quantIdxCbs = null, byte[] quantIdxCrs = null)
        {
            this.admEntropyAlgorithm = entropy;
            this.admOperationMode = opMode;
            TS_RFX_TILESET rfxTileSet = rdprfxServer.CreateTsRfxTileSet(opMode, entropy, tileImages, positions, codecQuantVals, quantIdxYs, quantIdxCbs, quantIdxCrs);
            if (this.currentTestType == RdprfxNegativeType.TsRfxTileSet_InvalidIdx)
            {
                rfxTileSet.idx = 0x0001; //set to an invalid value other than 0x0000.
            }
            else if (this.currentTestType == RdprfxNegativeType.TsRfxTileSet_InvalidLt)
            {
                rfxTileSet.properties &= 0xFFFE; //set "lt" to an invalid value: 0x0.
            }
            else if (this.currentTestType == RdprfxNegativeType.TsRfxTileSet_InvalidCct)
            {
                rfxTileSet.properties &= 0xFFCF; //set "cct" to an invalid value: 0x0.
            }
            else if (this.currentTestType == RdprfxNegativeType.TsRfxTileSet_InvalidXft)
            {
                rfxTileSet.properties &= 0xFC3F; //set "xft" to an invalid value: 0x0.
            }
            else if (this.currentTestType == RdprfxNegativeType.TsRfxTileSet_InvalidQt)
            {
                rfxTileSet.properties &= 0x3FFF; //set "xft" to an invalid value: 0x0.
            }
            else if (this.currentTestType == RdprfxNegativeType.TsRfxTileSet_InvalidTileSize)
            {
                rfxTileSet.tileSize = 0x80; //set to an invalid value other than 0x40.
            }

            if (this.rdpbcgrAdapter.SimulatedScreen != null)
            {
                this.rdpbcgrAdapter.SimulatedScreen.SetRemoteFXTileSet(rfxTileSet, entropy);
            }

            AddToPendingList(rfxTileSet);
            if (!CheckIfClientSupports(opMode, entropy))
            {
                Site.Log.Add(LogEntryKind.Debug, "The client Cap is not supported: OperationalMode = {0}, EntropyAlgorithm = {1}",
                    opMode.ToString(),
                    entropy.ToString());
            }
        }
        /// <summary>
        /// Method to create TS_RFX_TILESET.
        /// </summary>
        /// <param name="opMode">Indicates the operational mode.</param>
        /// <param name="entropy">Indicates the entropy algorithm.</param>
        /// <param name="tileImages">An array of bitmaps in Image type for a tile. The width and heigth must be less than or equals with 64.</param>
        /// <param name="positions">A TILE_POSITION array indicating the positions of each tile images</param>
        /// <param name="codecQuantVals">Quant values array</param>
        /// <param name="quantIdxYs">Index array of Y component in Quant value array</param>
        /// <param name="quantIdxCbs">Index array of Cb component in Quant value array</param>
        /// <param name="quantIdxCrs">Index array of Cr component in Quant value array</param>
        /// <returns></returns>
        public TS_RFX_TILESET CreateTsRfxTileSet(
            OperationalMode opMode,
            EntropyAlgorithm entropy,
            Image[] tileImages,
            TILE_POSITION[] positions,
            TS_RFX_CODEC_QUANT[] codecQuantVals = null,
            byte[] quantIdxYs = null,
            byte[] quantIdxCbs = null,
            byte[] quantIdxCrs = null
            )
        {
            if (codecQuantVals == null)
            {
                codecQuantVals = new TS_RFX_CODEC_QUANT[1];
                codecQuantVals[0] = codecQuant;
            }

            TS_RFX_TILESET rfxTileSet = new TS_RFX_TILESET();
            rfxTileSet.CodecChannelT = new TS_RFX_CODEC_CHANNELT();
            rfxTileSet.CodecChannelT.blockType = blockType_Value.WBT_EXTENSION;
            rfxTileSet.CodecChannelT.blockLen = 22 + 5;
            rfxTileSet.CodecChannelT.codecId = 0x01;
            rfxTileSet.CodecChannelT.channelId = 0x00;
            rfxTileSet.subtype = 0xCAC2;
            rfxTileSet.idx = 0x0000;

            ushort lt = 0x0001;
            ushort flags = 0x0002;
            if (opMode == OperationalMode.VideoMode) flags = 0x0000;
            ushort cct = 0x0001;
            ushort xft = 0x0001;
            ushort et = 0x0001;
            if (entropy == EntropyAlgorithm.CLW_ENTROPY_RLGR3) et = 0x0004;
            ushort qt = 0x0001;
            rfxTileSet.properties = lt;
            rfxTileSet.properties |= (ushort)(flags << 1);
            rfxTileSet.properties |= (ushort)(cct << 4);
            rfxTileSet.properties |= (ushort)(xft << 6);
            rfxTileSet.properties |= (ushort)(et << 10);
            rfxTileSet.properties |= (ushort)(qt << 14);

            rfxTileSet.numQuant = (byte)codecQuantVals.Length;
            rfxTileSet.tileSize = RdprfxServer.TileSize;
            rfxTileSet.numTiles = 1;

            rfxTileSet.quantVals = codecQuantVals;

            byte[] yData, cbData, crData;

            rfxTileSet.tiles = new TS_RFX_TILE[tileImages.Length];
            rfxTileSet.numTiles = (ushort) rfxTileSet.tiles.Length;

            for (int i = 0; i < tileImages.Length; i++)
            {
                byte quantIdxY = quantIdxYs == null ? (byte)0 : (quantIdxYs.Length > i ? quantIdxYs[i] : (byte)0);
                byte quantIdxCb = quantIdxCbs == null ? (byte)0 : (quantIdxCbs.Length > i ? quantIdxCbs[i] : (byte)0);
                byte quantIdxCr = quantIdxCrs == null ? (byte)0 : (quantIdxCrs.Length > i ? quantIdxCrs[i] : (byte)0);

                RemoteFXCodecContext encodingContext = new RemoteFXCodecContext(codecQuantVals, quantIdxY, quantIdxCb, quantIdxCr, entropy);
                RemoteFXEncoder.EncodeTile(tileImages[i], 0, 0, encodingContext);
                yData = encodingContext.YData;
                cbData = encodingContext.CbData;
                crData = encodingContext.CrData;

                rfxTileSet.tiles[i].BlockT.blockType = blockType_Value.CBT_TILE;
                rfxTileSet.tiles[i].BlockT.blockLen = (uint)(19 + yData.Length + cbData.Length + crData.Length);
                rfxTileSet.tiles[i].quantIdxY = quantIdxY;
                rfxTileSet.tiles[i].quantIdxCb = quantIdxCb;
                rfxTileSet.tiles[i].quantIdxCr = quantIdxCr;
                rfxTileSet.tiles[i].xIdx = positions[i].xIdx;
                rfxTileSet.tiles[i].yIdx = positions[i].yIdx;
                rfxTileSet.tiles[i].YLen = (ushort)yData.Length;
                rfxTileSet.tiles[i].CbLen = (ushort)cbData.Length;
                rfxTileSet.tiles[i].CrLen = (ushort)crData.Length;
                rfxTileSet.tiles[i].YData = yData;
                rfxTileSet.tiles[i].CbData = cbData;
                rfxTileSet.tiles[i].CrData = crData;

                rfxTileSet.tilesDataSize += rfxTileSet.tiles[i].BlockT.blockLen;
                rfxTileSet.CodecChannelT.blockLen = (uint)(22 + 5 * rfxTileSet.numQuant + rfxTileSet.tilesDataSize);
            }

            return rfxTileSet;
        }