Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 1 | /* Linux driver for Philips webcam |
| 2 | Decompression for chipset version 2 et 3 |
| 3 | (C) 2004-2006 Luc Saillard (luc@saillard.org) |
| 4 | |
| 5 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx |
| 6 | driver and thus may have bugs that are not present in the original version. |
| 7 | Please send bug reports and support requests to <luc@saillard.org>. |
| 8 | The decompression routines have been implemented by reverse-engineering the |
| 9 | Nemosoft binary pwcx module. Caveat emptor. |
| 10 | |
| 11 | This program is free software; you can redistribute it and/or modify |
| 12 | it under the terms of the GNU General Public License as published by |
| 13 | the Free Software Foundation; either version 2 of the License, or |
| 14 | (at your option) any later version. |
| 15 | |
| 16 | This program is distributed in the hope that it will be useful, |
| 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | GNU General Public License for more details. |
| 20 | |
| 21 | You should have received a copy of the GNU General Public License |
| 22 | along with this program; if not, write to the Free Software |
| 23 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 24 | |
| 25 | */ |
| 26 | |
| 27 | #include "pwc-timon.h" |
| 28 | #include "pwc-kiara.h" |
| 29 | #include "pwc-dec23.h" |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 30 | |
| 31 | #include <linux/string.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 32 | #include <linux/slab.h> |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 33 | |
| 34 | /* |
| 35 | * USE_LOOKUP_TABLE_TO_CLAMP |
| 36 | * 0: use a C version of this tests: { a<0?0:(a>255?255:a) } |
| 37 | * 1: use a faster lookup table for cpu with a big cache (intel) |
| 38 | */ |
| 39 | #define USE_LOOKUP_TABLE_TO_CLAMP 1 |
| 40 | /* |
| 41 | * UNROLL_LOOP_FOR_COPYING_BLOCK |
| 42 | * 0: use a loop for a smaller code (but little slower) |
| 43 | * 1: when unrolling the loop, gcc produces some faster code (perhaps only |
| 44 | * valid for intel processor class). Activating this option, automaticaly |
| 45 | * activate USE_LOOKUP_TABLE_TO_CLAMP |
| 46 | */ |
| 47 | #define UNROLL_LOOP_FOR_COPY 1 |
| 48 | #if UNROLL_LOOP_FOR_COPY |
| 49 | # undef USE_LOOKUP_TABLE_TO_CLAMP |
| 50 | # define USE_LOOKUP_TABLE_TO_CLAMP 1 |
| 51 | #endif |
| 52 | |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 53 | static void build_subblock_pattern(struct pwc_dec23_private *pdec) |
| 54 | { |
| 55 | static const unsigned int initial_values[12] = { |
| 56 | -0x526500, -0x221200, 0x221200, 0x526500, |
| 57 | -0x3de200, 0x3de200, |
| 58 | -0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480, |
| 59 | -0x12c200, 0x12c200 |
| 60 | |
| 61 | }; |
| 62 | static const unsigned int values_derivated[12] = { |
| 63 | 0xa4ca, 0x4424, -0x4424, -0xa4ca, |
| 64 | 0x7bc4, -0x7bc4, |
| 65 | 0xdb69, 0x5aba, -0x5aba, -0xdb69, |
| 66 | 0x2584, -0x2584 |
| 67 | }; |
| 68 | unsigned int temp_values[12]; |
| 69 | int i, j; |
| 70 | |
| 71 | memcpy(temp_values, initial_values, sizeof(initial_values)); |
| 72 | for (i = 0; i < 256; i++) { |
| 73 | for (j = 0; j < 12; j++) { |
| 74 | pdec->table_subblock[i][j] = temp_values[j]; |
| 75 | temp_values[j] += values_derivated[j]; |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | static void build_bit_powermask_table(struct pwc_dec23_private *pdec) |
| 81 | { |
| 82 | unsigned char *p; |
| 83 | unsigned int bit, byte, mask, val; |
| 84 | unsigned int bitpower = 1; |
| 85 | |
| 86 | for (bit = 0; bit < 8; bit++) { |
| 87 | mask = bitpower - 1; |
| 88 | p = pdec->table_bitpowermask[bit]; |
| 89 | for (byte = 0; byte < 256; byte++) { |
| 90 | val = (byte & mask); |
| 91 | if (byte & bitpower) |
| 92 | val = -val; |
| 93 | *p++ = val; |
| 94 | } |
| 95 | bitpower<<=1; |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | |
| 100 | static void build_table_color(const unsigned int romtable[16][8], |
Trent Piepho | 657de3c | 2006-06-20 00:30:57 -0300 | [diff] [blame] | 101 | unsigned char p0004[16][1024], |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 102 | unsigned char p8004[16][256]) |
| 103 | { |
| 104 | int compression_mode, j, k, bit, pw; |
| 105 | unsigned char *p0, *p8; |
| 106 | const unsigned int *r; |
| 107 | |
| 108 | /* We have 16 compressions tables */ |
| 109 | for (compression_mode = 0; compression_mode < 16; compression_mode++) { |
| 110 | p0 = p0004[compression_mode]; |
| 111 | p8 = p8004[compression_mode]; |
| 112 | r = romtable[compression_mode]; |
| 113 | |
| 114 | for (j = 0; j < 8; j++, r++, p0 += 128) { |
| 115 | |
| 116 | for (k = 0; k < 16; k++) { |
| 117 | if (k == 0) |
| 118 | bit = 1; |
| 119 | else if (k >= 1 && k < 3) |
| 120 | bit = (r[0] >> 15) & 7; |
| 121 | else if (k >= 3 && k < 6) |
| 122 | bit = (r[0] >> 12) & 7; |
| 123 | else if (k >= 6 && k < 10) |
| 124 | bit = (r[0] >> 9) & 7; |
| 125 | else if (k >= 10 && k < 13) |
| 126 | bit = (r[0] >> 6) & 7; |
| 127 | else if (k >= 13 && k < 15) |
| 128 | bit = (r[0] >> 3) & 7; |
| 129 | else |
| 130 | bit = (r[0]) & 7; |
| 131 | if (k == 0) |
| 132 | *p8++ = 8; |
| 133 | else |
| 134 | *p8++ = j - bit; |
| 135 | *p8++ = bit; |
| 136 | |
| 137 | pw = 1 << bit; |
| 138 | p0[k + 0x00] = (1 * pw) + 0x80; |
| 139 | p0[k + 0x10] = (2 * pw) + 0x80; |
| 140 | p0[k + 0x20] = (3 * pw) + 0x80; |
| 141 | p0[k + 0x30] = (4 * pw) + 0x80; |
| 142 | p0[k + 0x40] = (-1 * pw) + 0x80; |
| 143 | p0[k + 0x50] = (-2 * pw) + 0x80; |
| 144 | p0[k + 0x60] = (-3 * pw) + 0x80; |
| 145 | p0[k + 0x70] = (-4 * pw) + 0x80; |
| 146 | } /* end of for (k=0; k<16; k++, p8++) */ |
| 147 | } /* end of for (j=0; j<8; j++ , table++) */ |
| 148 | } /* end of foreach compression_mode */ |
| 149 | } |
| 150 | |
| 151 | /* |
| 152 | * |
| 153 | */ |
| 154 | static void fill_table_dc00_d800(struct pwc_dec23_private *pdec) |
| 155 | { |
| 156 | #define SCALEBITS 15 |
| 157 | #define ONE_HALF (1UL << (SCALEBITS - 1)) |
| 158 | int i; |
| 159 | unsigned int offset1 = ONE_HALF; |
| 160 | unsigned int offset2 = 0x0000; |
| 161 | |
| 162 | for (i=0; i<256; i++) { |
| 163 | pdec->table_dc00[i] = offset1 & ~(ONE_HALF); |
| 164 | pdec->table_d800[i] = offset2; |
| 165 | |
| 166 | offset1 += 0x7bc4; |
| 167 | offset2 += 0x7bc4; |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | /* |
| 172 | * To decode the stream: |
| 173 | * if look_bits(2) == 0: # op == 2 in the lookup table |
| 174 | * skip_bits(2) |
| 175 | * end of the stream |
| 176 | * elif look_bits(3) == 7: # op == 1 in the lookup table |
| 177 | * skip_bits(3) |
| 178 | * yyyy = get_bits(4) |
| 179 | * xxxx = get_bits(8) |
| 180 | * else: # op == 0 in the lookup table |
| 181 | * skip_bits(x) |
| 182 | * |
| 183 | * For speedup processing, we build a lookup table and we takes the first 6 bits. |
| 184 | * |
| 185 | * struct { |
| 186 | * unsigned char op; // operation to execute |
| 187 | * unsigned char bits; // bits use to perform operation |
| 188 | * unsigned char offset1; // offset to add to access in the table_0004 % 16 |
| 189 | * unsigned char offset2; // offset to add to access in the table_0004 |
| 190 | * } |
| 191 | * |
| 192 | * How to build this table ? |
| 193 | * op == 2 when (i%4)==0 |
| 194 | * op == 1 when (i%8)==7 |
| 195 | * op == 0 otherwise |
| 196 | * |
| 197 | */ |
| 198 | static const unsigned char hash_table_ops[64*4] = { |
| 199 | 0x02, 0x00, 0x00, 0x00, |
| 200 | 0x00, 0x03, 0x01, 0x00, |
| 201 | 0x00, 0x04, 0x01, 0x10, |
| 202 | 0x00, 0x06, 0x01, 0x30, |
| 203 | 0x02, 0x00, 0x00, 0x00, |
| 204 | 0x00, 0x03, 0x01, 0x40, |
| 205 | 0x00, 0x05, 0x01, 0x20, |
| 206 | 0x01, 0x00, 0x00, 0x00, |
| 207 | 0x02, 0x00, 0x00, 0x00, |
| 208 | 0x00, 0x03, 0x01, 0x00, |
| 209 | 0x00, 0x04, 0x01, 0x50, |
| 210 | 0x00, 0x05, 0x02, 0x00, |
| 211 | 0x02, 0x00, 0x00, 0x00, |
| 212 | 0x00, 0x03, 0x01, 0x40, |
| 213 | 0x00, 0x05, 0x03, 0x00, |
| 214 | 0x01, 0x00, 0x00, 0x00, |
| 215 | 0x02, 0x00, 0x00, 0x00, |
| 216 | 0x00, 0x03, 0x01, 0x00, |
| 217 | 0x00, 0x04, 0x01, 0x10, |
| 218 | 0x00, 0x06, 0x02, 0x10, |
| 219 | 0x02, 0x00, 0x00, 0x00, |
| 220 | 0x00, 0x03, 0x01, 0x40, |
| 221 | 0x00, 0x05, 0x01, 0x60, |
| 222 | 0x01, 0x00, 0x00, 0x00, |
| 223 | 0x02, 0x00, 0x00, 0x00, |
| 224 | 0x00, 0x03, 0x01, 0x00, |
| 225 | 0x00, 0x04, 0x01, 0x50, |
| 226 | 0x00, 0x05, 0x02, 0x40, |
| 227 | 0x02, 0x00, 0x00, 0x00, |
| 228 | 0x00, 0x03, 0x01, 0x40, |
| 229 | 0x00, 0x05, 0x03, 0x40, |
| 230 | 0x01, 0x00, 0x00, 0x00, |
| 231 | 0x02, 0x00, 0x00, 0x00, |
| 232 | 0x00, 0x03, 0x01, 0x00, |
| 233 | 0x00, 0x04, 0x01, 0x10, |
| 234 | 0x00, 0x06, 0x01, 0x70, |
| 235 | 0x02, 0x00, 0x00, 0x00, |
| 236 | 0x00, 0x03, 0x01, 0x40, |
| 237 | 0x00, 0x05, 0x01, 0x20, |
| 238 | 0x01, 0x00, 0x00, 0x00, |
| 239 | 0x02, 0x00, 0x00, 0x00, |
| 240 | 0x00, 0x03, 0x01, 0x00, |
| 241 | 0x00, 0x04, 0x01, 0x50, |
| 242 | 0x00, 0x05, 0x02, 0x00, |
| 243 | 0x02, 0x00, 0x00, 0x00, |
| 244 | 0x00, 0x03, 0x01, 0x40, |
| 245 | 0x00, 0x05, 0x03, 0x00, |
| 246 | 0x01, 0x00, 0x00, 0x00, |
| 247 | 0x02, 0x00, 0x00, 0x00, |
| 248 | 0x00, 0x03, 0x01, 0x00, |
| 249 | 0x00, 0x04, 0x01, 0x10, |
| 250 | 0x00, 0x06, 0x02, 0x50, |
| 251 | 0x02, 0x00, 0x00, 0x00, |
| 252 | 0x00, 0x03, 0x01, 0x40, |
| 253 | 0x00, 0x05, 0x01, 0x60, |
| 254 | 0x01, 0x00, 0x00, 0x00, |
| 255 | 0x02, 0x00, 0x00, 0x00, |
| 256 | 0x00, 0x03, 0x01, 0x00, |
| 257 | 0x00, 0x04, 0x01, 0x50, |
| 258 | 0x00, 0x05, 0x02, 0x40, |
| 259 | 0x02, 0x00, 0x00, 0x00, |
| 260 | 0x00, 0x03, 0x01, 0x40, |
| 261 | 0x00, 0x05, 0x03, 0x40, |
| 262 | 0x01, 0x00, 0x00, 0x00 |
| 263 | }; |
| 264 | |
| 265 | /* |
| 266 | * |
| 267 | */ |
| 268 | static const unsigned int MulIdx[16][16] = { |
| 269 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, |
| 270 | {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,}, |
| 271 | {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,}, |
| 272 | {4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,}, |
| 273 | {6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,}, |
| 274 | {4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,}, |
| 275 | {1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,}, |
| 276 | {0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,}, |
| 277 | {0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,}, |
| 278 | {1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,}, |
| 279 | {7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,}, |
| 280 | {4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,}, |
| 281 | {7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,}, |
| 282 | {1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,}, |
| 283 | {1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,}, |
| 284 | {10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10} |
| 285 | }; |
| 286 | |
| 287 | #if USE_LOOKUP_TABLE_TO_CLAMP |
| 288 | #define MAX_OUTER_CROP_VALUE (512) |
| 289 | static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE]; |
| 290 | #define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)]) |
| 291 | #else |
| 292 | #define CLAMP(x) ((x)>255?255:((x)<0?0:x)) |
| 293 | #endif |
| 294 | |
| 295 | |
| 296 | /* If the type or the command change, we rebuild the lookup table */ |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 297 | void pwc_dec23_init(struct pwc_device *pdev, unsigned char *cmd) |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 298 | { |
| 299 | int flags, version, shift, i; |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 300 | struct pwc_dec23_private *pdec = &pdev->dec23; |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 301 | |
Hans de Goede | c20d78c | 2011-10-09 09:16:46 -0300 | [diff] [blame] | 302 | mutex_init(&pdec->lock); |
| 303 | |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 304 | if (DEVICE_USE_CODEC3(pdev->type)) { |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 305 | flags = cmd[2] & 0x18; |
| 306 | if (flags == 8) |
| 307 | pdec->nbits = 7; /* More bits, mean more bits to encode the stream, but better quality */ |
| 308 | else if (flags == 0x10) |
| 309 | pdec->nbits = 8; |
| 310 | else |
| 311 | pdec->nbits = 6; |
| 312 | |
| 313 | version = cmd[2] >> 5; |
| 314 | build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1); |
| 315 | build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); |
| 316 | |
| 317 | } else { |
| 318 | |
| 319 | flags = cmd[2] & 6; |
| 320 | if (flags == 2) |
| 321 | pdec->nbits = 7; |
| 322 | else if (flags == 4) |
| 323 | pdec->nbits = 8; |
| 324 | else |
| 325 | pdec->nbits = 6; |
| 326 | |
| 327 | version = cmd[2] >> 3; |
| 328 | build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1); |
| 329 | build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); |
| 330 | } |
| 331 | |
| 332 | /* Informations can be coded on a variable number of bits but never less than 8 */ |
| 333 | shift = 8 - pdec->nbits; |
| 334 | pdec->scalebits = SCALEBITS - shift; |
| 335 | pdec->nbitsmask = 0xFF >> shift; |
| 336 | |
| 337 | fill_table_dc00_d800(pdec); |
| 338 | build_subblock_pattern(pdec); |
| 339 | build_bit_powermask_table(pdec); |
| 340 | |
| 341 | #if USE_LOOKUP_TABLE_TO_CLAMP |
| 342 | /* Build the static table to clamp value [0-255] */ |
| 343 | for (i=0;i<MAX_OUTER_CROP_VALUE;i++) |
| 344 | pwc_crop_table[i] = 0; |
| 345 | for (i=0; i<256; i++) |
| 346 | pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i; |
| 347 | for (i=0; i<MAX_OUTER_CROP_VALUE; i++) |
| 348 | pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255; |
| 349 | #endif |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 350 | } |
| 351 | |
| 352 | /* |
| 353 | * Copy the 4x4 image block to Y plane buffer |
| 354 | */ |
| 355 | static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) |
| 356 | { |
| 357 | #if UNROLL_LOOP_FOR_COPY |
| 358 | const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; |
| 359 | const int *c = src; |
| 360 | unsigned char *d = dst; |
| 361 | |
| 362 | *d++ = cm[c[0] >> scalebits]; |
| 363 | *d++ = cm[c[1] >> scalebits]; |
| 364 | *d++ = cm[c[2] >> scalebits]; |
| 365 | *d++ = cm[c[3] >> scalebits]; |
| 366 | |
| 367 | d = dst + bytes_per_line; |
| 368 | *d++ = cm[c[4] >> scalebits]; |
| 369 | *d++ = cm[c[5] >> scalebits]; |
| 370 | *d++ = cm[c[6] >> scalebits]; |
| 371 | *d++ = cm[c[7] >> scalebits]; |
| 372 | |
| 373 | d = dst + bytes_per_line*2; |
| 374 | *d++ = cm[c[8] >> scalebits]; |
| 375 | *d++ = cm[c[9] >> scalebits]; |
| 376 | *d++ = cm[c[10] >> scalebits]; |
| 377 | *d++ = cm[c[11] >> scalebits]; |
| 378 | |
| 379 | d = dst + bytes_per_line*3; |
| 380 | *d++ = cm[c[12] >> scalebits]; |
| 381 | *d++ = cm[c[13] >> scalebits]; |
| 382 | *d++ = cm[c[14] >> scalebits]; |
| 383 | *d++ = cm[c[15] >> scalebits]; |
| 384 | #else |
| 385 | int i; |
| 386 | const int *c = src; |
| 387 | unsigned char *d = dst; |
| 388 | for (i = 0; i < 4; i++, c++) |
| 389 | *d++ = CLAMP((*c) >> scalebits); |
| 390 | |
| 391 | d = dst + bytes_per_line; |
| 392 | for (i = 0; i < 4; i++, c++) |
| 393 | *d++ = CLAMP((*c) >> scalebits); |
| 394 | |
| 395 | d = dst + bytes_per_line*2; |
| 396 | for (i = 0; i < 4; i++, c++) |
| 397 | *d++ = CLAMP((*c) >> scalebits); |
| 398 | |
| 399 | d = dst + bytes_per_line*3; |
| 400 | for (i = 0; i < 4; i++, c++) |
| 401 | *d++ = CLAMP((*c) >> scalebits); |
| 402 | #endif |
| 403 | } |
| 404 | |
| 405 | /* |
| 406 | * Copy the 4x4 image block to a CrCb plane buffer |
| 407 | * |
| 408 | */ |
| 409 | static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) |
| 410 | { |
| 411 | #if UNROLL_LOOP_FOR_COPY |
| 412 | /* Unroll all loops */ |
| 413 | const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; |
| 414 | const int *c = src; |
| 415 | unsigned char *d = dst; |
| 416 | |
| 417 | *d++ = cm[c[0] >> scalebits]; |
| 418 | *d++ = cm[c[4] >> scalebits]; |
| 419 | *d++ = cm[c[1] >> scalebits]; |
| 420 | *d++ = cm[c[5] >> scalebits]; |
| 421 | *d++ = cm[c[2] >> scalebits]; |
| 422 | *d++ = cm[c[6] >> scalebits]; |
| 423 | *d++ = cm[c[3] >> scalebits]; |
| 424 | *d++ = cm[c[7] >> scalebits]; |
| 425 | |
| 426 | d = dst + bytes_per_line; |
| 427 | *d++ = cm[c[12] >> scalebits]; |
| 428 | *d++ = cm[c[8] >> scalebits]; |
| 429 | *d++ = cm[c[13] >> scalebits]; |
| 430 | *d++ = cm[c[9] >> scalebits]; |
| 431 | *d++ = cm[c[14] >> scalebits]; |
| 432 | *d++ = cm[c[10] >> scalebits]; |
| 433 | *d++ = cm[c[15] >> scalebits]; |
| 434 | *d++ = cm[c[11] >> scalebits]; |
| 435 | #else |
| 436 | int i; |
| 437 | const int *c1 = src; |
| 438 | const int *c2 = src + 4; |
| 439 | unsigned char *d = dst; |
| 440 | |
| 441 | for (i = 0; i < 4; i++, c1++, c2++) { |
| 442 | *d++ = CLAMP((*c1) >> scalebits); |
| 443 | *d++ = CLAMP((*c2) >> scalebits); |
| 444 | } |
| 445 | c1 = src + 12; |
| 446 | d = dst + bytes_per_line; |
| 447 | for (i = 0; i < 4; i++, c1++, c2++) { |
| 448 | *d++ = CLAMP((*c1) >> scalebits); |
| 449 | *d++ = CLAMP((*c2) >> scalebits); |
| 450 | } |
| 451 | #endif |
| 452 | } |
| 453 | |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 454 | /* |
| 455 | * To manage the stream, we keep bits in a 32 bits register. |
| 456 | * fill_nbits(n): fill the reservoir with at least n bits |
| 457 | * skip_bits(n): discard n bits from the reservoir |
| 458 | * get_bits(n): fill the reservoir, returns the first n bits and discard the |
| 459 | * bits from the reservoir. |
| 460 | * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir |
| 461 | * contains at least n bits. bits returned is discarded. |
| 462 | */ |
| 463 | #define fill_nbits(pdec, nbits_wanted) do { \ |
| 464 | while (pdec->nbits_in_reservoir<(nbits_wanted)) \ |
| 465 | { \ |
| 466 | pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \ |
| 467 | pdec->nbits_in_reservoir += 8; \ |
| 468 | } \ |
| 469 | } while(0); |
| 470 | |
| 471 | #define skip_nbits(pdec, nbits_to_skip) do { \ |
| 472 | pdec->reservoir >>= (nbits_to_skip); \ |
| 473 | pdec->nbits_in_reservoir -= (nbits_to_skip); \ |
| 474 | } while(0); |
| 475 | |
| 476 | #define get_nbits(pdec, nbits_wanted, result) do { \ |
| 477 | fill_nbits(pdec, nbits_wanted); \ |
| 478 | result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \ |
| 479 | skip_nbits(pdec, nbits_wanted); \ |
| 480 | } while(0); |
| 481 | |
| 482 | #define __get_nbits(pdec, nbits_wanted, result) do { \ |
| 483 | result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \ |
| 484 | skip_nbits(pdec, nbits_wanted); \ |
| 485 | } while(0); |
| 486 | |
| 487 | #define look_nbits(pdec, nbits_wanted) \ |
| 488 | ((pdec->reservoir) & ((1U<<(nbits_wanted))-1)) |
| 489 | |
| 490 | /* |
| 491 | * Decode a 4x4 pixel block |
| 492 | */ |
| 493 | static void decode_block(struct pwc_dec23_private *pdec, |
| 494 | const unsigned char *ptable0004, |
| 495 | const unsigned char *ptable8004) |
| 496 | { |
| 497 | unsigned int primary_color; |
| 498 | unsigned int channel_v, offset1, op; |
| 499 | int i; |
| 500 | |
| 501 | fill_nbits(pdec, 16); |
| 502 | __get_nbits(pdec, pdec->nbits, primary_color); |
| 503 | |
| 504 | if (look_nbits(pdec,2) == 0) { |
| 505 | skip_nbits(pdec, 2); |
| 506 | /* Very simple, the color is the same for all pixels of the square */ |
| 507 | for (i = 0; i < 16; i++) |
| 508 | pdec->temp_colors[i] = pdec->table_dc00[primary_color]; |
| 509 | |
| 510 | return; |
| 511 | } |
| 512 | |
| 513 | /* This block is encoded with small pattern */ |
| 514 | for (i = 0; i < 16; i++) |
| 515 | pdec->temp_colors[i] = pdec->table_d800[primary_color]; |
| 516 | |
| 517 | __get_nbits(pdec, 3, channel_v); |
| 518 | channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2); |
| 519 | |
| 520 | ptable0004 += (channel_v * 128); |
| 521 | ptable8004 += (channel_v * 32); |
| 522 | |
| 523 | offset1 = 0; |
| 524 | do |
| 525 | { |
| 526 | unsigned int htable_idx, rows = 0; |
| 527 | const unsigned int *block; |
| 528 | |
| 529 | /* [ zzzz y x x ] |
| 530 | * xx == 00 :=> end of the block def, remove the two bits from the stream |
| 531 | * yxx == 111 |
| 532 | * yxx == any other value |
| 533 | * |
| 534 | */ |
| 535 | fill_nbits(pdec, 16); |
| 536 | htable_idx = look_nbits(pdec, 6); |
| 537 | op = hash_table_ops[htable_idx * 4]; |
| 538 | |
| 539 | if (op == 2) { |
| 540 | skip_nbits(pdec, 2); |
| 541 | |
| 542 | } else if (op == 1) { |
| 543 | /* 15bits [ xxxx xxxx yyyy 111 ] |
| 544 | * yyy => offset in the table8004 |
| 545 | * xxx => offset in the tabled004 (tree) |
| 546 | */ |
| 547 | unsigned int mask, shift; |
| 548 | unsigned int nbits, col1; |
| 549 | unsigned int yyyy; |
| 550 | |
| 551 | skip_nbits(pdec, 3); |
| 552 | /* offset1 += yyyy */ |
| 553 | __get_nbits(pdec, 4, yyyy); |
| 554 | offset1 += 1 + yyyy; |
| 555 | offset1 &= 0x0F; |
| 556 | nbits = ptable8004[offset1 * 2]; |
| 557 | |
| 558 | /* col1 = xxxx xxxx */ |
| 559 | __get_nbits(pdec, nbits+1, col1); |
| 560 | |
| 561 | /* Bit mask table */ |
| 562 | mask = pdec->table_bitpowermask[nbits][col1]; |
| 563 | shift = ptable8004[offset1 * 2 + 1]; |
| 564 | rows = ((mask << shift) + 0x80) & 0xFF; |
| 565 | |
| 566 | block = pdec->table_subblock[rows]; |
| 567 | for (i = 0; i < 16; i++) |
| 568 | pdec->temp_colors[i] += block[MulIdx[offset1][i]]; |
| 569 | |
| 570 | } else { |
| 571 | /* op == 0 |
| 572 | * offset1 is coded on 3 bits |
| 573 | */ |
| 574 | unsigned int shift; |
| 575 | |
| 576 | offset1 += hash_table_ops [htable_idx * 4 + 2]; |
| 577 | offset1 &= 0x0F; |
| 578 | |
| 579 | rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]]; |
| 580 | block = pdec->table_subblock[rows]; |
| 581 | for (i = 0; i < 16; i++) |
| 582 | pdec->temp_colors[i] += block[MulIdx[offset1][i]]; |
| 583 | |
| 584 | shift = hash_table_ops[htable_idx * 4 + 1]; |
| 585 | skip_nbits(pdec, shift); |
| 586 | } |
| 587 | |
| 588 | } while (op != 2); |
| 589 | |
| 590 | } |
| 591 | |
| 592 | static void DecompressBand23(struct pwc_dec23_private *pdec, |
| 593 | const unsigned char *rawyuv, |
| 594 | unsigned char *planar_y, |
| 595 | unsigned char *planar_u, |
| 596 | unsigned char *planar_v, |
| 597 | unsigned int compressed_image_width, |
| 598 | unsigned int real_image_width) |
| 599 | { |
| 600 | int compression_index, nblocks; |
| 601 | const unsigned char *ptable0004; |
| 602 | const unsigned char *ptable8004; |
| 603 | |
| 604 | pdec->reservoir = 0; |
| 605 | pdec->nbits_in_reservoir = 0; |
| 606 | pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */ |
| 607 | |
| 608 | get_nbits(pdec, 4, compression_index); |
| 609 | |
| 610 | /* pass 1: uncompress Y component */ |
| 611 | nblocks = compressed_image_width / 4; |
| 612 | |
| 613 | ptable0004 = pdec->table_0004_pass1[compression_index]; |
| 614 | ptable8004 = pdec->table_8004_pass1[compression_index]; |
| 615 | |
| 616 | /* Each block decode a square of 4x4 */ |
| 617 | while (nblocks) { |
| 618 | decode_block(pdec, ptable0004, ptable8004); |
| 619 | copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits); |
| 620 | planar_y += 4; |
| 621 | nblocks--; |
| 622 | } |
| 623 | |
| 624 | /* pass 2: uncompress UV component */ |
| 625 | nblocks = compressed_image_width / 8; |
| 626 | |
| 627 | ptable0004 = pdec->table_0004_pass2[compression_index]; |
| 628 | ptable8004 = pdec->table_8004_pass2[compression_index]; |
| 629 | |
| 630 | /* Each block decode a square of 4x4 */ |
| 631 | while (nblocks) { |
| 632 | decode_block(pdec, ptable0004, ptable8004); |
| 633 | copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits); |
| 634 | |
| 635 | decode_block(pdec, ptable0004, ptable8004); |
| 636 | copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits); |
| 637 | |
| 638 | planar_v += 8; |
| 639 | planar_u += 8; |
| 640 | nblocks -= 2; |
| 641 | } |
| 642 | |
| 643 | } |
| 644 | |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 645 | /** |
| 646 | * |
| 647 | * Uncompress a pwc23 buffer. |
| 648 | * |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 649 | * src: raw data |
| 650 | * dst: image output |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 651 | */ |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 652 | void pwc_dec23_decompress(struct pwc_device *pdev, |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 653 | const void *src, |
Hans de Goede | dc8a7e8 | 2011-12-31 10:52:02 -0300 | [diff] [blame] | 654 | void *dst) |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 655 | { |
Hans de Goede | 795e6eb | 2012-01-04 16:58:44 -0300 | [diff] [blame] | 656 | int bandlines_left, bytes_per_block; |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 657 | struct pwc_dec23_private *pdec = &pdev->dec23; |
Hans de Goede | c20d78c | 2011-10-09 09:16:46 -0300 | [diff] [blame] | 658 | |
Hans de Goede | dc8a7e8 | 2011-12-31 10:52:02 -0300 | [diff] [blame] | 659 | /* YUV420P image format */ |
| 660 | unsigned char *pout_planar_y; |
| 661 | unsigned char *pout_planar_u; |
| 662 | unsigned char *pout_planar_v; |
| 663 | unsigned int plane_size; |
| 664 | |
Hans de Goede | c20d78c | 2011-10-09 09:16:46 -0300 | [diff] [blame] | 665 | mutex_lock(&pdec->lock); |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 666 | |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 667 | bandlines_left = pdev->height / 4; |
| 668 | bytes_per_block = pdev->width * 4; |
| 669 | plane_size = pdev->height * pdev->width; |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 670 | |
Hans de Goede | 795e6eb | 2012-01-04 16:58:44 -0300 | [diff] [blame] | 671 | pout_planar_y = dst; |
| 672 | pout_planar_u = dst + plane_size; |
| 673 | pout_planar_v = dst + plane_size + plane_size / 4; |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 674 | |
Hans de Goede | dc8a7e8 | 2011-12-31 10:52:02 -0300 | [diff] [blame] | 675 | while (bandlines_left--) { |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 676 | DecompressBand23(pdec, src, |
Hans de Goede | dc8a7e8 | 2011-12-31 10:52:02 -0300 | [diff] [blame] | 677 | pout_planar_y, pout_planar_u, pout_planar_v, |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 678 | pdev->width, pdev->width); |
| 679 | src += pdev->vbandlength; |
Hans de Goede | dc8a7e8 | 2011-12-31 10:52:02 -0300 | [diff] [blame] | 680 | pout_planar_y += bytes_per_block; |
Hans de Goede | 56ae24a | 2012-01-08 11:29:19 -0300 | [diff] [blame^] | 681 | pout_planar_u += pdev->width; |
| 682 | pout_planar_v += pdev->width; |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 683 | } |
Hans de Goede | c20d78c | 2011-10-09 09:16:46 -0300 | [diff] [blame] | 684 | mutex_unlock(&pdec->lock); |
Luc Saillard | 2b455db | 2006-04-24 10:29:46 -0300 | [diff] [blame] | 685 | } |