1 /*
2 * sn9c2028-decomp.c
3 *
4 * Decompression function for the Sonix SN9C2028 dual-mode cameras.
5 *
6 * Code adapted from libgphoto2/camlibs/sonix, original version of which was
7 * Copyright (c) 2005 Theodore Kilgore <kilgota@auburn.edu>
8 *
9 * History:
10 *
11 * This decoding algorithm originates from the work of Bertrik Sikken for the
12 * SN9C102 cameras. This version is an adaptation of work done by Mattias
13 * Krauss for the webcam-osx (macam) project. There, it was further adapted
14 * for use with the Vivitar Vivicam 3350B (an SN9C2028 camera) by
15 * Harald Ruda <hrx@users.sourceforge.net>. Harald brought to my attention the
16 * work done in the macam project and suggested that I use it. One improvement
17 * of my own was to notice that the even and odd columns of the image have been
18 * reversed by the decompression algorithm, and this needs to be corrected
19 * during the decompression.
20 *
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Lesser General Public
24 * License as published by the Free Software Foundation; either
25 * version 2.1 of the License, or (at your option) any later version.
26 *
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31 * Lesser General Public License for more details.
32 *
33 * You should have received a copy of the GNU Lesser General Public
34 * License along with this program; if not, write to the
35 * Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
36 * Boston, MA 02111-1307, USA.
37 */
38
39 #include "libv4lconvert-priv.h"
40
41 /* Four defines for bitstream operations, used in the decode function */
42
43 #define PEEK_BITS(num, to) { \
44 if (bitBufCount < num) { \
45 do { \
46 bitBuf = (bitBuf << 8) | (*(src++)); \
47 bitBufCount += 8; \
48 } while (bitBufCount < 24); \
49 } \
50 to = bitBuf >> (bitBufCount - num); \
51 }
52
53 /*
54 * PEEK_BITS puts the next <num> bits into the low bits of <to>.
55 * when the buffer is empty, it is completely refilled.
56 * This strategy tries to reduce memory access. Note that the high bits
57 * are NOT set to zero!
58 */
59
60 #define EAT_BITS(num) { bitBufCount -= num; bits_eaten += num; }
61
62 /*
63 * EAT_BITS consumes <num> bits (PEEK_BITS does not consume anything,
64 * it just peeks)
65 */
66
67 #define PARSE_PIXEL(val) {\
68 PEEK_BITS(10, bits);\
69 if ((bits & 0x200) == 0) {\
70 EAT_BITS(1);\
71 } \
72 else if ((bits & 0x380) == 0x280) {\
73 EAT_BITS(3);\
74 val += 3;\
75 if (val > 255)\
76 val = 255;\
77 } \
78 else if ((bits & 0x380) == 0x300) {\
79 EAT_BITS(3);\
80 val -= 3;\
81 if (val < 0)\
82 val = 0;\
83 } \
84 else if ((bits & 0x3c0) == 0x200) {\
85 EAT_BITS(4);\
86 val += 8;\
87 if (val > 255)\
88 val = 255;\
89 } \
90 else if ((bits & 0x3c0) == 0x240) {\
91 EAT_BITS(4);\
92 val -= 8;\
93 if (val < 0)\
94 val = 0;\
95 } \
96 else if ((bits & 0x3c0) == 0x3c0) {\
97 EAT_BITS(4);\
98 val -= 20;\
99 if (val < 0)\
100 val = 0;\
101 } \
102 else if ((bits & 0x3e0) == 0x380) {\
103 EAT_BITS(5);\
104 val += 20;\
105 if (val > 255)\
106 val = 255;\
107 } \
108 else {\
109 EAT_BITS(10);\
110 val = 8 * (bits & 0x1f);\
111 } \
112 }
113
114
115 #define PUT_PIXEL_PAIR {\
116 long pp;\
117 pp = (c1val << 8) + c2val;\
118 *((unsigned short *)(dst + dst_index)) = pp;\
119 dst_index += 2;\
120 }
121
122 /* Now the decode function itself */
123
v4lconvert_decode_sn9c2028(const unsigned char * src,unsigned char * dst,int width,int height)124 void v4lconvert_decode_sn9c2028(const unsigned char *src, unsigned char *dst,
125 int width, int height)
126 {
127 long dst_index = 0;
128 int starting_row = 0;
129 unsigned short bits;
130 short c1val, c2val;
131 int x, y;
132 unsigned long bitBuf = 0;
133 unsigned long bitBufCount = 0;
134 unsigned long bits_eaten = 0;
135
136 src += 12; /* Remove the header */
137
138 for (y = starting_row; y < height; y++) {
139 PEEK_BITS(8, bits);
140 EAT_BITS(8);
141 c2val = (bits & 0xff);
142 PEEK_BITS(8, bits);
143 EAT_BITS(8);
144 c1val = (bits & 0xff);
145
146 PUT_PIXEL_PAIR;
147
148 for (x = 2; x < width ; x += 2) {
149 /* The compression reversed the even and odd columns.*/
150 PARSE_PIXEL(c2val);
151 PARSE_PIXEL(c1val);
152 PUT_PIXEL_PAIR;
153 }
154 }
155 }
156