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: }