1:  // ------------------------------------------------------------------------------
   2:  // Copyright (c) Microsoft Corporation. All rights reserved.
   3:  // ------------------------------------------------------------------------------
   4:   
   5:  using System;
   6:  using System.Collections;
   7:  using System.Collections.Generic;
   8:   
   9:  namespace Microsoft.Protocols.TestTools.StackSdk.RemoteDesktop.Rdprfx
  10:  {
  11:      /// <summary>
  12:      /// The RemoteeFX decoder.
  13:      /// </summary>
  14:      public class RemoteFXDecoder
  15:      {
  16:          protected const int DWT_PREC = 4;
  17:          protected const int TileSize = 64;
  18:   
  19:          #region public methods
  20:   
  21:          /// <summary>
  22:          /// Decode the tile data
  23:          /// </summary>
  24:          /// <param name="codecContext">The decoding context</param>
  25:          /// <param name="yData">The Y data to be decoded.</param>
  26:          /// <param name="cbData">The Cb data to be decoded.</param>
  27:          /// <param name="crData">The Cr data to be decoded.</param>
  28:          public static void DecodeTile(RemoteFXCodecContext codecContext, byte[] yData, byte[] cbData, byte[] crData)
  29:          {
  30:              //Load the encoded tile data
  31:              FileEncodedData(codecContext, yData, cbData, crData);
  32:   
  33:              //Do ALGR decode
  34:              RLGRDecode(codecContext);
  35:   
  36:              //Do reconstruction
  37:              SubBandReconstruction(codecContext);
  38:   
  39:              //Dequantization
  40:              Dequantization(codecContext);
  41:   
  42:              //Inverse DWT
  43:              InverseDWT(codecContext);
  44:   
  45:              //Color coversion
  46:              YCbCrToRGB(codecContext);
  47:          }
  48:   
  49:   
  50:          //Load encoded data into decoding context
  51:          public static void FileEncodedData(RemoteFXCodecContext codecContext, byte[] yData, byte[] cbData, byte[] crData)
  52:          {
  53:              codecContext.YData = new byte[yData.Length];
  54:              codecContext.CbData = new byte[cbData.Length];
  55:              codecContext.CrData = new byte[crData.Length];
  56:              Array.Copy(yData, codecContext.YData, yData.Length);
  57:              Array.Copy(cbData, codecContext.CbData, cbData.Length);
  58:              Array.Copy(crData, codecContext.CrData, crData.Length);
  59:          }
  60:   
  61:          //RLGR decode
  62:          public static void RLGRDecode(RemoteFXCodecContext codecContext)
  63:          {
  64:              RLGRDecoder decoder = new RLGRDecoder();
  65:              int comLen = TileSize * TileSize;
  66:              codecContext.YComponent = decoder.Decode(codecContext.YData, codecContext.Mode, comLen);
  67:              codecContext.CbComponent = decoder.Decode(codecContext.CbData, codecContext.Mode, comLen);
  68:              codecContext.CrComponent = decoder.Decode(codecContext.CrData, codecContext.Mode, comLen);
  69:          }
  70:   
  71:          //Sub-Band Reconstruction
  72:          public static void SubBandReconstruction(RemoteFXCodecContext codecContext)
  73:          {
  74:              reconstruction_Component(codecContext.YComponent, out codecContext.YSet);
  75:              reconstruction_Component(codecContext.CbComponent, out codecContext.CbSet);
  76:              reconstruction_Component(codecContext.CrComponent, out codecContext.CrSet);
  77:          }
  78:   
  79:          //Dequantization
  80:          public static void Dequantization(RemoteFXCodecContext codecContext)
  81:          {
  82:              dequantization_Component(codecContext.YSet, codecContext.CodecQuantVals[codecContext.QuantIdxY]);
  83:              dequantization_Component(codecContext.CbSet, codecContext.CodecQuantVals[codecContext.QuantIdxCb]);
  84:              dequantization_Component(codecContext.CrSet, codecContext.CodecQuantVals[codecContext.QuantIdxCr]);
  85:          }
  86:   
  87:          //InverseDWT
  88:          public static void InverseDWT(RemoteFXCodecContext codecContext)
  89:          {
  90:              InverseDWT_Component(codecContext.YSet);
  91:              InverseDWT_Component(codecContext.CbSet);
  92:              InverseDWT_Component(codecContext.CrSet);
  93:          }
  94:   
  95:          //YCbCrToRGB
  96:          public static void YCbCrToRGB(RemoteFXCodecContext codecContext)
  97:          {
  98:              YCbCrToRGB(codecContext.YSet, codecContext.CbSet, codecContext.CrSet, out codecContext.RSet, out codecContext.GSet, out codecContext.BSet);
  99:          }
 100:   
 101:   
 102:          public static void getColFrom2DArr<T>(T[,] input2D, out T[] output1D, int xIdx, int len)
 103:          {
 104:              output1D = new T[len];
 105:              for (int i = 0; i < len; i++)
 106:              {
 107:                  output1D[i] = input2D[xIdx, i];
 108:              }
 109:          }
 110:   
 111:          public static void getRowFrom2DArr<T>(T[,] input2D, out T[] output1D, int yIdx, int len)
 112:          {
 113:              output1D = new T[len];
 114:              for (int i = 0; i < len; i++)
 115:              {
 116:                  output1D[i] = input2D[i, yIdx];
 117:              }
 118:          }
 119:   
 120:          #endregion 
 121:   
 122:          #region Private Methods
 123:   
 124:   
 125:          protected static void reconstruction_Component(short[] component1D, out short[,] compontent2D)
 126:          {
 127:              //sequence: HL1, LH1, HH1, HL2, LH2, HH2, HL3, LH3, HH3, and LL3
 128:              //lineOutput = new short[TileSize * TileSize];
 129:              compontent2D = new short[TileSize, TileSize];
 130:   
 131:              int top, left, right, bottom;
 132:              int offset = 0;
 133:   
 134:              for (int i = 0; i <= 2; i++)
 135:              {
 136:                  int levelSize = TileSize >> i;
 137:   
 138:                  //HL
 139:                  top = 0;
 140:                  left = levelSize / 2;
 141:                  right = levelSize - 1;
 142:                  bottom = levelSize / 2 - 1;
 143:                  reconstruction_SubBand(compontent2D, left, top, right, bottom, component1D, ref offset);
 144:   
 145:                  //LH
 146:                  top = levelSize / 2;
 147:                  left = 0;
 148:                  right = levelSize / 2 - 1;
 149:                  bottom = levelSize - 1;
 150:                  reconstruction_SubBand(compontent2D, left, top, right, bottom, component1D, ref offset);
 151:   
 152:                  //HH
 153:                  top = levelSize / 2;
 154:                  left = levelSize / 2;
 155:                  right = levelSize - 1;
 156:                  bottom = levelSize - 1;
 157:                  reconstruction_SubBand(compontent2D, left, top, right, bottom, component1D, ref offset);
 158:              }
 159:   
 160:              //LL
 161:              top = 0;
 162:              left = 0;
 163:              right = TileSize / 8 - 1;
 164:              bottom = TileSize / 8 - 1;
 165:              int llLen = (right - left + 1) * (bottom - top + 1);
 166:              short[] llBand = new short[llLen];
 167:              Array.Copy(component1D, offset, llBand, 0, llLen);
 168:              for (int i = 1; i < llLen; i++)
 169:              {
 170:                  llBand[i] = (short)(llBand[i - 1] + llBand[i]);
 171:              }
 172:              int llOffset = 0;
 173:              reconstruction_SubBand(compontent2D, left, top, right, bottom, llBand, ref llOffset);
 174:          }
 175:   
 176:          private static void reconstruction_SubBand(short[,] input, int left, int top, int right, int bottom, short[] bandOutput, ref int offset)
 177:          {
 178:              //int totalNum = (right - left + 1) * (bottom - top + 1);
 179:              //bandOutput = new short[totalNum];
 180:              for (int y = top; y <= bottom; y++)
 181:              {
 182:                  for (int x = left; x <= right; x++)
 183:                  {
 184:                      input[x, y] = bandOutput[offset++];
 185:                  }
 186:              }
 187:          }
 188:   
 189:          protected static void dequantization_Component(short[,] compontent, TS_RFX_CODEC_QUANT tsRfxCodecQuant)
 190:          {
 191:              // Quantization factor: HL1, LH1, HH1, HL2, LH2, HH2, HL3, LH3, HH3, LL3            
 192:              Hashtable scaleValueTable = new Hashtable();
 193:              int HL1_Factor = tsRfxCodecQuant.HL1_HH1 & 0x0f;
 194:              int LH1_Factor = (tsRfxCodecQuant.HH2_LH1 & 0xf0) >> 4;
 195:              int HH1_Factor = (tsRfxCodecQuant.HL1_HH1 & 0xf0) >> 4;
 196:              int HL2_Factor = (tsRfxCodecQuant.LH2_HL2 & 0xf0) >> 4;
 197:              int LH2_Factor = tsRfxCodecQuant.LH2_HL2 & 0x0f;
 198:              int HH2_Factor = tsRfxCodecQuant.HH2_LH1 & 0x0f;
 199:              int HL3_Factor = tsRfxCodecQuant.HL3_HH3 & 0x0f;
 200:              int LH3_Factor = (tsRfxCodecQuant.LL3_LH3 & 0xf0) >> 4;
 201:              int HH3_Factor = (tsRfxCodecQuant.HL3_HH3 & 0xf0) >> 4;
 202:              int LL3_Factor = tsRfxCodecQuant.LL3_LH3 & 0x0f;
 203:              int[] HL_Factor = { HL1_Factor, HL2_Factor, HL3_Factor };
 204:              int[] LH_Factor = { LH1_Factor, LH2_Factor, LH3_Factor };
 205:              int[] HH_Factor = { HH1_Factor, HH2_Factor, HH3_Factor };
 206:   
 207:              int top, left, right, bottom;
 208:   
 209:              //Level 1, 2, 3
 210:              for (int i = 0; i <= 2; i++)
 211:              {
 212:                  int levelSize = TileSize >> i;
 213:   
 214:                  //HL1,2,3
 215:                  top = 0;
 216:                  left = levelSize / 2;
 217:                  right = levelSize - 1;
 218:                  bottom = levelSize / 2 - 1;
 219:                  doDequantization_Subband(compontent, left, top, right, bottom, HL_Factor[i]);
 220:   
 221:                  //LH1,2,3
 222:                  top = levelSize / 2;
 223:                  left = 0;
 224:                  right = levelSize / 2 - 1;
 225:                  bottom = levelSize - 1;
 226:                  doDequantization_Subband(compontent, left, top, right, bottom, LH_Factor[i]);
 227:   
 228:                  //HH1,2,3
 229:                  top = levelSize / 2;
 230:                  left = levelSize / 2;
 231:                  right = levelSize - 1;
 232:                  bottom = levelSize - 1;
 233:                  doDequantization_Subband(compontent, left, top, right, bottom, HH_Factor[i]);
 234:              }
 235:              //LL3
 236:              top = 0;
 237:              left = 0;
 238:              right = TileSize / 8 - 1;
 239:              bottom = TileSize / 8 - 1;
 240:              doDequantization_Subband(compontent, left, top, right, bottom, LL3_Factor);
 241:          }
 242:   
 243:          private static void doDequantization_Subband(short[,] input, int left, int top, int right, int bottom, int factor)
 244:          {
 245:              for (int x = left; x <= right; x++)
 246:              {
 247:                  for (int y = top; y <= bottom; y++)
 248:                  {
 249:                      input[x, y] = (short)(input[x, y] << (factor - 6));//<< DWT_PREC);
 250:                  }
 251:              }
 252:          }
 253:   
 254:          protected static void InverseDWT_Component(short[,] component)
 255:          {
 256:              //Level 3, 2, 1
 257:              InverseDWT_2D(component, 3);
 258:              InverseDWT_2D(component, 2);
 259:              InverseDWT_2D(component, 1);
 260:          }
 261:   
 262:          private static void InverseDWT_2D(short[,] data2D, int level)
 263:          {
 264:              //level > 0
 265:              //data2D.Length % (1<<(level - 1)) == 0
 266:              int inScopelen = TileSize >> (level - 1);
 267:   
 268:              //Horizontal DWT
 269:              for (int y = 0; y < inScopelen; y++)
 270:              {
 271:                  short[] row;
 272:                  getRowFrom2DArr<short>(data2D, out row, y, inScopelen);
 273:                  row = InverseDWT_1D(row);
 274:                  for (int x = 0; x < inScopelen; x++)
 275:                  {
 276:                      data2D[x, y] = row[x];
 277:                  }
 278:              }
 279:   
 280:              //Vertical DWT
 281:              for (int x = 0; x < inScopelen; x++)
 282:              {
 283:                  short[] col;
 284:                  getColFrom2DArr<short>(data2D, out col, x, inScopelen);
 285:                  col = InverseDWT_1D(col);
 286:                  for (int y = 0; y < inScopelen; y++)
 287:                  {
 288:                      data2D[x, y] = col[y];
 289:                  }
 290:              }
 291:   
 292:          }
 293:          
 294:          private static short[] InverseDWT_1D(short[] encodedData)
 295:          {
 296:              int hOffset = encodedData.Length / 2;
 297:              short[] decodedData = new short[encodedData.Length];
 298:              for (int i = 1; 2 * i < encodedData.Length; i++)
 299:              {
 300:                  //X[2n] = L[n] - (H[n-1] + H[n] + 1) / 2
 301:                  decodedData[2 * i] = (short)Math.Round(encodedData[i] - (encodedData[hOffset + i - 1] + encodedData[hOffset + i] + 1.0f) / 2);
 302:              }
 303:   
 304:              for (int i = 1; 2 * i + 2 < encodedData.Length; i++)
 305:              {
 306:                  //X[2n + 1] = 2*H[n] + (X[2n] + X[2n + 2])/2
 307:                  decodedData[2 * i + 1] = (short)Math.Round(2 * encodedData[hOffset + i] + (decodedData[2 * i] + decodedData[2 * i + 2] + 0.0f) / 2);
 308:              }
 309:   
 310:              //Handle X[0], [1], [len-1]
 311:              //H(-1) = H[0]
 312:              decodedData[0] = (short)Math.Round(encodedData[0] - (encodedData[hOffset] + encodedData[hOffset] + 1.0f) / 2);
 313:              decodedData[1] = (short)Math.Round(2 * encodedData[hOffset] + (decodedData[0] + decodedData[2] + 0.0f) / 2);
 314:              decodedData[decodedData.Length - 1] = (short)(2 * encodedData[hOffset + hOffset - 1] + decodedData[decodedData.Length - 2]);
 315:              return decodedData;
 316:          }
 317:   
 318:          protected static void YCbCrToRGB(short[,] ySet, short[,] cbSet, short[,] crSet, out byte[,] rSet, out byte[,] gSet, out byte[,] bSet)
 319:          {
 320:              rSet = new byte[TileSize, TileSize];
 321:              gSet = new byte[TileSize, TileSize];
 322:              bSet = new byte[TileSize, TileSize];
 323:   
 324:              for (int x = 0; x < TileSize; x++)
 325:              {
 326:                  for (int y = 0; y < TileSize; y++)
 327:                  {
 328:                      byte[] rgb = yuvToRGB(ySet[x, y], cbSet[x, y], crSet[x, y]);
 329:                      rSet[x, y] = rgb[0];
 330:                      gSet[x, y] = rgb[1];
 331:                      bSet[x, y] = rgb[2];
 332:                  }
 333:              }
 334:          }
 335:   
 336:          private static byte[] yuvToRGB(short y, short cb, short cr)
 337:          {
 338:              byte[] rgb = new byte[3];
 339:   
 340:              double yF = (y + 128.0f);
 341:              double cbF = cb;
 342:              double crF = cr;
 343:   
 344:              short r = (short)Math.Round((yF * 1.0 + cbF * 0 + crF * 1.403)); //R
 345:              short g = (short)Math.Round((yF * 1.0 + cbF * (-0.344) + crF * (-0.714)));
 346:              short b = (short)Math.Round((yF * 1.0 + cbF * 1.77 + crF * 0.0));
 347:   
 348:              if (r > 255) r = 255;
 349:              if (r < 0) r = 0;
 350:              if (g > 255) g = 255;
 351:              if (g < 0) g = 0;
 352:              if (b > 255) b = 255;
 353:              if (b < 0) b = 0;
 354:   
 355:              rgb[0] = (byte)r;
 356:              rgb[1] = (byte)g;
 357:              rgb[2] = (byte)b;
 358:   
 359:              return rgb;
 360:          }
 361:          
 362:          #endregion
 363:      
 364:      }
 365:   
 366:  }