/* * sn9c2028-decomp.c * * Decompression function for the Sonix SN9C2028 dual-mode cameras. * * Code adapted from libgphoto2/camlibs/sonix, original version of which was * Copyright (c) 2005 Theodore Kilgore * * History: * * This decoding algorithm originates from the work of Bertrik Sikken for the * SN9C102 cameras. This version is an adaptation of work done by Mattias * Krauss for the webcam-osx (macam) project. There, it was further adapted * for use with the Vivitar Vivicam 3350B (an SN9C2028 camera) by * Harald Ruda . Harald brought to my attention the * work done in the macam project and suggested that I use it. One improvement * of my own was to notice that the even and odd columns of the image have been * reversed by the decompression algorithm, and this needs to be corrected * during the decompression. * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02111-1307, USA. */ #include "libv4lconvert-priv.h" /* Four defines for bitstream operations, used in the decode function */ #define PEEK_BITS(num, to) { \ if (bitBufCount < num) { \ do { \ bitBuf = (bitBuf << 8) | (*(src++)); \ bitBufCount += 8; \ } while (bitBufCount < 24); \ } \ to = bitBuf >> (bitBufCount - num); \ } /* * PEEK_BITS puts the next bits into the low bits of . * when the buffer is empty, it is completely refilled. * This strategy tries to reduce memory access. Note that the high bits * are NOT set to zero! */ #define EAT_BITS(num) { bitBufCount -= num; bits_eaten += num; } /* * EAT_BITS consumes bits (PEEK_BITS does not consume anything, * it just peeks) */ #define PARSE_PIXEL(val) {\ PEEK_BITS(10, bits);\ if ((bits & 0x200) == 0) {\ EAT_BITS(1);\ } \ else if ((bits & 0x380) == 0x280) {\ EAT_BITS(3);\ val += 3;\ if (val > 255)\ val = 255;\ } \ else if ((bits & 0x380) == 0x300) {\ EAT_BITS(3);\ val -= 3;\ if (val < 0)\ val = 0;\ } \ else if ((bits & 0x3c0) == 0x200) {\ EAT_BITS(4);\ val += 8;\ if (val > 255)\ val = 255;\ } \ else if ((bits & 0x3c0) == 0x240) {\ EAT_BITS(4);\ val -= 8;\ if (val < 0)\ val = 0;\ } \ else if ((bits & 0x3c0) == 0x3c0) {\ EAT_BITS(4);\ val -= 20;\ if (val < 0)\ val = 0;\ } \ else if ((bits & 0x3e0) == 0x380) {\ EAT_BITS(5);\ val += 20;\ if (val > 255)\ val = 255;\ } \ else {\ EAT_BITS(10);\ val = 8 * (bits & 0x1f);\ } \ } #define PUT_PIXEL_PAIR {\ long pp;\ pp = (c1val << 8) + c2val;\ *((unsigned short *)(dst + dst_index)) = pp;\ dst_index += 2;\ } /* Now the decode function itself */ void v4lconvert_decode_sn9c2028(const unsigned char *src, unsigned char *dst, int width, int height) { long dst_index = 0; int starting_row = 0; unsigned short bits; short c1val, c2val; int x, y; unsigned long bitBuf = 0; unsigned long bitBufCount = 0; unsigned long bits_eaten = 0; src += 12; /* Remove the header */ for (y = starting_row; y < height; y++) { PEEK_BITS(8, bits); EAT_BITS(8); c2val = (bits & 0xff); PEEK_BITS(8, bits); EAT_BITS(8); c1val = (bits & 0xff); PUT_PIXEL_PAIR; for (x = 2; x < width ; x += 2) { /* The compression reversed the even and odd columns.*/ PARSE_PIXEL(c2val); PARSE_PIXEL(c1val); PUT_PIXEL_PAIR; } } }