blob: 63ca73eebfc38305288fe8f5835c22bd0e843177
1 | /* ***** BEGIN LICENSE BLOCK ***** |
2 | * Source last modified: $Id: rasl.c,v 1.1.1.1.2.1 2005/05/04 18:21:33 hubbe Exp $ |
3 | * |
4 | * REALNETWORKS CONFIDENTIAL--NOT FOR DISTRIBUTION IN SOURCE CODE FORM |
5 | * Portions Copyright (c) 1995-2005 RealNetworks, Inc. |
6 | * All Rights Reserved. |
7 | * |
8 | * The contents of this file, and the files included with this file, |
9 | * are subject to the current version of the Real Format Source Code |
10 | * Porting and Optimization License, available at |
11 | * https://helixcommunity.org/2005/license/realformatsource (unless |
12 | * RealNetworks otherwise expressly agrees in writing that you are |
13 | * subject to a different license). You may also obtain the license |
14 | * terms directly from RealNetworks. You may not use this file except |
15 | * in compliance with the Real Format Source Code Porting and |
16 | * Optimization License. There are no redistribution rights for the |
17 | * source code of this file. Please see the Real Format Source Code |
18 | * Porting and Optimization License for the rights, obligations and |
19 | * limitations governing use of the contents of the file. |
20 | * |
21 | * RealNetworks is the developer of the Original Code and owns the |
22 | * copyrights in the portions it created. |
23 | * |
24 | * This file, and the files included with this file, is distributed and |
25 | * made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, |
26 | * EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL |
27 | * SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF |
28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT |
29 | * OR NON-INFRINGEMENT. |
30 | * |
31 | * Technology Compatibility Kit Test Suite(s) Location: |
32 | * https://rarvcode-tck.helixcommunity.org |
33 | * |
34 | * Contributor(s): |
35 | * |
36 | * ***** END LICENSE BLOCK ***** */ |
37 | |
38 | #include <memory.h> |
39 | #include "helix_types.h" |
40 | #include "rasl.h" |
41 | |
42 | /* |
43 | * The interleave table was created with the following properties: |
44 | * -equal contributions from each block |
45 | * -symmetric (if table[i] = j, then table[j] = i), allows in-place interleave |
46 | * -random spacing between lost frames, except |
47 | * -no double losses |
48 | * Solution was generated by a random-walk optimization loop. |
49 | * |
50 | */ |
51 | /* Loss patterns for a five-block solution: |
52 | ...X..X....X.X.....X.X.X........X..........X...X.X....X........X..X..X..X....... |
53 | .X..X....X........X...X..X.....X.X........X...X....X...X..X......X....X.......X. |
54 | ..X..X.X.........X..........X.X...X...X..X...X.......X.....X.X.....X......X.X... |
55 | ..........X.X..X....X......X.X......X...X...X...X.X.....X.....X.X......X.X...... |
56 | X.......X.....X.X.......X.X........X.X.X............X....X..X.......X......X.X.X |
57 | */ |
58 | /* |
59 | static int RASL_InterleaveTable[RASL_NFRAMES * RASL_NBLOCKS] = { |
60 | 66, 21, 43, 3, 23, 47, 6, 32, 72, 19, 49, 11, 54, 13, 69, 63, |
61 | 65, 42, 18, 9, 58, 1, 22, 4, 78, 25, 70, 51, 33, 55, 46, 31, |
62 | 7, 28, 34, 74, 61, 76, 38, 67, 59, 41, 17, 2, 53, 45, 30, 5, |
63 | 48, 10, 50, 27, 71, 44, 12, 29, 56, 73, 20, 40, 64, 36, 62, 15, |
64 | 60, 16, 0, 39, 68, 14, 26, 52, 8, 57, 35, 75, 37, 77, 24, 79 |
65 | }; |
66 | */ |
67 | |
68 | /* Loss pattern for a six-block solution |
69 | ....X.X....X..........X........X....X..X....X........X....X....X....X....X.......X....X...X..... |
70 | .X.....X..........X....X...X..X...X...........X...X...X..X...........X.X...X............X.....X. |
71 | ..X.......X..X......X...X............X...X.....X........X..X.....X....X...X..........X.X....X... |
72 | X........X.....X.X........X..X..........X....X......X.......X.X.............X..X.........X...X.X |
73 | ............X.X.X....X......X...X..X.......X....X............X..X.X.....X.....X.X..X............ |
74 | ...X.X..X..........X.....X.......X....X...X......X.X...X...........X.........X....X.X......X.... |
75 | */ |
76 | static const int RASL_InterleaveTable[RASL_NFRAMES * RASL_NBLOCKS] = { |
77 | 63, 22, 44, 90, 4, 81, 6, 31, 86, 58, 36, 11, 68, 39, 73, 53, |
78 | 69, 57, 18, 88, 34, 71, 1, 23, 46, 94, 54, 27, 75, 50, 30, 7, |
79 | 70, 92, 20, 74, 10, 37, 85, 13, 56, 41, 87, 65, 2, 59, 24, 47, |
80 | 79, 93, 29, 89, 52, 15, 26, 95, 40, 17, 9, 45, 60, 76, 62, 0, |
81 | 64, 43, 66, 83, 12, 16, 32, 21, 72, 14, 35, 28, 61, 80, 78, 48, |
82 | 77, 5, 82, 67, 84, 38, 8, 42, 19, 51, 3, 91, 33, 49, 25, 55 |
83 | }; |
84 | |
85 | /* |
86 | * DeInterleave operates in-place!. |
87 | * |
88 | * Entry: |
89 | * buf points to NCODEBYTES * NFRAMES * NBLOCKS bytes of interleaved data. |
90 | * If an input block is bad, flag[block] should be set. |
91 | * |
92 | * Exit: |
93 | * data in buf is deinterleaved. |
94 | * flags[block] stores a bit array for each output block, |
95 | * where (flags[block] & (1 << F)) is set if Fth frame is bad. |
96 | */ |
97 | void |
98 | RASL_DeInterleave(char *buf, unsigned long ulBufSize, int type, ULONG32 * pFlags) |
99 | { |
100 | char temp[RASL_MAXCODEBYTES]; /* space for swapping */ /* Flawfinder: ignore */ |
101 | INT32 inFlags[RASL_NBLOCKS]; /* save input flags */ |
102 | int nCodeBytes, nCodeBits; |
103 | int fi, fo; /* frame in/out */ |
104 | int blk; |
105 | int bitOffsetTo, bitOffsetFrom; /* for bit maniputlations */ |
106 | char *toPtr, *fromPtr; /* for bit maniputlations */ |
107 | unsigned long ulToBufSize; |
108 | unsigned long ulFromBufSize; |
109 | |
110 | nCodeBits = 0; |
111 | if (type == 0) { |
112 | nCodeBits = RA65_NCODEBITS; |
113 | } |
114 | if (type == 1) { |
115 | nCodeBits = RA85_NCODEBITS; |
116 | } |
117 | if (type == 2) { |
118 | nCodeBits = RA50_NCODEBITS; |
119 | } |
120 | if (type == 3) { |
121 | nCodeBits = RA160_NCODEBITS; |
122 | } else { |
123 | // wrong nCodeBits |
124 | while (1) { |
125 | ; |
126 | } |
127 | } |
128 | |
129 | |
130 | /* Save input flags, and initialize output flags */ |
131 | if (pFlags) |
132 | for (blk = 0; blk < RASL_NBLOCKS; blk++) { |
133 | inFlags[blk] = pFlags[blk]; /* save input */ |
134 | pFlags[blk] = 0; /* init output to no error */ |
135 | } |
136 | |
137 | |
138 | if (nCodeBits % 8 == 0) { |
139 | nCodeBytes = nCodeBits >> 3; |
140 | for (fi = 0; fi < RASL_NFRAMES * RASL_NBLOCKS; fi++) { |
141 | |
142 | fo = RASL_InterleaveTable[fi]; /* frame to swap with */ |
143 | /* |
144 | * Note that when (fo == fi), the frame doesn't move, |
145 | * and if (fo < fi), we have swapped it already. |
146 | */ |
147 | if (fo > fi) { /* do the swap if needed */ |
148 | memcpy(temp, buf + fo * nCodeBytes, nCodeBytes); /* Flawfinder: ignore */ |
149 | memcpy(buf + fo * nCodeBytes, buf + fi * nCodeBytes, nCodeBytes); /* Flawfinder: ignore */ |
150 | memcpy(buf + fi * nCodeBytes, temp, nCodeBytes); /* Flawfinder: ignore */ |
151 | } |
152 | |
153 | /* |
154 | * If frame came from bad block, set bit corresponding to new position. |
155 | * Only check one of the swapped pair, since other will be done when |
156 | * fi gets there. |
157 | */ |
158 | if (pFlags && inFlags[RASL_BLOCK_NUM(fi)]) { |
159 | pFlags[RASL_BLOCK_NUM(fo)] |= (1 << RASL_BLOCK_OFF(fo)); |
160 | } |
161 | } |
162 | } else { |
163 | for (fi = 0; fi < RASL_NFRAMES * RASL_NBLOCKS; fi++) { |
164 | |
165 | fo = RASL_InterleaveTable[fi]; /* frame to swap with */ |
166 | /* |
167 | * Note that when (fo == fi), the frame doesn't move, |
168 | * and if (fo < fi), we have swapped it already. |
169 | */ |
170 | if (fo > fi) { /* do the swap if needed */ |
171 | toPtr = temp; |
172 | ulToBufSize = RASL_MAXCODEBYTES; |
173 | fromPtr = buf; |
174 | ulFromBufSize = ulBufSize; |
175 | bitOffsetTo = 0; |
176 | bitOffsetFrom = fo * nCodeBits; |
177 | ra_bitcopy((unsigned char *)toPtr, ulToBufSize, (unsigned char *)fromPtr, ulFromBufSize, bitOffsetTo, bitOffsetFrom, nCodeBits); |
178 | |
179 | toPtr = buf; |
180 | ulToBufSize = ulBufSize; |
181 | fromPtr = buf; |
182 | ulFromBufSize = ulBufSize; |
183 | bitOffsetTo = fo * nCodeBits; |
184 | bitOffsetFrom = fi * nCodeBits; |
185 | ra_bitcopy((unsigned char *)toPtr, ulToBufSize, (unsigned char *)fromPtr, ulFromBufSize, bitOffsetTo, bitOffsetFrom, nCodeBits); |
186 | |
187 | toPtr = buf; |
188 | ulToBufSize = ulBufSize; |
189 | fromPtr = temp; |
190 | ulFromBufSize = RASL_MAXCODEBYTES; |
191 | bitOffsetTo = fi * nCodeBits; |
192 | bitOffsetFrom = 0; |
193 | ra_bitcopy((unsigned char *)toPtr, ulToBufSize, (unsigned char *)fromPtr, ulFromBufSize, bitOffsetTo, bitOffsetFrom, nCodeBits); |
194 | } |
195 | |
196 | /* |
197 | * If frame came from bad block, set bit corresponding to new position. |
198 | * Only check one of the swapped pair, since other will be done when |
199 | * fi gets there. |
200 | */ |
201 | if (pFlags && inFlags[RASL_BLOCK_NUM(fi)]) { |
202 | pFlags[RASL_BLOCK_NUM(fo)] |= (1 << RASL_BLOCK_OFF(fo)); |
203 | } |
204 | } |
205 | } |
206 | } |
207 | |
208 | void ra_bitcopy(unsigned char* toPtr, |
209 | unsigned long ulToBufSize, |
210 | unsigned char* fromPtr, |
211 | unsigned long ulFromBufSize, |
212 | int bitOffsetTo, |
213 | int bitOffsetFrom, |
214 | int numBits) |
215 | { |
216 | unsigned char* pToLimit = toPtr + ulToBufSize; |
217 | unsigned char* pFromLimit = fromPtr + ulFromBufSize; |
218 | int bofMod8, botMod8, nbMod8, eightMinusBotMod8, eightMinusBofMod8, i, iMax; |
219 | unsigned char rightInword, leftInword, *byteOffsetFrom, *byteOffsetTo, |
220 | alignWord, endWord; |
221 | unsigned char lmask[9] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; /* Flawfinder: ignore */ |
222 | unsigned char rmask[9] = {0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; /* Flawfinder: ignore */ |
223 | |
224 | int nibbleAlignFrom, nibbleAlignTo, alignCase = 30; // special case variables |
225 | unsigned char mask[2] = {0x0f, 0xf0}; /* Flawfinder: ignore */ |
226 | |
227 | bofMod8 = bitOffsetFrom & 0x07; // same as %8 |
228 | botMod8 = bitOffsetTo & 0x07; |
229 | nbMod8 = numBits & 0x07; |
230 | eightMinusBofMod8 = 8 - bofMod8; // don't want these evaluated every loop |
231 | eightMinusBotMod8 = 8 - botMod8; |
232 | byteOffsetFrom = fromPtr + (bitOffsetFrom >> 3); |
233 | byteOffsetTo = toPtr + (bitOffsetTo >> 3); |
234 | iMax = (numBits >> 3) - 1; // last output byte not handled inside a loop |
235 | |
236 | if (numBits >> 3 == 0) |
237 | // quick and easy if we have fewer than 8 bits to align |
238 | |
239 | { |
240 | leftInword = *(byteOffsetFrom++); |
241 | rightInword = *(byteOffsetFrom); |
242 | alignWord = (leftInword >> bofMod8) + (rightInword << (eightMinusBofMod8)); |
243 | alignWord &= rmask[nbMod8]; |
244 | |
245 | if (nbMod8 >= eightMinusBotMod8) // have more extra input bits than |
246 | // free space in current output byte |
247 | { |
248 | *(byteOffsetTo) &= rmask[botMod8]; |
249 | *(byteOffsetTo++) += (alignWord << botMod8); |
250 | *(byteOffsetTo) = ((*byteOffsetTo) & lmask[8 - (nbMod8 - eightMinusBotMod8)]) |
251 | + (alignWord >> eightMinusBotMod8); |
252 | } |
253 | |
254 | else // have fewer input bits than free space in current output byte |
255 | // be careful not to overwrite extra bits already in output byte |
256 | { |
257 | endWord = *(byteOffsetTo) & lmask[8 - (nbMod8 + botMod8)]; |
258 | *(byteOffsetTo) &= rmask[botMod8]; |
259 | *(byteOffsetTo) += ((alignWord << botMod8) + endWord); |
260 | } |
261 | return; // finished, return to calling function |
262 | } |
263 | |
264 | if (bitOffsetFrom % 4 == 0 && bitOffsetTo % 4 == 0) |
265 | // byte-packing done here is optimized for the common case of nibble-alignment |
266 | |
267 | { |
268 | nibbleAlignFrom = (bitOffsetFrom & 0x04) >> 2; // 0 implies whole-byte alignment |
269 | nibbleAlignTo = (bitOffsetTo & 0x04) >> 2; // 1 implies half-byte alignment |
270 | |
271 | |
272 | if (nibbleAlignFrom == nibbleAlignTo) // either src and dest both byte-aligned |
273 | // or both half byte-aligned |
274 | if (nibbleAlignFrom == 0) { |
275 | alignCase = 0; |
276 | } else { |
277 | alignCase = 3; |
278 | } |
279 | |
280 | |
281 | if (nibbleAlignFrom != nibbleAlignTo) |
282 | if (nibbleAlignFrom == 0) { |
283 | alignCase = 1; // src aligned, dest half aligned |
284 | } else { |
285 | alignCase = 2; // src half aligned, dest aligned |
286 | } |
287 | |
288 | switch (alignCase) { |
289 | case 0: |
290 | for (i = 0; i < iMax; i++) { |
291 | *byteOffsetTo++ = *byteOffsetFrom++; // copy byte-by-byte directly |
292 | } |
293 | break; |
294 | |
295 | case 1: |
296 | for (i = 0; i < iMax; i++) { // move two nibbles from src to dest each loop |
297 | // shift bits as necessary |
298 | *byteOffsetTo = (*byteOffsetTo & mask[0]) + |
299 | ((*byteOffsetFrom & mask[0]) << 4); |
300 | *++byteOffsetTo = ((*byteOffsetFrom++ & mask[1]) >> 4); |
301 | } |
302 | break; |
303 | |
304 | case 2: |
305 | for (i = 0; i < iMax; i++) { // same as case 1, but shift other direction |
306 | *byteOffsetTo = ((*byteOffsetFrom & mask[1]) >> 4); |
307 | *byteOffsetTo++ += ((*++byteOffsetFrom & mask[0]) << 4); |
308 | } |
309 | break; |
310 | |
311 | case 3: { |
312 | *byteOffsetTo &= mask[0]; // align first nibble, thereafter this is |
313 | *byteOffsetTo += (*byteOffsetFrom & mask[1]); // just like case 0 |
314 | for (i = 0; i < iMax; i++) { |
315 | *++byteOffsetTo = *++byteOffsetFrom; // copy byte-by-byte directly |
316 | } |
317 | } |
318 | break; |
319 | } |
320 | } |
321 | |
322 | else |
323 | // this code can handle all source and destination buffer offsets |
324 | |
325 | { |
326 | // take the first 8 desired bits from the input buffer, store them |
327 | // in alignWord, then break up alignWord into two pieces to |
328 | // fit in the free space in two consecutive output buffer bytes |
329 | |
330 | for (i = 0; i < iMax; i++) { |
331 | leftInword = *(byteOffsetFrom++); |
332 | rightInword = *(byteOffsetFrom); |
333 | alignWord = (leftInword >> bofMod8) + (rightInword << (eightMinusBofMod8)); |
334 | *(byteOffsetTo) = (*(byteOffsetTo) & rmask[botMod8]) + |
335 | (alignWord << (botMod8)); |
336 | *(++byteOffsetTo) = alignWord >> (eightMinusBotMod8); |
337 | } |
338 | } |
339 | // special section to set last byte in fromBuf correctly |
340 | |
341 | // even if byte packing was done with the code optimized for nibble-alignment, |
342 | // the tricky job of setting the last output byte is still done here |
343 | |
344 | leftInword = *(byteOffsetFrom++); |
345 | rightInword = *(byteOffsetFrom); |
346 | alignWord = (leftInword >> bofMod8) + (rightInword << (eightMinusBofMod8)); |
347 | *(byteOffsetTo) = (*(byteOffsetTo) & rmask[botMod8]) + |
348 | (alignWord << (botMod8)); |
349 | |
350 | if (nbMod8 >= eightMinusBotMod8) { |
351 | *(++byteOffsetTo) = alignWord >> (eightMinusBotMod8); |
352 | |
353 | leftInword = *(byteOffsetFrom++); |
354 | rightInword = *(byteOffsetFrom); |
355 | alignWord = (leftInword >> bofMod8) + (rightInword << (eightMinusBofMod8)); |
356 | alignWord &= rmask[nbMod8]; |
357 | *(byteOffsetTo++) += (alignWord << botMod8); |
358 | if (byteOffsetTo >= toPtr && byteOffsetTo < pToLimit) { |
359 | *(byteOffsetTo) = ((*byteOffsetTo) & lmask[8 - (nbMod8 - eightMinusBotMod8)]) |
360 | + (alignWord >> eightMinusBotMod8); |
361 | } |
362 | } |
363 | |
364 | else { |
365 | endWord = *(++byteOffsetTo) & lmask[8 - (nbMod8 + botMod8)]; |
366 | *(byteOffsetTo) = alignWord >> (eightMinusBotMod8); |
367 | leftInword = *(byteOffsetFrom++); |
368 | rightInword = *(byteOffsetFrom); |
369 | alignWord = (leftInword >> bofMod8) + (rightInword << (eightMinusBofMod8)); |
370 | alignWord &= rmask[nbMod8]; |
371 | *(byteOffsetTo) += ((alignWord << botMod8) + endWord); |
372 | } |
373 | |
374 | |
375 | } |
376 | |
377 |