1: // ------------------------------------------------------------------------------
2: // Copyright (c) Microsoft Corporation. All rights reserved.
3: // ------------------------------------------------------------------------------
4:
5: using System;
6: using System.Collections;
7: using System.Collections.Generic;
8: using System.Drawing;
9: using System.Drawing.Imaging;
10:
11: namespace Microsoft.Protocols.TestTools.StackSdk.RemoteDesktop.Rdprfx
12: {
13: /// <summary>
14: /// The RemoteFX encoder
15: /// </summary>
16: public class RemoteFXEncoder
17: {
18: protected const int DWT_PREC = 4;
19: protected const int TileSize = 64;
20:
21:
22: #region public Methods
23:
24: /// <summary>
25: /// Encode a tile from a image.
26: /// </summary>
27: /// <param name="image">The input image.</param>
28: /// <param name="leftOffset">The left offset of the tile.</param>
29: /// <param name="topOffset">The top offset of the tile.</param>
30: /// <param name="encodingContext">The encoding context.</param>
31: public static void EncodeTile(Image image, int leftOffset, int topOffset, RemoteFXCodecContext encodingContext)
32: {
33:
34: //Initialize the encoding context
35: GetTileData(image, leftOffset, topOffset, encodingContext);
36:
37: //Do color conversion
38: RGBToYCbCr(encodingContext);
39:
40: //Do three level DWT
41: DWT(encodingContext);
42:
43: //Do quantiztion
44: Quantization(encodingContext);
45:
46: //Do linearization
47: Linearization(encodingContext);
48:
49: //ALRG encode
50: RLGREncode(encodingContext);
51: }
52:
53: /// <summary>
54: /// Encode a tile from a image.
55: /// </summary>
56: /// <param name="image">The input RgbTile.</param>
57: /// <param name="leftOffset">The left offset of the tile.</param>
58: /// <param name="topOffset">The top offset of the tile.</param>
59: /// <param name="encodingContext">The encoding context.</param>
60: public static void EncodeTile(RgbTile tile, int leftOffset, int topOffset, RemoteFXCodecContext encodingContext)
61: {
62:
63: //Initialize the encoding context
64: encodingContext.RSet = tile.RSet;
65: encodingContext.GSet = tile.GSet;
66: encodingContext.BSet = tile.BSet;
67:
68: //Do color conversion
69: RGBToYCbCr(encodingContext);
70:
71: //Do three level DWT
72: DWT(encodingContext);
73:
74: //Do quantiztion
75: Quantization(encodingContext);
76:
77: //Do linearization
78: Linearization(encodingContext);
79:
80: //ALRG encode
81: RLGREncode(encodingContext);
82: }
83:
84: //Load a tile from image
85: public static void GetTileData(Image image, int leftOffset, int topOffset, RemoteFXCodecContext encodingContext)
86: {
87: Bitmap bitmap = new Bitmap(image);
88: encodingContext.RSet = new byte[TileSize, TileSize];
89: encodingContext.GSet = new byte[TileSize, TileSize];
90: encodingContext.BSet = new byte[TileSize, TileSize];
91:
92: int right = Math.Min(image.Width - 1, leftOffset + TileSize - 1);
93: int bottom = Math.Min(image.Height - 1, topOffset + TileSize - 1);
94:
95: BitmapData bmpData = bitmap.LockBits(new Rectangle(leftOffset, topOffset, right - leftOffset + 1, bottom - topOffset + 1), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
96:
97: unsafe
98: {
99: byte* cusor = (byte*)bmpData.Scan0.ToPointer();
100: for (int y = topOffset; y <= bottom; y++)
101: {
102: for (int x = leftOffset; x <= right; x++)
103: {
104: int tileX = x - leftOffset;
105: int tileY = y - topOffset;
106: encodingContext.BSet[tileX, tileY] = cusor[0];
107: encodingContext.GSet[tileX, tileY] = cusor[1];
108: encodingContext.RSet[tileX, tileY] = cusor[2];
109: cusor += 3;
110: }
111: cusor += (bmpData.Stride - 3 * (bmpData.Width));
112: }
113: }
114: bitmap.UnlockBits(bmpData);
115: }
116:
117: //Color coversion
118: public static void RGBToYCbCr(RemoteFXCodecContext encodingContext)
119: {
120: encodingContext.YSet = new short[TileSize, TileSize];
121: encodingContext.CbSet = new short[TileSize, TileSize];
122: encodingContext.CrSet = new short[TileSize, TileSize];
123: for (int x = 0; x < TileSize; x++)
124: {
125: for (int y = 0; y < TileSize; y++)
126: {
127: short[] yuv = RGBToYCbCr(encodingContext.RSet[x, y], encodingContext.GSet[x, y], encodingContext.BSet[x, y]);
128: encodingContext.YSet[x, y] = yuv[0];
129: encodingContext.CbSet[x, y] = yuv[1];
130: encodingContext.CrSet[x, y] = yuv[2];
131: }
132: }
133: }
134:
135: //DWT
136: public static void DWT(RemoteFXCodecContext encodingContext)
137: {
138: DWT_RomoteFX(encodingContext.YSet);
139: DWT_RomoteFX(encodingContext.CbSet);
140: DWT_RomoteFX(encodingContext.CrSet);
141: }
142:
143: //Quantization
144: public static void Quantization(RemoteFXCodecContext encodingContext)
145: {
146: doQuantization_Component(encodingContext.YSet, encodingContext.CodecQuantVals[encodingContext.QuantIdxY]);
147: doQuantization_Component(encodingContext.CbSet, encodingContext.CodecQuantVals[encodingContext.QuantIdxCb]);
148: doQuantization_Component(encodingContext.CrSet, encodingContext.CodecQuantVals[encodingContext.QuantIdxCr]);
149: }
150:
151: //Linearization
152: public static void Linearization(RemoteFXCodecContext encodingContext)
153: {
154: linearization_Compontent(encodingContext.YSet, out encodingContext.YComponent);
155: linearization_Compontent(encodingContext.CbSet, out encodingContext.CbComponent);
156: linearization_Compontent(encodingContext.CrSet, out encodingContext.CrComponent);
157: }
158:
159: //RLGREncode
160: public static void RLGREncode(RemoteFXCodecContext encodingContext)
161: {
162: RLGREncoder encoder = new RLGREncoder();
163: encodingContext.YData = encoder.Encode(encodingContext.YComponent, encodingContext.Mode);
164: encodingContext.CbData = encoder.Encode(encodingContext.CbComponent, encodingContext.Mode);
165: encodingContext.CrData = encoder.Encode(encodingContext.CrComponent, encodingContext.Mode);
166: }
167:
168:
169: public static void getColFrom2DArr<T>(T[,] input2D, out T[] output1D, int xIdx, int len)
170: {
171: output1D = new T[len];
172: for (int i = 0; i < len; i++)
173: {
174: output1D[i] = input2D[xIdx, i];
175: }
176: }
177:
178: public static void getRowFrom2DArr<T>(T[,] input2D, out T[] output1D, int yIdx, int len)
179: {
180: output1D = new T[len];
181: for (int i = 0; i < len; i++)
182: {
183: output1D[i] = input2D[i, yIdx];
184: }
185: }
186:
187: #endregion
188:
189: #region Private Methods
190:
191:
192:
193: protected static short[] RGBToYCbCr(byte r, byte g, byte b)
194: {
195: short[] yuv = new short[3];
196:
197: float rF = r / 255.0f;
198: float gF = g / 255.0f;
199: float bF = b / 255.0f;
200:
201: float y = 0.299f * rF + 0.587f * gF + 0.114f * bF - 0.5f;
202: float u = -0.168935f * rF - 0.331665f * gF + 0.50059f * bF;// + 0.5f;
203: float v = 0.499813f * rF - 0.418531f * gF - 0.081282f * bF;// + 0.5f;
204:
205: //* 16 == << 4: with 4 fractional bits
206: // yuv[0] = (short)(y * 255.0f * 16);
207: // yuv[1] = (short)(u * 255.0f * 16);
208: // yuv[2] = (short)(v * 255.0f * 16);
209:
210: yuv[0] = (short)(y * 255.0f);
211: yuv[1] = (short)(u * 255.0f);
212: yuv[2] = (short)(v * 255.0f);
213:
214: return yuv;
215: }
216:
217: protected static void DWT_RomoteFX(short[,] data2D)
218: {
219: DWT_2D(data2D, 1);//level 1
220: DWT_2D(data2D, 2);//level 2
221: DWT_2D(data2D, 3);//level 3
222: }
223:
224: /// <summary>
225: /// Quantization
226: /// </summary>
227: /// <param name="component">Y_Set, Cb_Set, Cr_Set</param>
228: /// <param name="tsRfxCodecQuant">TS_RFX_CODEC_QUANT struct stored quantization factor</param>
229: protected static void doQuantization_Component(short[,] component, TS_RFX_CODEC_QUANT tsRfxCodecQuant)
230: {
231: // Quantization factor: HL1, LH1, HH1, HL2, LH2, HH2, HL3, LH3, HH3, LL3
232: Hashtable scaleValueTable = new Hashtable();
233: int HL1_Factor = tsRfxCodecQuant.HL1_HH1 & 0x0f;
234: int LH1_Factor = (tsRfxCodecQuant.HH2_LH1 & 0xf0) >> 4;
235: int HH1_Factor = (tsRfxCodecQuant.HL1_HH1 & 0xf0) >> 4;
236: int HL2_Factor = (tsRfxCodecQuant.LH2_HL2 & 0xf0) >> 4;
237: int LH2_Factor = tsRfxCodecQuant.LH2_HL2 & 0x0f;
238: int HH2_Factor = tsRfxCodecQuant.HH2_LH1 & 0x0f;
239: int HL3_Factor = tsRfxCodecQuant.HL3_HH3 & 0x0f;
240: int LH3_Factor = (tsRfxCodecQuant.LL3_LH3 & 0xf0) >> 4;
241: int HH3_Factor = (tsRfxCodecQuant.HL3_HH3 & 0xf0) >> 4;
242: int LL3_Factor = tsRfxCodecQuant.LL3_LH3 & 0x0f;
243: int[] HL_Factor = { HL1_Factor, HL2_Factor, HL3_Factor };
244: int[] LH_Factor = { LH1_Factor, LH2_Factor, LH3_Factor };
245: int[] HH_Factor = { HH1_Factor, HH2_Factor, HH3_Factor };
246:
247: int top, left, right, bottom;
248:
249: //Level 1, 2, 3
250: for (int i = 0; i <= 2; i++)
251: {
252: int levelSize = TileSize >> i;
253:
254: //HL1,2,3
255: top = 0;
256: left = levelSize / 2;
257: right = levelSize - 1;
258: bottom = levelSize / 2 - 1;
259: doQuantization_Subband(component, left, top, right, bottom, HL_Factor[i]);
260:
261: //LH1,2,3
262: top = levelSize / 2;
263: left = 0;
264: right = levelSize / 2 - 1;
265: bottom = levelSize - 1;
266: doQuantization_Subband(component, left, top, right, bottom, LH_Factor[i]);
267:
268: //HH1,2,3
269: top = levelSize / 2;
270: left = levelSize / 2;
271: right = levelSize - 1;
272: bottom = levelSize - 1;
273: doQuantization_Subband(component, left, top, right, bottom, HH_Factor[i]);
274: }
275: //LL3
276: top = 0;
277: left = 0;
278: right = TileSize / 8 - 1;
279: bottom = TileSize / 8 - 1;
280: doQuantization_Subband(component, left, top, right, bottom, LL3_Factor);
281: }
282:
283: private static short quant(short input, int factor)
284: {
285: short output;
286: // output = (short)(Math.Abs(input) >> ((factor - 6) + 4));
287: output = (short)(Math.Abs(input) >> (factor - 6));
288: if (input < 0) output *= -1;
289: return output;
290: }
291:
292: private static void doQuantization_Subband(short[,] input, int left, int top, int right, int bottom, int factor)
293: {
294: for (int x = left; x <= right; x++)
295: {
296: for (int y = top; y <= bottom; y++)
297: {
298: input[x, y] = quant(input[x, y], factor);
299: }
300: }
301: }
302:
303: protected static void linearization_Compontent(short[,] compontent, out short[] lineOutput)
304: {
305: //sequence: HL1, LH1, HH1, HL2, LH2, HH2, HL3, LH3, HH3, and LL3
306: lineOutput = new short[TileSize * TileSize];
307: int curIdx = 0;
308:
309: int top, left, right, bottom;
310: short[] bandOutput;
311:
312: for (int i = 0; i <= 2; i++)
313: {
314: int levelSize = TileSize >> i;
315:
316: //HL
317: top = 0;
318: left = levelSize / 2;
319: right = levelSize - 1;
320: bottom = levelSize / 2 - 1;
321: linearization_SubBand(compontent, left, top, right, bottom, out bandOutput);
322: Array.Copy(bandOutput, 0, lineOutput, curIdx, bandOutput.Length);
323: curIdx += bandOutput.Length;
324:
325: //LH
326: top = levelSize / 2;
327: left = 0;
328: right = levelSize / 2 - 1;
329: bottom = levelSize - 1;
330: linearization_SubBand(compontent, left, top, right, bottom, out bandOutput);
331: Array.Copy(bandOutput, 0, lineOutput, curIdx, bandOutput.Length);
332: curIdx += bandOutput.Length;
333:
334: //HH
335: top = levelSize / 2;
336: left = levelSize / 2;
337: right = levelSize - 1;
338: bottom = levelSize - 1;
339: linearization_SubBand(compontent, left, top, right, bottom, out bandOutput);
340: Array.Copy(bandOutput, 0, lineOutput, curIdx, bandOutput.Length);
341: curIdx += bandOutput.Length;
342: }
343: //LL
344: top = 0;
345: left = 0;
346: right = TileSize / 8 - 1;
347: bottom = TileSize / 8 - 1;
348: linearization_SubBand(compontent, left, top, right, bottom, out bandOutput);
349: for (int i = bandOutput.Length - 1; i > 0; i--)
350: {
351: bandOutput[i] = (short)(bandOutput[i] - bandOutput[i - 1]);
352: }
353:
354: Array.Copy(bandOutput, 0, lineOutput, curIdx, bandOutput.Length);
355: curIdx += bandOutput.Length;
356: }
357:
358: private static void linearization_SubBand(short[,] input, int left, int top, int right, int bottom, out short[] bandOutput)
359: {
360: int totalNum = (right - left + 1) * (bottom - top + 1);
361: bandOutput = new short[totalNum];
362: int curIdx = 0;
363: for (int y = top; y <= bottom; y++)
364: {
365: for (int x = left; x <= right; x++)
366: {
367: bandOutput[curIdx++] = input[x, y];
368: }
369: }
370: }
371:
372: private static short DWT_H(short[] dataArr, int n)
373: {
374: //n < dataArr.length/2
375: short x2n, x2n1, x2n2;
376: if (n == -1)
377: {
378: x2n = dataArr[2];
379: x2n1 = dataArr[1];
380: x2n2 = dataArr[0];
381: }
382: else
383: {
384: x2n = dataArr[2 * n];
385: x2n1 = dataArr[2 * n + 1];
386: if (2 * n + 2 >= dataArr.Length - 1)
387: {
388: x2n2 = x2n;
389: }
390: else
391: {
392: x2n2 = dataArr[2 * n + 2];
393: }
394: }
395:
396: short result = (short)((x2n1 - (x2n + x2n2 + 0.0f) / 2) / 2);
397: return result;
398: }
399:
400: private static short DWT_L(short[] dataArr, int n)
401: {
402: short result = (short)(dataArr[2 * n] + (DWT_H(dataArr, n - 1) + DWT_H(dataArr, n)) / 2);
403: return result;
404: }
405:
406: private static void DWT(short[] dataArr)
407: {
408: int N = dataArr.Length / 2;
409: short[] hResult = new short[N];
410: short[] lResult = new short[N];
411: for (int i = 0; i < N; i++)
412: {
413: hResult[i] = DWT_H(dataArr, i);
414: lResult[i] = DWT_L(dataArr, i);
415: }
416: for (int i = 0; i < N; i++)
417: {
418: dataArr[i] = lResult[i];
419: dataArr[N + i] = hResult[i];
420: }
421: }
422:
423: private static void DWT_2D(short[,] data2D, int level)
424: {
425: //level > 0
426: //data2D.Length % (1<<(level - 1)) == 0
427: int inScopelen = TileSize >> (level - 1);
428:
429: //Vertical DWT
430: for (int x = 0; x < inScopelen; x++)
431: {
432: short[] col;
433: getColFrom2DArr<short>(data2D, out col, x, inScopelen);
434: DWT(col);
435: for (int y = 0; y < inScopelen; y++)
436: {
437: data2D[x, y] = col[y];
438: }
439: }
440: //Horizontal DWT
441: for (int y = 0; y < inScopelen; y++)
442: {
443: short[] row;
444: getRowFrom2DArr<short>(data2D, out row, y, inScopelen);
445: DWT(row);
446: for (int x = 0; x < inScopelen; x++)
447: {
448: data2D[x, y] = row[x];
449: }
450: }
451: }
452:
453: private static void Convert2Dto1D<T>(T[,] sourceArr, out T[] targetArr, ArrayDirection direction)
454: {
455: int len0 = sourceArr.GetLength(0);
456: int len1 = sourceArr.GetLength(1);
457: int totalLen = len0 * len1;
458:
459: targetArr = new T[totalLen];
460: int idx = 0;
461: if (direction == ArrayDirection.Horizontal)
462: {
463: for (int y = 0; y < len1; y++)
464: {
465: for (int x = 0; x < len0; x++)
466: {
467: targetArr[idx++] = sourceArr[x, y];
468: }
469: }
470: }
471: else
472: {
473: for (int x = 0; x < len0; x++)
474: {
475: for (int y = 0; y < len1; y++)
476: {
477: targetArr[idx++] = sourceArr[x, y];
478: }
479: }
480: }
481: }
482:
483: private static void Convert1Dto2D<T>(T[] sourceArr, int xLen, int yLen, out T[,] targetArr, ArrayDirection direction)
484: {
485: targetArr = new T[xLen, yLen];
486: int curIdx = 0;
487: if (direction == ArrayDirection.Horizontal)
488: {
489: for (int y = 0; y < yLen; y++)
490: {
491: for (int x = 0; x < xLen; x++)
492: {
493: targetArr[x, y] = sourceArr[curIdx++];
494: }
495: }
496: }
497: else
498: {
499: for (int x = 0; x < xLen; x++)
500: {
501: for (int y = 0; y < yLen; y++)
502: {
503: targetArr[x, y] = sourceArr[curIdx++];
504: }
505: }
506: }
507: }
508:
509: private static void RGBToYCbCr(byte[] rSet, byte[] gSet, byte[] bSet, out short[] ySet, out short[] cbSet, out short[] crSet)
510: {
511: ySet = new short[rSet.Length];
512: cbSet = new short[rSet.Length];
513: crSet = new short[rSet.Length];
514:
515: for (int i = 0; i < rSet.Length; i++)
516: {
517: float r = rSet[i] / 255.0f;
518: float g = gSet[i] / 255.0f;
519: float b = bSet[i] / 255.0f;
520:
521: float y = 0.299f * r + 0.587f * g + 0.114f * b - 0.5f;
522: float u = -0.168935f * r - 0.331665f * g + 0.50059f * b;// + 0.5f;
523: float v = 0.499813f * r - 0.418531f * g - 0.081282f * b;// + 0.5f;
524:
525: //<< 4
526: ySet[i] = (short)(y * 255.0f * 16);
527: cbSet[i] = (short)(u * 255.0f * 16);
528: crSet[i] = (short)(v * 255.0f * 16);
529: }
530: }
531:
532: #endregion
533: }
534:
535: }