Updating prebuilts and/or headers

ebebd4b880fc415f09f76597b2ac7f30e79212b9 - libv4lconvert/Makefile
66dd7958319442bd52ba40ede28fbfe31bb4e074 - libv4lconvert/cpia1.c
3271d74d02e2f33c16e3e50aeb1268eb9c440782 - libv4lconvert/rgbyuv.c
db3c69c666e451c5d4ef6d1b5a3117f4b128baa4 - libv4lconvert/libv4lconvert-priv.h
1f1d1e05443c4b824cd697c0ce5efa9ea1277964 - libv4lconvert/ov518-decomp.c
b694b6348e035b3da880824c2c2768145c9b5199 - libv4lconvert/jpeg_memsrcdest.c
22a502c238e48f4b939c81de41feccfc7c366766 - libv4lconvert/Makefile.dGPU
60e29f95ea52df4407d771330897813cdb38340f - libv4lconvert/libv4lsyscall-priv.h
cc3f3e94a21795990610e63887c30528bde7b42e - libv4lconvert/bayer.c
72953a5a3a56b0188d35f49246356b9c8c35756c - libv4lconvert/helper.c
d6c1aba89bbcb6fef46a6f22b7ea01025435c44d - libv4lconvert/Makefile.am
ddd39b2fe0e2a86a6c64031ccc0d36edfd9b0f1a - libv4lconvert/sn9c10x.c
07f8e7c84abfbbe76d49d8bfd1f4eae6ea39a90b - libv4lconvert/jpgl.c
84c9c3812d4b5f237c8cd616d37fc1161a212acc - libv4lconvert/se401.c
fbbffd8182b4fe2e85289b6e784f70cba7ea7b1d - libv4lconvert/sq905c.c
fa751ff0f78845f3b4591396710df3b165bc8d11 - libv4lconvert/mr97310a.c
6ad4947dca51a7e67e056561cdb445d6c354d23c - libv4lconvert/libv4lconvert.c
4eff5c1a5e0b99ce4d6e9aa63645d9628467fdc3 - libv4lconvert/sn9c2028-decomp.c
5430e46abb1ac7039ed0309ca338237533ff29c9 - libv4lconvert/sn9c20x.c
3c49d99b9753208a9c1c2a9c738a1e7ad291ca22 - libv4lconvert/jpeg_memsrcdest.h
fb3344cfa8df97688332ee4fd3b17968437e8ad5 - libv4lconvert/helper-funcs.h
8b7644ac3d5c4161cfb6dcc2a34013f4c379c665 - libv4lconvert/libv4lconvert.export
be9e3bf3d7d1086b6eed0c1bf2f574c2b1737c00 - libv4lconvert/tinyjpeg.c
f08c902ecd48c2739956606b502fc0b8e4007703 - libv4lconvert/crop.c
f4d73412805f12fa08dd79a43798a7f8d7acece9 - libv4lconvert/pac207.c
25130d299463897a09e8b9adf72389dac2e89fa4 - libv4lconvert/tinyjpeg-internal.h
463725aa4dd3fecaf89c0b8bbf4747f8f7577935 - libv4lconvert/jpeg.c
725c9b8d0bfadba566cf200921e602961cb12705 - libv4lconvert/spca561-decompress.c
ff7444c48a8da88f8a466cfb138e30e585828cb3 - libv4lconvert/jl2005bcd.c
803c4d0b9364050eda163452b8792e62e221ab6d - libv4lconvert/tinyjpeg.h
cc8982bb6f753249181c715fe6430ffefc78c23b - libv4lconvert/stv0680.c
3e8e6c1fb85e3c4b58c4e9b2b0a223ddc793edcb - libv4lconvert/libv4lconvert.pc.in
033894511bd7e8a374a52486889658faa17918c4 - libv4lconvert/flip.c
f061a4e0e45ca8e0dbab630dd477e19a6c915fda - libv4lconvert/spca501.c
b2c19c2eac71d39d3fb883cdc159a69c2afa8fd6 - libv4lconvert/ov511-decomp.c
1d9c446cd8a232da87bd79acebc93e018ec72499 - libv4lconvert/jidctflt.c
1949e23fe99ccd0a05dcd084848f6d38b0af7ab6 - libv4lconvert/hm12.c
7da402829dbff238ca6ac829c037a85476185db6 - libv4lconvert/processing/autogain.c
a54c2cb0439e606af01d0b4f02704f411819d98c - libv4lconvert/processing/libv4lprocessing.c
dae9c69b7f019d7d4494cd56e2cf757e8510824a - libv4lconvert/processing/whitebalance.c
ebf12bcf99f35fb9c400b04a1439e68598268249 - libv4lconvert/processing/gamma.c
0390d660eb130f0e580832bcf8ad5069010d2696 - libv4lconvert/processing/libv4lprocessing.h
33ab91b54108e8c24cbb80c5c335d96391d440b2 - libv4lconvert/processing/libv4lprocessing-priv.h
19a7fd04cdeba61172f281806d030472dee79fcd - libv4lconvert/control/libv4lcontrol.c
1e08fb01a598d71e3fc69656c4f2291f7dc13105 - libv4lconvert/control/libv4lcontrol.h
70f4992835e964b2698473971904375333e3659b - libv4lconvert/control/libv4lcontrol-priv.h
6feb5b2b8c99c99712dd1ea7fe9ab674d58bf86b - include/libv4l1.h
bc44111fd6b2f0374a9fc67b1b23666c5c498b2c - include/libv4l2rds.h
f751b481c4a9203345cdbb6459d0f2882f7cdbd9 - include/libv4lconvert.h
1edc439e6c0fc98513fa4a69557eb6221d043be0 - include/libv4l2.h
f2b73fa5ab10ea7038e58bd9a4461d8e16316249 - include/libv4l1-videodev.h
94434b9692371b7d5f54ddef2141d22d90079ce9 - include/libv4l-plugin.h
c84a9a115a21d1fd20da0f6ca3df7b46dd23cd2a - include/config.h
1ba874a7cad36ff31e4af3bfb37b98c05063d6b2 - include/libdvbv5/desc_event_extended.h
6bd2ed0beaf6aa4838e239198564fd8e1d20a3a1 - include/libdvbv5/desc_t2_delivery.h
92d4c28148d0b537c8afc289e1a76de68435cba0 - include/libdvbv5/dvb-scan.h
22c83d133e5c1d2648efb3028e0d89c970d0aad4 - include/libdvbv5/desc_partial_reception.h
98365b48442b9e3abb58101983b5da8c14f78289 - include/libdvbv5/dvb-v5-std.h
2f55ba765c689500401111747bb381b5aca77b30 - include/libdvbv5/desc_ca.h
100c02ce3bc364ddff895c75f4fb1f928a748d2d - include/libdvbv5/desc_cable_delivery.h
96db22ef84892a36d5df3cffa0b30d5bad01939c - include/libdvbv5/desc_logical_channel.h
7645dda247bcd45628afbb74ec2707a47050992e - include/libdvbv5/nit.h
30e9a7240938943de2725f2b335b19ad320179a5 - include/libdvbv5/header.h
c1212a9308d96730de547648d3cda2fc144d0e29 - include/libdvbv5/desc_atsc_service_location.h
5b4a5e7fb30a7f28118be012837e73a7151d2619 - include/libdvbv5/cat.h
2560f18846a535a2c02e1ae449511e731f11c011 - include/libdvbv5/desc_ca_identifier.h
450fab787e61210c0c5f527df92c31c90b44a113 - include/libdvbv5/desc_service.h
cabecc6d7c9fdf1c437273bd6a746bf83c156f72 - include/libdvbv5/desc_frequency_list.h
7a6093b13354d054cac78ea118a96e813cac3395 - include/libdvbv5/atsc_eit.h
9a2b20076d6728b5799096e4149e33a73119e1ef - include/libdvbv5/desc_sat.h
146f4f53fc49c66b59905249c0142efffd72fc54 - include/libdvbv5/desc_network_name.h
efa3a711499f68ae370d49d98dc1963bf6bafcd8 - include/libdvbv5/desc_extension.h
44ab16a8d4eae09690c71a6301927c1da55dda6d - include/libdvbv5/descriptors.h
c18291ff9009bfe71a2c7c6f0fce75331dc95e30 - include/libdvbv5/sdt.h
5e2dfc1d9a71805389e9a7932812695d0309050c - include/libdvbv5/dvb-frontend.h
e81b7f75c11f175cf365fc7fb535e80828f10e24 - include/libdvbv5/dvb-file.h
d7a096d51e3050c8f52e0e2111d88b71a5313da1 - include/libdvbv5/dvb-demux.h
bdf514383ca0afe981cf4fd6af86440db2dc6667 - include/libdvbv5/pat.h
b72b6d1ffcdd81e3e631c7c20bb30e5c287dc7ff - include/libdvbv5/vct.h
9b5cfad4a5f41cbf886507da6e79b07314827b32 - include/libdvbv5/desc_language.h
6e6fd4c61c1f61006c63214cbe4868d49428ddb9 - include/libdvbv5/mpeg_pes.h
188fc2cbec97288787a7f66554a4b6288224f980 - include/libdvbv5/desc_isdbt_delivery.h
73b7b0cf684de0e8a4eae49a8521f81b411d7b72 - include/libdvbv5/desc_ts_info.h
7544b5fb8f621a9c637c40d8f7a2a71f6ab4bd63 - include/libdvbv5/desc_hierarchy.h
9d523ee179af955a687662996050ee3cfaacf2ab - include/libdvbv5/crc32.h
7fb0966c6a1ccdf1a8844aed4a94d4ae1d02fcd7 - include/libdvbv5/dvb-fe.h
c8b4fc511833f0993fa740a529e1f61e0f5a216f - include/libdvbv5/mpeg_es.h
ac87e3306569dae329809f27ef227c5d50f0b60e - include/libdvbv5/desc_event_short.h
40a06b5375dbc0de88a15d26cc6c1e9a505119bc - include/libdvbv5/eit.h
ef979f3276cc3cad6e947865a42643fbba860c69 - include/libdvbv5/mgt.h
b867a2e7941d718aa64b2f6a1402322b616cb2da - include/libdvbv5/pmt.h
fb8d640da36b6a156cbe0ef12dc25468de89a2a1 - include/libdvbv5/dvb-sat.h
4c412880f0c49cd00cb16e56eed082c4744211a5 - include/libdvbv5/countries.h
ad13bfa0b1642fc72cca387e62bc193974c8d5ee - include/libdvbv5/atsc_header.h
02168c58e3c772f116f075085579ac4a8422e819 - include/libdvbv5/desc_terrestrial_delivery.h
4fe7def34ff640fc5e327b3596298169fdfe2f1c - include/libdvbv5/mpeg_ts.h
d562371bb8a3b961c4d63a0f5618453bdff4bcd3 - include/libdvbv5/dvb-log.h
2542aabb7fbff4b1a09faaadec6006c4410a6d10 - libv4l2/libv4l2-priv.h
4ba98a607592ed0b8327b387af354544c65c9b67 - libv4l2/v4l2-plugin-android.c
b89578e115fc3704f6e4c0eb73eeea844788c10e - libv4l2/Makefile
ffecae84262f548deac1da0fa51f1aba6b6f96a0 - libv4l2/Makefile.dGPU
766aaca553b0166eb736557e44ad42b69464aa53 - libv4l2/libv4l2.export
64ab87e3f0fa33ac77533c79da6284041857ff20 - libv4l2/v4l2-plugin.c
8e335567bf404eeb3d180dd384309f687f2ab944 - libv4l2/Makefile.am
2835a7389ec7591d4ff4a6d552afe7d947548608 - libv4l2/libv4l2.c
2c6d79307968536d738adf5a70109eb77aee4faf - libv4l2/log.c
cbcee4426c19c168c6f49d04af3a0b2e30c0b681 - libv4l2/libv4l2.pc.in
9d456d1772885d900865a8958c0291e13d509de5 - libv4l2/v4l2convert.c

Change-Id: If618efc63e14808fcafb6f947b8d8542cbdc4767
This commit is contained in:
svcmobrel-release
2024-09-27 12:48:57 -07:00
parent e003da6fcd
commit 4bd02cecb6
111 changed files with 30919 additions and 0 deletions

69
libv4lconvert/Makefile Normal file
View File

@@ -0,0 +1,69 @@
###############################################################################
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
# property and proprietary rights in and to this material, related
# documentation and any modifications thereto. Any use, reproduction,
# disclosure or distribution of this material and related documentation
# without an express license agreement from NVIDIA CORPORATION or
# its affiliates is strictly prohibited.
#
###############################################################################
SO_NAME := libnvv4lconvert.so
DEST_DIR ?= /usr/lib/aarch64-linux-gnu/nvidia
SRCS := libv4lconvert.c tinyjpeg.c sn9c10x.c sn9c20x.c pac207.c mr97310a.c \
flip.c crop.c jidctflt.c spca561-decompress.c \
rgbyuv.c sn9c2028-decomp.c spca501.c sq905c.c bayer.c hm12.c \
stv0680.c cpia1.c se401.c jpgl.c jpeg.c jl2005bcd.c helper.c \
$(wildcard processing/*.c) \
$(wildcard control/*.c)
INCLUDES += -I./ -I../include -I./control -I./processing
OBJS := $(SRCS:.c=.o)
CFLAGS := -fPIC
MACHINE = $(shell uname -m)
ifeq ($(MACHINE),x86_64)
CFLAGS += -DLIBV4L2_PLUGIN_DIR_PATH_X86
DEST_DIR ?= /opt/nvidia/deepstream/deepstream-4.0/lib
SYM_LINK_DIR := $(DEST_DIR)
else
DEST_DIR ?= /usr/lib/$(MACHINE)-linux-gnu/nvidia
SYM_LINK_DIR := $(shell realpath $(DEST_DIR)/..)
endif
LIBS = -lrt
LDFLAGS := -Wl,-soname,libv4lconvert.so.0
all: $(SO_NAME)
%.o: %.c
$(CC) -c $< $(CFLAGS) $(INCLUDES) -o $@
$(SO_NAME): $(OBJS)
$(CC) -shared -o $(SO_NAME) $(OBJS) $(LIBS) $(LDFLAGS)
.PHONY: install
install: $(SO_NAME)
cp -vp $(SO_NAME) $(DEST_DIR)
if [ "$(MACHINE)" = "aarch64" ]; then \
ln -sf nvidia/$(SO_NAME) $(SYM_LINK_DIR)/libv4lconvert.so.0.0.999999 ; \
else \
ln -sf $(SO_NAME) $(SYM_LINK_DIR)/libv4lconvert.so.0.0.999999 ; \
fi
ln -sf libv4lconvert.so.0.0.999999 \
$(SYM_LINK_DIR)/libv4lconvert.so
ln -sf libv4lconvert.so.0.0.999999 \
${SYM_LINK_DIR}/libv4lconvert.so.0
.PHONY: clean
clean:
rm -rf $(OBJS) $(SO_NAME)

31
libv4lconvert/Makefile.am Normal file
View File

@@ -0,0 +1,31 @@
if WITH_LIBV4L
lib_LTLIBRARIES = libv4lconvert.la
libv4lconvertpriv_PROGRAMS = ov511-decomp ov518-decomp
include_HEADERS = ../include/libv4lconvert.h
pkgconfig_DATA = libv4lconvert.pc
LIBV4LCONVERT_VERSION = -version-info 0
else
noinst_LTLIBRARIES = libv4lconvert.la
endif
libv4lconvert_la_SOURCES = \
libv4lconvert.c tinyjpeg.c sn9c10x.c sn9c20x.c pac207.c mr97310a.c \
flip.c crop.c jidctflt.c spca561-decompress.c \
rgbyuv.c sn9c2028-decomp.c spca501.c sq905c.c bayer.c hm12.c \
stv0680.c cpia1.c se401.c jpgl.c jpeg.c jl2005bcd.c \
control/libv4lcontrol.c control/libv4lcontrol.h control/libv4lcontrol-priv.h \
processing/libv4lprocessing.c processing/whitebalance.c processing/autogain.c \
processing/gamma.c processing/libv4lprocessing.h processing/libv4lprocessing-priv.h \
helper.c helper-funcs.h libv4lconvert-priv.h libv4lsyscall-priv.h \
tinyjpeg.h tinyjpeg-internal.h
if HAVE_JPEG
libv4lconvert_la_SOURCES += jpeg_memsrcdest.c jpeg_memsrcdest.h
endif
libv4lconvert_la_CPPFLAGS = $(CFLAG_VISIBILITY) $(ENFORCE_LIBV4L_STATIC)
libv4lconvert_la_LDFLAGS = $(LIBV4LCONVERT_VERSION) -lrt -lm $(JPEG_LIBS) $(ENFORCE_LIBV4L_STATIC)
ov511_decomp_SOURCES = ov511-decomp.c
ov518_decomp_SOURCES = ov518-decomp.c
EXTRA_DIST = Android.mk

View File

@@ -0,0 +1,41 @@
###############################################################################
#
# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
#
# NVIDIA Corporation and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA Corporation is strictly prohibited.
#
###############################################################################
CC:=gcc
TARGET_NAME:= libnvv4lconvert.so
SRCS := libv4lconvert.c tinyjpeg.c sn9c10x.c sn9c20x.c pac207.c mr97310a.c \
flip.c crop.c jidctflt.c spca561-decompress.c \
rgbyuv.c sn9c2028-decomp.c spca501.c sq905c.c bayer.c hm12.c \
stv0680.c cpia1.c se401.c jpgl.c jpeg.c jl2005bcd.c helper.c \
$(wildcard processing/*.c) \
$(wildcard control/*.c)
INC_PATHS:= ../include ./control ./processing
CFLAGS:= -fPIC
CFLAGS += -DLIBV4L2_PLUGIN_DIR_PATH_X86
IGNORE_DS_PACKAGE_NAMING:=1
LDFLAGS:= -shared -Wl,-soname,libv4lconvert.so.0
LIBS:= -lrt -lm
#IS_V4L2_LIB:=1
PACKAGE_BINARY_IN_DS:=1
BUILD_DIR:=../../../../deepstream/sdk/build/libs/libv4l/
include ../../../../deepstream/sdk/Rules.mk
install::
ln -sf $(INSTALL_DIR)/$(TARGET_NAME) /usr/lib/x86_64-linux-gnu/libv4lconvert.so.0.0.99999
ldconfig

632
libv4lconvert/bayer.c Normal file
View File

@@ -0,0 +1,632 @@
/*
* lib4lconvert, video4linux2 format conversion lib
* (C) 2008 Hans de Goede <hdegoede@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License, version 2.1, as published by the Free Software Foundation.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*
* Note: original bayer_to_bgr24 code from :
* 1394-Based Digital Camera Control Library
*
* Bayer pattern decoding functions
*
* Written by Damien Douxchamps and Frederic Devernay
*
* Note that the original bayer.c in libdc1394 supports many different
* bayer decode algorithms, for lib4lconvert the one in this file has been
* chosen (and optimized a bit) and the other algorithms have been removed,
* see bayer.c from libdc1394 for all supported algorithms
*/
#include <string.h>
#include "libv4lconvert-priv.h"
/**************************************************************
* Color conversion functions for cameras that can *
* output raw-Bayer pattern images, such as some Basler and *
* Point Grey camera. Most of the algos presented here come *
* from http://www-ise.stanford.edu/~tingchen/ and have been *
* converted from Matlab to C and extended to all elementary *
* patterns. *
**************************************************************/
/* inspired by OpenCV's Bayer decoding */
static void v4lconvert_border_bayer_line_to_bgr24(
const unsigned char *bayer, const unsigned char *adjacent_bayer,
unsigned char *bgr, int width, const int start_with_green, const int blue_line)
{
int t0, t1;
if (start_with_green) {
/* First pixel */
if (blue_line) {
*bgr++ = bayer[1];
*bgr++ = bayer[0];
*bgr++ = adjacent_bayer[0];
} else {
*bgr++ = adjacent_bayer[0];
*bgr++ = bayer[0];
*bgr++ = bayer[1];
}
/* Second pixel */
t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
if (blue_line) {
*bgr++ = bayer[1];
*bgr++ = t0;
*bgr++ = t1;
} else {
*bgr++ = t1;
*bgr++ = t0;
*bgr++ = bayer[1];
}
bayer++;
adjacent_bayer++;
width -= 2;
} else {
/* First pixel */
t0 = (bayer[1] + adjacent_bayer[0] + 1) >> 1;
if (blue_line) {
*bgr++ = bayer[0];
*bgr++ = t0;
*bgr++ = adjacent_bayer[1];
} else {
*bgr++ = adjacent_bayer[1];
*bgr++ = t0;
*bgr++ = bayer[0];
}
width--;
}
if (blue_line) {
for ( ; width > 2; width -= 2) {
t0 = (bayer[0] + bayer[2] + 1) >> 1;
*bgr++ = t0;
*bgr++ = bayer[1];
*bgr++ = adjacent_bayer[1];
bayer++;
adjacent_bayer++;
t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
*bgr++ = bayer[1];
*bgr++ = t0;
*bgr++ = t1;
bayer++;
adjacent_bayer++;
}
} else {
for ( ; width > 2; width -= 2) {
t0 = (bayer[0] + bayer[2] + 1) >> 1;
*bgr++ = adjacent_bayer[1];
*bgr++ = bayer[1];
*bgr++ = t0;
bayer++;
adjacent_bayer++;
t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
*bgr++ = t1;
*bgr++ = t0;
*bgr++ = bayer[1];
bayer++;
adjacent_bayer++;
}
}
if (width == 2) {
/* Second to last pixel */
t0 = (bayer[0] + bayer[2] + 1) >> 1;
if (blue_line) {
*bgr++ = t0;
*bgr++ = bayer[1];
*bgr++ = adjacent_bayer[1];
} else {
*bgr++ = adjacent_bayer[1];
*bgr++ = bayer[1];
*bgr++ = t0;
}
/* Last pixel */
t0 = (bayer[1] + adjacent_bayer[2] + 1) >> 1;
if (blue_line) {
*bgr++ = bayer[2];
*bgr++ = t0;
*bgr++ = adjacent_bayer[1];
} else {
*bgr++ = adjacent_bayer[1];
*bgr++ = t0;
*bgr++ = bayer[2];
}
} else {
/* Last pixel */
if (blue_line) {
*bgr++ = bayer[0];
*bgr++ = bayer[1];
*bgr++ = adjacent_bayer[1];
} else {
*bgr++ = adjacent_bayer[1];
*bgr++ = bayer[1];
*bgr++ = bayer[0];
}
}
}
/* From libdc1394, which on turn was based on OpenCV's Bayer decoding */
static void bayer_to_rgbbgr24(const unsigned char *bayer,
unsigned char *bgr, int width, int height, const unsigned int stride, unsigned int pixfmt,
int start_with_green, int blue_line)
{
/* render the first line */
v4lconvert_border_bayer_line_to_bgr24(bayer, bayer + stride, bgr, width,
start_with_green, blue_line);
bgr += width * 3;
/* reduce height by 2 because of the special case top/bottom line */
for (height -= 2; height; height--) {
int t0, t1;
/* (width - 2) because of the border */
const unsigned char *bayer_end = bayer + (width - 2);
if (start_with_green) {
t0 = (bayer[1] + bayer[stride * 2 + 1] + 1) >> 1;
/* Write first pixel */
t1 = (bayer[0] + bayer[stride * 2] + bayer[stride + 1] + 1) / 3;
if (blue_line) {
*bgr++ = t0;
*bgr++ = t1;
*bgr++ = bayer[stride];
} else {
*bgr++ = bayer[stride];
*bgr++ = t1;
*bgr++ = t0;
}
/* Write second pixel */
t1 = (bayer[stride] + bayer[stride + 2] + 1) >> 1;
if (blue_line) {
*bgr++ = t0;
*bgr++ = bayer[stride + 1];
*bgr++ = t1;
} else {
*bgr++ = t1;
*bgr++ = bayer[stride + 1];
*bgr++ = t0;
}
bayer++;
} else {
/* Write first pixel */
t0 = (bayer[0] + bayer[stride * 2] + 1) >> 1;
if (blue_line) {
*bgr++ = t0;
*bgr++ = bayer[stride];
*bgr++ = bayer[stride + 1];
} else {
*bgr++ = bayer[stride + 1];
*bgr++ = bayer[stride];
*bgr++ = t0;
}
}
if (blue_line) {
for (; bayer <= bayer_end - 2; bayer += 2) {
t0 = (bayer[0] + bayer[2] + bayer[stride * 2] +
bayer[stride * 2 + 2] + 2) >> 2;
t1 = (bayer[1] + bayer[stride] + bayer[stride + 2] +
bayer[stride * 2 + 1] + 2) >> 2;
*bgr++ = t0;
*bgr++ = t1;
*bgr++ = bayer[stride + 1];
t0 = (bayer[2] + bayer[stride * 2 + 2] + 1) >> 1;
t1 = (bayer[stride + 1] + bayer[stride + 3] + 1) >> 1;
*bgr++ = t0;
*bgr++ = bayer[stride + 2];
*bgr++ = t1;
}
} else {
for (; bayer <= bayer_end - 2; bayer += 2) {
t0 = (bayer[0] + bayer[2] + bayer[stride * 2] +
bayer[stride * 2 + 2] + 2) >> 2;
t1 = (bayer[1] + bayer[stride] + bayer[stride + 2] +
bayer[stride * 2 + 1] + 2) >> 2;
*bgr++ = bayer[stride + 1];
*bgr++ = t1;
*bgr++ = t0;
t0 = (bayer[2] + bayer[stride * 2 + 2] + 1) >> 1;
t1 = (bayer[stride + 1] + bayer[stride + 3] + 1) >> 1;
*bgr++ = t1;
*bgr++ = bayer[stride + 2];
*bgr++ = t0;
}
}
if (bayer < bayer_end) {
/* write second to last pixel */
t0 = (bayer[0] + bayer[2] + bayer[stride * 2] +
bayer[stride * 2 + 2] + 2) >> 2;
t1 = (bayer[1] + bayer[stride] + bayer[stride + 2] +
bayer[stride * 2 + 1] + 2) >> 2;
if (blue_line) {
*bgr++ = t0;
*bgr++ = t1;
*bgr++ = bayer[stride + 1];
} else {
*bgr++ = bayer[stride + 1];
*bgr++ = t1;
*bgr++ = t0;
}
/* write last pixel */
t0 = (bayer[2] + bayer[stride * 2 + 2] + 1) >> 1;
if (blue_line) {
*bgr++ = t0;
*bgr++ = bayer[stride + 2];
*bgr++ = bayer[stride + 1];
} else {
*bgr++ = bayer[stride + 1];
*bgr++ = bayer[stride + 2];
*bgr++ = t0;
}
bayer++;
} else {
/* write last pixel */
t0 = (bayer[0] + bayer[stride * 2] + 1) >> 1;
t1 = (bayer[1] + bayer[stride * 2 + 1] + bayer[stride] + 1) / 3;
if (blue_line) {
*bgr++ = t0;
*bgr++ = t1;
*bgr++ = bayer[stride + 1];
} else {
*bgr++ = bayer[stride + 1];
*bgr++ = t1;
*bgr++ = t0;
}
}
/* skip 2 border pixels and padding */
bayer += (stride - width) + 2;
blue_line = !blue_line;
start_with_green = !start_with_green;
}
/* render the last line */
v4lconvert_border_bayer_line_to_bgr24(bayer + stride, bayer, bgr, width,
!start_with_green, !blue_line);
}
void v4lconvert_bayer_to_rgb24(const unsigned char *bayer,
unsigned char *bgr, int width, int height, const unsigned int stride, unsigned int pixfmt)
{
bayer_to_rgbbgr24(bayer, bgr, width, height, stride, pixfmt,
pixfmt == V4L2_PIX_FMT_SGBRG8 /* start with green */
|| pixfmt == V4L2_PIX_FMT_SGRBG8,
pixfmt != V4L2_PIX_FMT_SBGGR8 /* blue line */
&& pixfmt != V4L2_PIX_FMT_SGBRG8);
}
void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
unsigned char *bgr, int width, int height, const unsigned int stride, unsigned int pixfmt)
{
bayer_to_rgbbgr24(bayer, bgr, width, height, stride, pixfmt,
pixfmt == V4L2_PIX_FMT_SGBRG8 /* start with green */
|| pixfmt == V4L2_PIX_FMT_SGRBG8,
pixfmt == V4L2_PIX_FMT_SBGGR8 /* blue line */
|| pixfmt == V4L2_PIX_FMT_SGBRG8);
}
static void v4lconvert_border_bayer_line_to_y(
const unsigned char *bayer, const unsigned char *adjacent_bayer,
unsigned char *y, int width, int start_with_green, int blue_line)
{
int t0, t1;
if (start_with_green) {
/* First pixel */
if (blue_line) {
*y++ = (8453 * adjacent_bayer[0] + 16594 * bayer[0] +
3223 * bayer[1] + 524288) >> 15;
} else {
*y++ = (8453 * bayer[1] + 16594 * bayer[0] +
3223 * adjacent_bayer[0] + 524288) >> 15;
}
/* Second pixel */
t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
t1 = adjacent_bayer[0] + adjacent_bayer[2];
if (blue_line)
*y++ = (4226 * t1 + 5531 * t0 + 3223 * bayer[1] + 524288) >> 15;
else
*y++ = (8453 * bayer[1] + 5531 * t0 + 1611 * t1 + 524288) >> 15;
bayer++;
adjacent_bayer++;
width -= 2;
} else {
/* First pixel */
t0 = bayer[1] + adjacent_bayer[0];
if (blue_line) {
*y++ = (8453 * adjacent_bayer[1] + 8297 * t0 +
3223 * bayer[0] + 524288) >> 15;
} else {
*y++ = (8453 * bayer[0] + 8297 * t0 +
3223 * adjacent_bayer[1] + 524288) >> 15;
}
width--;
}
if (blue_line) {
for ( ; width > 2; width -= 2) {
t0 = bayer[0] + bayer[2];
*y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] +
1611 * t0 + 524288) >> 15;
bayer++;
adjacent_bayer++;
t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
t1 = adjacent_bayer[0] + adjacent_bayer[2];
*y++ = (4226 * t1 + 5531 * t0 + 3223 * bayer[1] + 524288) >> 15;
bayer++;
adjacent_bayer++;
}
} else {
for ( ; width > 2; width -= 2) {
t0 = bayer[0] + bayer[2];
*y++ = (4226 * t0 + 16594 * bayer[1] +
3223 * adjacent_bayer[1] + 524288) >> 15;
bayer++;
adjacent_bayer++;
t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
t1 = adjacent_bayer[0] + adjacent_bayer[2];
*y++ = (8453 * bayer[1] + 5531 * t0 + 1611 * t1 + 524288) >> 15;
bayer++;
adjacent_bayer++;
}
}
if (width == 2) {
/* Second to last pixel */
t0 = bayer[0] + bayer[2];
if (blue_line) {
*y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] +
1611 * t0 + 524288) >> 15;
} else {
*y++ = (4226 * t0 + 16594 * bayer[1] +
3223 * adjacent_bayer[1] + 524288) >> 15;
}
/* Last pixel */
t0 = bayer[1] + adjacent_bayer[2];
if (blue_line) {
*y++ = (8453 * adjacent_bayer[1] + 8297 * t0 +
3223 * bayer[2] + 524288) >> 15;
} else {
*y++ = (8453 * bayer[2] + 8297 * t0 +
3223 * adjacent_bayer[1] + 524288) >> 15;
}
} else {
/* Last pixel */
if (blue_line) {
*y++ = (8453 * adjacent_bayer[1] + 16594 * bayer[1] +
3223 * bayer[0] + 524288) >> 15;
} else {
*y++ = (8453 * bayer[0] + 16594 * bayer[1] +
3223 * adjacent_bayer[1] + 524288) >> 15;
}
}
}
void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv,
int width, int height, const unsigned int stride, unsigned int src_pixfmt, int yvu)
{
int blue_line = 0, start_with_green = 0, x, y;
unsigned char *ydst = yuv;
unsigned char *udst, *vdst;
if (yvu) {
vdst = yuv + width * height;
udst = vdst + width * height / 4;
} else {
udst = yuv + width * height;
vdst = udst + width * height / 4;
}
/* First calculate the u and v planes 2x2 pixels at a time */
switch (src_pixfmt) {
case V4L2_PIX_FMT_SBGGR8:
for (y = 0; y < height; y += 2) {
for (x = 0; x < width; x += 2) {
int b, g, r;
b = bayer[x];
g = bayer[x + 1];
g += bayer[x + stride];
r = bayer[x + stride + 1];
*udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
*vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15;
}
bayer += 2 * stride;
}
blue_line = 1;
break;
case V4L2_PIX_FMT_SRGGB8:
for (y = 0; y < height; y += 2) {
for (x = 0; x < width; x += 2) {
int b, g, r;
r = bayer[x];
g = bayer[x + 1];
g += bayer[x + stride];
b = bayer[x + stride + 1];
*udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
*vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15;
}
bayer += 2 * stride;
}
break;
case V4L2_PIX_FMT_SGBRG8:
for (y = 0; y < height; y += 2) {
for (x = 0; x < width; x += 2) {
int b, g, r;
g = bayer[x];
b = bayer[x + 1];
r = bayer[x + stride];
g += bayer[x + stride + 1];
*udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
*vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15;
}
bayer += 2 * stride;
}
blue_line = 1;
start_with_green = 1;
break;
case V4L2_PIX_FMT_SGRBG8:
for (y = 0; y < height; y += 2) {
for (x = 0; x < width; x += 2) {
int b, g, r;
g = bayer[x];
r = bayer[x + 1];
b = bayer[x + stride];
g += bayer[x + stride + 1];
*udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
*vdst++ = (14456 * r - 6052 * g - 2351 * b + 4210688) >> 15;
}
bayer += 2 * stride;
}
start_with_green = 1;
break;
}
/* Point bayer back to start of frame */
bayer -= stride * height;
/* render the first line */
v4lconvert_border_bayer_line_to_y(bayer, bayer + stride, ydst, width,
start_with_green, blue_line);
ydst += width;
/* reduce height by 2 because of the border */
for (height -= 2; height; height--) {
int t0, t1;
/* (width - 2) because of the border */
const unsigned char *bayer_end = bayer + (width - 2);
if (start_with_green) {
t0 = bayer[1] + bayer[stride * 2 + 1];
/* Write first pixel */
t1 = bayer[0] + bayer[stride * 2] + bayer[stride + 1];
if (blue_line)
*ydst++ = (8453 * bayer[stride] + 5516 * t1 +
1661 * t0 + 524288) >> 15;
else
*ydst++ = (4226 * t0 + 5516 * t1 +
3223 * bayer[stride] + 524288) >> 15;
/* Write second pixel */
t1 = bayer[stride] + bayer[stride + 2];
if (blue_line)
*ydst++ = (4226 * t1 + 16594 * bayer[stride + 1] +
1611 * t0 + 524288) >> 15;
else
*ydst++ = (4226 * t0 + 16594 * bayer[stride + 1] +
1611 * t1 + 524288) >> 15;
bayer++;
} else {
/* Write first pixel */
t0 = bayer[0] + bayer[stride * 2];
if (blue_line) {
*ydst++ = (8453 * bayer[stride + 1] + 16594 * bayer[stride] +
1661 * t0 + 524288) >> 15;
} else {
*ydst++ = (4226 * t0 + 16594 * bayer[stride] +
3223 * bayer[stride + 1] + 524288) >> 15;
}
}
if (blue_line) {
for (; bayer <= bayer_end - 2; bayer += 2) {
t0 = bayer[0] + bayer[2] + bayer[stride * 2] + bayer[stride * 2 + 2];
t1 = bayer[1] + bayer[stride] + bayer[stride + 2] + bayer[stride * 2 + 1];
*ydst++ = (8453 * bayer[stride + 1] + 4148 * t1 +
806 * t0 + 524288) >> 15;
t0 = bayer[2] + bayer[stride * 2 + 2];
t1 = bayer[stride + 1] + bayer[stride + 3];
*ydst++ = (4226 * t1 + 16594 * bayer[stride + 2] +
1611 * t0 + 524288) >> 15;
}
} else {
for (; bayer <= bayer_end - 2; bayer += 2) {
t0 = bayer[0] + bayer[2] + bayer[stride * 2] + bayer[stride * 2 + 2];
t1 = bayer[1] + bayer[stride] + bayer[stride + 2] + bayer[stride * 2 + 1];
*ydst++ = (2113 * t0 + 4148 * t1 +
3223 * bayer[stride + 1] + 524288) >> 15;
t0 = bayer[2] + bayer[stride * 2 + 2];
t1 = bayer[stride + 1] + bayer[stride + 3];
*ydst++ = (4226 * t0 + 16594 * bayer[stride + 2] +
1611 * t1 + 524288) >> 15;
}
}
if (bayer < bayer_end) {
/* Write second to last pixel */
t0 = bayer[0] + bayer[2] + bayer[stride * 2] + bayer[stride * 2 + 2];
t1 = bayer[1] + bayer[stride] + bayer[stride + 2] + bayer[stride * 2 + 1];
if (blue_line)
*ydst++ = (8453 * bayer[stride + 1] + 4148 * t1 +
806 * t0 + 524288) >> 15;
else
*ydst++ = (2113 * t0 + 4148 * t1 +
3223 * bayer[stride + 1] + 524288) >> 15;
/* write last pixel */
t0 = bayer[2] + bayer[stride * 2 + 2];
if (blue_line) {
*ydst++ = (8453 * bayer[stride + 1] + 16594 * bayer[stride + 2] +
1661 * t0 + 524288) >> 15;
} else {
*ydst++ = (4226 * t0 + 16594 * bayer[stride + 2] +
3223 * bayer[stride + 1] + 524288) >> 15;
}
bayer++;
} else {
/* write last pixel */
t0 = bayer[0] + bayer[stride * 2];
t1 = bayer[1] + bayer[stride * 2 + 1] + bayer[stride];
if (blue_line)
*ydst++ = (8453 * bayer[stride + 1] + 5516 * t1 +
1661 * t0 + 524288) >> 15;
else
*ydst++ = (4226 * t0 + 5516 * t1 +
3223 * bayer[stride + 1] + 524288) >> 15;
}
/* skip 2 border pixels and padding */
bayer += (stride - width) + 2;
blue_line = !blue_line;
start_with_green = !start_with_green;
}
/* render the last line */
v4lconvert_border_bayer_line_to_y(bayer + stride, bayer, ydst, width,
!start_with_green, !blue_line);
}

View File

@@ -0,0 +1,79 @@
/*
# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#ifndef __LIBV4LCONTROL_PRIV_H
#define __LIBV4LCONTROL_PRIV_H
#include "libv4l-plugin.h"
#define V4LCONTROL_SHM_SIZE 4096
#define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01
#define V4LCONTROL_MEMORY_IS_MALLOCED 0x02
struct v4lcontrol_flags_info;
struct v4lcontrol_data {
int fd; /* Device fd */
int bandwidth; /* Connection bandwidth (0 = unknown) */
int flags; /* Flags for this device */
int priv_flags; /* Internal use only flags */
int controls; /* Which controls to use for this device */
unsigned int *shm_values; /* shared memory control value store */
unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */
const struct v4lcontrol_flags_info *flags_info;
void *dev_ops_priv;
const struct libv4l_dev_ops *dev_ops;
};
struct v4lcontrol_flags_info {
unsigned short vendor_id;
unsigned short product_id;
unsigned short product_mask;
const char *dmi_board_vendor;
const char *dmi_board_name;
/* We could also use the USB manufacturer and product strings some devices have
const char *manufacturer;
const char *product; */
int flags;
int default_gamma;
/* Some seldom used dmi strings (for notebooks with bogus info in the board
entries, but usefull info elsewhere). We keep this at the end as to not
polute the initalizers for the normal case. */
/* System (product) vendor / name */
const char *dmi_system_vendor;
const char *dmi_system_name;
/* Board and System versions */
const char *dmi_board_version;
const char *dmi_system_version;
};
struct v4lcontrol_usb_id {
unsigned short vendor_id;
unsigned short product_id;
};
struct v4lcontrol_upside_down_table {
const char **board_vendor;
const char **board_name;
const struct v4lcontrol_usb_id *camera_id;
};
#endif

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
/*
# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#ifndef __LIBV4LCONTROL_H
#define __LIBV4LCONTROL_H
#include "libv4l-plugin.h"
/* Flags */
#define V4LCONTROL_HFLIPPED 0x01
#define V4LCONTROL_VFLIPPED 0x02
#define V4LCONTROL_ROTATED_90_JPEG 0x04
#define V4LCONTROL_WANTS_WB 0x08
#define V4LCONTROL_WANTS_AUTOGAIN 0x10
#define V4LCONTROL_FORCE_TINYJPEG 0x20
/* Masks */
#define V4LCONTROL_WANTS_WB_AUTOGAIN (V4LCONTROL_WANTS_WB | V4LCONTROL_WANTS_AUTOGAIN)
/* Controls */
enum {
V4LCONTROL_WHITEBALANCE,
V4LCONTROL_HFLIP,
V4LCONTROL_VFLIP,
V4LCONTROL_GAMMA,
/* All fake controls above here are auto enabled when not present in hw */
V4LCONTROL_AUTO_ENABLE_COUNT,
V4LCONTROL_AUTOGAIN,
V4LCONTROL_AUTOGAIN_TARGET,
V4LCONTROL_COUNT
};
struct v4lcontrol_data;
struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv,
const struct libv4l_dev_ops *dev_ops, int always_needs_conversion);
void v4lcontrol_destroy(struct v4lcontrol_data *data);
int v4lcontrol_get_bandwidth(struct v4lcontrol_data *data);
/* Functions used by v4lprocessing to get the control state */
int v4lcontrol_get_flags(struct v4lcontrol_data *data);
int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl);
/* Check if the controls have changed since the last time this function
was called */
int v4lcontrol_controls_changed(struct v4lcontrol_data *data);
/* Check if we must go through the conversion path (and thus alloc conversion
buffers, etc. in libv4l2). Note this always return 1 if we *may* need
rotate90 / flipping / processing, as if we actually need this may change
on the fly while the stream is active. */
int v4lcontrol_needs_conversion(struct v4lcontrol_data *data);
/* Functions used by v4lconvert to pass vidioc calls from libv4l2 */
int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg);
int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg);
int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg);
int v4lcontrol_vidioc_g_ext_ctrls(struct v4lcontrol_data *data, void *arg);
int v4lcontrol_vidioc_try_ext_ctrls(struct v4lcontrol_data *data, void *arg);
int v4lcontrol_vidioc_s_ext_ctrls(struct v4lcontrol_data *data, void *arg);
#endif

213
libv4lconvert/cpia1.c Normal file
View File

@@ -0,0 +1,213 @@
/*
# (C) 2010 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include "libv4lconvert-priv.h"
#include <stdlib.h>
#include <string.h>
#define MAGIC_0 0x19
#define MAGIC_1 0x68
#define SUBSAMPLE_420 0
#define SUBSAMPLE_422 1
#define YUVORDER_YUYV 0
#define YUVORDER_UYVY 1
#define NOT_COMPRESSED 0
#define COMPRESSED 1
#define NO_DECIMATION 0
#define DECIMATION_ENAB 1
#define EOI 0xff /* End Of Image */
#define EOL 0xfd /* End Of Line */
#define FRAME_HEADER_SIZE 64
/* CPIA YUYV (sometimes sort of compressed) */
int v4lconvert_cpia1_to_yuv420(struct v4lconvert_data *data,
const unsigned char *src, int src_size,
unsigned char *dest, int width, int height, int yvu)
{
int x, y, ll, compressed;
unsigned char *udest, *vdest;
if (width > 352 || height > 288) {
fprintf(stderr, "FATAL ERROR CPIA1 size > 352x288, please report!\n");
return -1;
}
if (data->previous_frame == NULL) {
data->previous_frame = malloc(352 * 288 * 3 / 2);
if (data->previous_frame == NULL) {
fprintf(stderr, "cpia1 decode error: could not allocate buffer!\n");
return -1;
}
}
if (yvu) {
vdest = dest + width * height;
udest = vdest + width * height / 4;
} else {
udest = dest + width * height;
vdest = udest + width * height / 4;
}
/* Verify header */
if (src_size < FRAME_HEADER_SIZE ||
src[0] != MAGIC_0 || src[1] != MAGIC_1 ||
src[17] != SUBSAMPLE_420 ||
src[18] != YUVORDER_YUYV ||
(src[25] - src[24]) * 8 != width ||
(src[27] - src[26]) * 4 != height ||
(src[28] != NOT_COMPRESSED && src[28] != COMPRESSED) ||
(src[29] != NO_DECIMATION && src[29] != DECIMATION_ENAB)) {
fprintf(stderr, "cpia1 decode error: invalid header\n");
return -1;
}
if (src[29] == DECIMATION_ENAB) {
fprintf(stderr, "cpia1 decode error: decimation is not supported\n");
return -1;
}
compressed = src[28] == COMPRESSED;
src += FRAME_HEADER_SIZE;
src_size -= FRAME_HEADER_SIZE;
if (!compressed) {
for (y = 0; y < height && src_size > 2; y++) {
ll = src[0] | (src[1] << 8);
src += 2;
src_size -= 2;
if (src_size < ll) {
fprintf(stderr, "cpia1 decode error: short frame\n");
return -1;
}
if (src[ll - 1] != EOL) {
fprintf(stderr, "cpia1 decode error: invalid terminated line\n");
return -1;
}
if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
if (ll != 2 * width + 1) {
fprintf(stderr, "cpia1 decode error: invalid uncompressed even ll\n");
return -1;
}
/* copy the Y values */
for (x = 0; x < width; x += 2) {
*dest++ = src[0];
*dest++ = src[2];
src += 4;
}
/* copy the UV values */
src -= 2 * width;
for (x = 0; x < width; x += 2) {
*udest++ = src[1];
*vdest++ = src[3];
src += 4;
}
} else { /* Odd line only Y values */
if (ll != width + 1) {
fprintf(stderr, "cpia1 decode error: invalid uncompressed odd ll\n");
return -1;
}
memcpy(dest, src, width);
dest += width;
src += width;
}
src++; /* Skip EOL */
src_size -= ll;
}
} else { /* compressed */
/* Pre-fill dest with previous frame, as the cpia1 "compression" consists
of simply ommitting certain pixels */
memcpy(dest, data->previous_frame, width * height * 3 / 2);
for (y = 0; y < height && src_size > 2; y++) {
ll = src[0] | (src[1] << 8);
src += 2;
src_size -= 2;
if (src_size < ll) {
fprintf(stderr, "cpia1 decode error: short frame\n");
return -1;
}
if (src[ll - 1] != EOL) {
fprintf(stderr, "cpia1 decode error: invalid terminated line\n");
return -1;
}
/* Do this now as we use ll as loop variable below */
src_size -= ll;
for (x = 0; x < width && ll > 1; ) {
if (*src & 1) { /* skip N pixels */
int skip = *src >> 1;
if (skip & 1) {
fprintf(stderr, "cpia1 decode error: odd number of pixels to skip");
return -1;
}
if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
dest += skip;
udest += skip / 2;
vdest += skip / 2;
} else { /* Odd line only Y values */
dest += skip;
}
x += skip;
src++;
ll--;
} else {
if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
*dest++ = *src++;
*udest++ = *src++;
*dest++ = *src++;
*vdest++ = *src++;
ll -= 4;
} else { /* Odd line only Y values */
*dest++ = *src++;
*dest++ = *src++;
ll -= 2;
}
x += 2;
}
}
if (ll != 1 || x != width) {
fprintf(stderr, "cpia1 decode error: line length mismatch\n");
return -1;
}
src++; /* Skip EOL */
}
}
if (y != height) {
fprintf(stderr, "cpia1 decode error: frame height mismatch\n");
return -1;
}
if (src_size < 4 || src[src_size - 4] != EOI || src[src_size - 3] != EOI ||
src[src_size - 2] != EOI || src[src_size - 1] != EOI) {
fprintf(stderr, "cpia1 decode error: invaled EOI marker\n");
return -1;
}
/* Safe frame for decompression of the next frame */
dest -= width * height;
memcpy(data->previous_frame, dest, width * height * 3 / 2);
return 0;
}

287
libv4lconvert/crop.c Normal file
View File

@@ -0,0 +1,287 @@
/*
# RGB and YUV crop routines
# (C) 2008 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <string.h>
#include "libv4lconvert-priv.h"
static void v4lconvert_reduceandcrop_rgbbgr24(
unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
unsigned int x, y;
int startx = src_fmt->fmt.pix.width / 2 - dest_fmt->fmt.pix.width;
int starty = src_fmt->fmt.pix.height / 2 - dest_fmt->fmt.pix.height;
src += starty * src_fmt->fmt.pix.bytesperline + 3 * startx;
for (y = 0; y < dest_fmt->fmt.pix.height; y++) {
unsigned char *mysrc = src;
for (x = 0; x < dest_fmt->fmt.pix.width; x++) {
*(dest++) = *(mysrc++);
*(dest++) = *(mysrc++);
*(dest++) = *(mysrc++);
mysrc += 3; /* skip one pixel */
}
src += 2 * src_fmt->fmt.pix.bytesperline; /* skip one line */
}
}
static void v4lconvert_crop_rgbbgr24(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
unsigned int x;
int startx = (src_fmt->fmt.pix.width - dest_fmt->fmt.pix.width) / 2;
int starty = (src_fmt->fmt.pix.height - dest_fmt->fmt.pix.height) / 2;
src += starty * src_fmt->fmt.pix.bytesperline + 3 * startx;
for (x = 0; x < dest_fmt->fmt.pix.height; x++) {
memcpy(dest, src, dest_fmt->fmt.pix.width * 3);
src += src_fmt->fmt.pix.bytesperline;
dest += dest_fmt->fmt.pix.bytesperline;
}
}
static void v4lconvert_reduceandcrop_yuv420(
unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
unsigned int x, y;
unsigned int dest_height_half = dest_fmt->fmt.pix.height / 2;
unsigned int dest_width_half = dest_fmt->fmt.pix.width / 2;
int startx = (src_fmt->fmt.pix.width / 2 - dest_fmt->fmt.pix.width) & ~1;
int starty = (src_fmt->fmt.pix.height / 2 - dest_fmt->fmt.pix.height) & ~1;
unsigned char *mysrc, *mysrc2;
/* Y */
mysrc = src + starty * src_fmt->fmt.pix.bytesperline + startx;
for (y = 0; y < dest_fmt->fmt.pix.height; y++) {
mysrc2 = mysrc;
for (x = 0; x < dest_fmt->fmt.pix.width; x++) {
*(dest++) = *mysrc2;
mysrc2 += 2; /* skip one pixel */
}
mysrc += 2 * src_fmt->fmt.pix.bytesperline; /* skip one line */
}
/* U */
mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline +
(starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2;
for (y = 0; y < dest_height_half; y++) {
mysrc2 = mysrc;
for (x = 0; x < dest_width_half; x++) {
*(dest++) = *mysrc2;
mysrc2 += 2; /* skip one pixel */
}
mysrc += src_fmt->fmt.pix.bytesperline ; /* skip one line */
}
/* V */
mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline * 5 / 4
+ (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2;
for (y = 0; y < dest_height_half; y++) {
mysrc2 = mysrc;
for (x = 0; x < dest_width_half; x++) {
*(dest++) = *mysrc2;
mysrc2 += 2; /* skip one pixel */
}
mysrc += src_fmt->fmt.pix.bytesperline ; /* skip one line */
}
}
static void v4lconvert_crop_yuv420(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
unsigned int x;
int startx = ((src_fmt->fmt.pix.width - dest_fmt->fmt.pix.width) / 2) & ~1;
int starty = ((src_fmt->fmt.pix.height - dest_fmt->fmt.pix.height) / 2) & ~1;
unsigned char *mysrc = src + starty * src_fmt->fmt.pix.bytesperline + startx;
/* Y */
for (x = 0; x < dest_fmt->fmt.pix.height; x++) {
memcpy(dest, mysrc, dest_fmt->fmt.pix.width);
mysrc += src_fmt->fmt.pix.bytesperline;
dest += dest_fmt->fmt.pix.bytesperline;
}
/* U */
mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline +
(starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2;
for (x = 0; x < dest_fmt->fmt.pix.height / 2; x++) {
memcpy(dest, mysrc, dest_fmt->fmt.pix.width / 2);
mysrc += src_fmt->fmt.pix.bytesperline / 2;
dest += dest_fmt->fmt.pix.bytesperline / 2;
}
/* V */
mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline * 5 / 4
+ (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2;
for (x = 0; x < dest_fmt->fmt.pix.height / 2; x++) {
memcpy(dest, mysrc, dest_fmt->fmt.pix.width / 2);
mysrc += src_fmt->fmt.pix.bytesperline / 2;
dest += dest_fmt->fmt.pix.bytesperline / 2;
}
}
/* Ok, so this is not really cropping, but more the reverse, whatever */
static void v4lconvert_add_border_rgbbgr24(
unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
int y;
int borderx = (dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2;
int bordery = (dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2;
for (y = 0; y < bordery; y++) {
memset(dest, 0, dest_fmt->fmt.pix.width * 3);
dest += dest_fmt->fmt.pix.bytesperline;
}
for (y = 0; (unsigned)y < src_fmt->fmt.pix.height; y++) {
memset(dest, 0, borderx * 3);
dest += borderx * 3;
memcpy(dest, src, src_fmt->fmt.pix.width * 3);
src += src_fmt->fmt.pix.bytesperline;
dest += src_fmt->fmt.pix.width * 3;
memset(dest, 0, borderx * 3);
dest += dest_fmt->fmt.pix.bytesperline -
(borderx + src_fmt->fmt.pix.width) * 3;
}
for (y = 0; y < bordery; y++) {
memset(dest, 0, dest_fmt->fmt.pix.width * 3);
dest += dest_fmt->fmt.pix.bytesperline;
}
}
static void v4lconvert_add_border_yuv420(
unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
int y;
int borderx = ((dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2) & ~1;
int bordery = ((dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2) & ~1;
/* Y */
for (y = 0; y < bordery; y++) {
memset(dest, 16, dest_fmt->fmt.pix.width);
dest += dest_fmt->fmt.pix.bytesperline;
}
for (y = 0; (unsigned)y < src_fmt->fmt.pix.height; y++) {
memset(dest, 16, borderx);
dest += borderx;
memcpy(dest, src, src_fmt->fmt.pix.width);
src += src_fmt->fmt.pix.bytesperline;
dest += src_fmt->fmt.pix.width;
memset(dest, 16, borderx);
dest += dest_fmt->fmt.pix.bytesperline -
(borderx + src_fmt->fmt.pix.width);
}
for (y = 0; y < bordery; y++) {
memset(dest, 16, dest_fmt->fmt.pix.width);
dest += dest_fmt->fmt.pix.bytesperline;
}
/* U */
for (y = 0; y < bordery / 2; y++) {
memset(dest, 128, dest_fmt->fmt.pix.width / 2);
dest += dest_fmt->fmt.pix.bytesperline / 2;
}
for (y = 0; (unsigned)y < src_fmt->fmt.pix.height / 2; y++) {
memset(dest, 128, borderx / 2);
dest += borderx / 2;
memcpy(dest, src, src_fmt->fmt.pix.width / 2);
src += src_fmt->fmt.pix.bytesperline / 2;
dest += src_fmt->fmt.pix.width / 2;
memset(dest, 128, borderx / 2);
dest += (dest_fmt->fmt.pix.bytesperline -
(borderx + src_fmt->fmt.pix.width)) / 2;
}
for (y = 0; y < bordery / 2; y++) {
memset(dest, 128, dest_fmt->fmt.pix.width / 2);
dest += dest_fmt->fmt.pix.bytesperline / 2;
}
/* V */
for (y = 0; y < bordery / 2; y++) {
memset(dest, 128, dest_fmt->fmt.pix.width / 2);
dest += dest_fmt->fmt.pix.bytesperline / 2;
}
for (y = 0; (unsigned)y < src_fmt->fmt.pix.height / 2; y++) {
memset(dest, 128, borderx / 2);
dest += borderx / 2;
memcpy(dest, src, src_fmt->fmt.pix.width / 2);
src += src_fmt->fmt.pix.bytesperline / 2;
dest += src_fmt->fmt.pix.width / 2;
memset(dest, 128, borderx / 2);
dest += (dest_fmt->fmt.pix.bytesperline -
(borderx + src_fmt->fmt.pix.width)) / 2;
}
for (y = 0; y < bordery / 2; y++) {
memset(dest, 128, dest_fmt->fmt.pix.width / 2);
dest += dest_fmt->fmt.pix.bytesperline / 2;
}
}
void v4lconvert_crop(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
switch (dest_fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
if (src_fmt->fmt.pix.width <= dest_fmt->fmt.pix.width &&
src_fmt->fmt.pix.height <= dest_fmt->fmt.pix.height)
v4lconvert_add_border_rgbbgr24(src, dest, src_fmt, dest_fmt);
else if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width &&
src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height)
v4lconvert_reduceandcrop_rgbbgr24(src, dest, src_fmt, dest_fmt);
else
v4lconvert_crop_rgbbgr24(src, dest, src_fmt, dest_fmt);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
if (src_fmt->fmt.pix.width <= dest_fmt->fmt.pix.width &&
src_fmt->fmt.pix.height <= dest_fmt->fmt.pix.height)
v4lconvert_add_border_yuv420(src, dest, src_fmt, dest_fmt);
else if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width &&
src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height)
v4lconvert_reduceandcrop_yuv420(src, dest, src_fmt, dest_fmt);
else
v4lconvert_crop_yuv420(src, dest, src_fmt, dest_fmt);
break;
}
}

266
libv4lconvert/flip.c Normal file
View File

@@ -0,0 +1,266 @@
/*
# RGB / YUV flip/rotate routines
# (C) 2008 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <string.h>
#include "libv4lconvert-priv.h"
static void v4lconvert_vflip_rgbbgr24(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt)
{
unsigned int y;
src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline;
for (y = 0; y < fmt->fmt.pix.height; y++) {
src -= fmt->fmt.pix.bytesperline;
memcpy(dest, src, fmt->fmt.pix.width * 3);
dest += fmt->fmt.pix.width * 3;
}
}
static void v4lconvert_vflip_yuv420(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt)
{
unsigned int y;
/* First flip the Y plane */
src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline;
for (y = 0; y < fmt->fmt.pix.height; y++) {
src -= fmt->fmt.pix.bytesperline;
memcpy(dest, src, fmt->fmt.pix.width);
dest += fmt->fmt.pix.width;
}
/* Now flip the U plane */
src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline * 5 / 4;
for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
src -= fmt->fmt.pix.bytesperline / 2;
memcpy(dest, src, fmt->fmt.pix.width / 2);
dest += fmt->fmt.pix.width / 2;
}
/* Last flip the V plane */
src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 2;
for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
src -= fmt->fmt.pix.bytesperline / 2;
memcpy(dest, src, fmt->fmt.pix.width / 2);
dest += fmt->fmt.pix.width / 2;
}
}
static void v4lconvert_hflip_rgbbgr24(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt)
{
unsigned int x, y;
for (y = 0; y < fmt->fmt.pix.height; y++) {
src += fmt->fmt.pix.width * 3;
for (x = 0; x < fmt->fmt.pix.width; x++) {
src -= 3;
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest += 3;
}
src += fmt->fmt.pix.bytesperline;
}
}
static void v4lconvert_hflip_yuv420(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt)
{
unsigned int x, y;
/* First flip the Y plane */
for (y = 0; y < fmt->fmt.pix.height; y++) {
src += fmt->fmt.pix.width;
for (x = 0; x < fmt->fmt.pix.width; x++)
*dest++ = *--src;
src += fmt->fmt.pix.bytesperline;
}
/* Now flip the U plane */
for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
src += fmt->fmt.pix.width / 2;
for (x = 0; x < fmt->fmt.pix.width / 2; x++)
*dest++ = *--src;
src += fmt->fmt.pix.bytesperline / 2;
}
/* Last flip the V plane */
for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
src += fmt->fmt.pix.width / 2;
for (x = 0; x < fmt->fmt.pix.width / 2; x++)
*dest++ = *--src;
src += fmt->fmt.pix.bytesperline / 2;
}
}
static void v4lconvert_rotate180_rgbbgr24(const unsigned char *src,
unsigned char *dst, int width, int height)
{
int i;
src += 3 * width * height - 3;
for (i = 0; i < width * height; i++) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst += 3;
src -= 3;
}
}
static void v4lconvert_rotate180_yuv420(const unsigned char *src,
unsigned char *dst, int width, int height)
{
int i;
/* First flip x and y of the Y plane */
src += width * height - 1;
for (i = 0; i < width * height; i++)
*dst++ = *src--;
/* Now flip the U plane */
src += width * height * 5 / 4;
for (i = 0; i < width * height / 4; i++)
*dst++ = *src--;
/* Last flip the V plane */
src += width * height / 2;
for (i = 0; i < width * height / 4; i++)
*dst++ = *src--;
}
static void v4lconvert_rotate90_rgbbgr24(const unsigned char *src,
unsigned char *dst, int destwidth, int destheight)
{
int x, y;
#define srcwidth destheight
#define srcheight destwidth
for (y = 0; y < destheight; y++)
for (x = 0; x < destwidth; x++) {
int offset = ((srcheight - x - 1) * srcwidth + y) * 3;
*dst++ = src[offset++];
*dst++ = src[offset++];
*dst++ = src[offset];
}
}
static void v4lconvert_rotate90_yuv420(const unsigned char *src,
unsigned char *dst, int destwidth, int destheight)
{
int x, y;
/* Y-plane */
for (y = 0; y < destheight; y++)
for (x = 0; x < destwidth; x++) {
int offset = (srcheight - x - 1) * srcwidth + y;
*dst++ = src[offset];
}
/* U-plane */
src += srcwidth * srcheight;
destwidth /= 2;
destheight /= 2;
for (y = 0; y < destheight; y++)
for (x = 0; x < destwidth; x++) {
int offset = (srcheight - x - 1) * srcwidth + y;
*dst++ = src[offset];
}
/* V-plane */
src += srcwidth * srcheight;
for (y = 0; y < destheight; y++)
for (x = 0; x < destwidth; x++) {
int offset = (srcheight - x - 1) * srcwidth + y;
*dst++ = src[offset];
}
}
void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt)
{
int tmp;
tmp = fmt->fmt.pix.width;
fmt->fmt.pix.width = fmt->fmt.pix.height;
fmt->fmt.pix.height = tmp;
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
v4lconvert_rotate90_rgbbgr24(src, dest, fmt->fmt.pix.width,
fmt->fmt.pix.height);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
v4lconvert_rotate90_yuv420(src, dest, fmt->fmt.pix.width,
fmt->fmt.pix.height);
break;
}
v4lconvert_fixup_fmt(fmt);
}
void v4lconvert_flip(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt, int hflip, int vflip)
{
if (vflip && hflip) {
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width,
fmt->fmt.pix.height);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width,
fmt->fmt.pix.height);
break;
}
} else if (hflip) {
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
v4lconvert_hflip_rgbbgr24(src, dest, fmt);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
v4lconvert_hflip_yuv420(src, dest, fmt);
break;
}
} else if (vflip) {
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
v4lconvert_vflip_rgbbgr24(src, dest, fmt);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
v4lconvert_vflip_yuv420(src, dest, fmt);
break;
}
}
/* Our newly written data has no padding */
v4lconvert_fixup_fmt(fmt);
}

View File

@@ -0,0 +1,79 @@
/* Utility functions for decompression helpers
*
* Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
static int v4lconvert_helper_write(int fd, const void *b, size_t count,
char *progname)
{
const unsigned char *buf = b;
size_t ret, written = 0;
while (written < count) {
ret = write(fd, buf + written, count - written);
if (ret == -1) {
if (errno == EINTR)
continue;
if (errno == EPIPE) /* Main program has quited */
exit(0);
fprintf(stderr, "%s: error writing: %s\n", progname, strerror(errno));
return -1;
}
written += ret;
}
return 0;
}
static int v4lconvert_helper_read(int fd, void *b, size_t count,
char *progname)
{
unsigned char *buf = b;
size_t ret, r = 0;
while (r < count) {
ret = read(fd, buf + r, count - r);
if (ret == -1) {
if (errno == EINTR)
continue;
fprintf(stderr, "%s: error reading: %s\n", progname, strerror(errno));
return -1;
}
if (ret == 0) /* EOF */
exit(0);
r += ret;
}
return 0;
}

219
libv4lconvert/helper.c Normal file
View File

@@ -0,0 +1,219 @@
/*
# (C) 2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include "libv4lconvert-priv.h"
#define READ_END 0
#define WRITE_END 1
/* <sigh> Unfortunately I've failed in contact some Authors of decompression
code of out of tree drivers. So I've no permission to relicense their code
their code from GPL to LGPL. To work around this, these decompression
algorithms are put in separate executables and we pipe data through these
to decompress.
The "protocol" is very simple:
From libv4l to the helper the following is send:
int width
int height
int flags
int data length
unsigned char[] data (data length long)
From the helper to libv4l the following is send:
int data length (-1 in case of a decompression error)
unsigned char[] data (not present when a decompression error happened)
*/
static int v4lconvert_helper_start(struct v4lconvert_data *data,
const char *helper)
{
if (pipe(data->decompress_in_pipe)) {
V4LCONVERT_ERR("with helper pipe: %s\n", strerror(errno));
goto error;
}
if (pipe(data->decompress_out_pipe)) {
V4LCONVERT_ERR("with helper pipe: %s\n", strerror(errno));
goto error_close_in_pipe;
}
data->decompress_pid = fork();
if (data->decompress_pid == -1) {
V4LCONVERT_ERR("with helper fork: %s\n", strerror(errno));
goto error_close_out_pipe;
}
if (data->decompress_pid == 0) {
/* We are the child */
/* Closed unused read / write end of the pipes */
close(data->decompress_out_pipe[WRITE_END]);
close(data->decompress_in_pipe[READ_END]);
/* Connect stdin / out to the pipes */
if (dup2(data->decompress_out_pipe[READ_END], STDIN_FILENO) == -1) {
perror("libv4lconvert: error with helper dup2");
exit(1);
}
if (dup2(data->decompress_in_pipe[WRITE_END], STDOUT_FILENO) == -1) {
perror("libv4lconvert: error with helper dup2");
exit(1);
}
/* And execute the helper */
execl(helper, helper, NULL);
/* We should never get here */
perror("libv4lconvert: error starting helper");
exit(1);
} else {
/* Closed unused read / write end of the pipes */
close(data->decompress_out_pipe[READ_END]);
close(data->decompress_in_pipe[WRITE_END]);
}
return 0;
error_close_out_pipe:
close(data->decompress_out_pipe[READ_END]);
close(data->decompress_out_pipe[WRITE_END]);
error_close_in_pipe:
close(data->decompress_in_pipe[READ_END]);
close(data->decompress_in_pipe[WRITE_END]);
error:
return -1;
}
/* IMPROVE ME: we could block SIGPIPE here using pthread_sigmask()
and then in case of EPIPE consume the signal using
sigtimedwait (we need to check if a blocked signal wasn't present
before the write, otherwise we will consume that) and
after consuming the signal try to restart the helper.
Note we currently do not do this, as SIGPIPE only happens if the
decompressor crashes, which in case of an embedded decompressor
would mean end of program, so by not handling SIGPIPE we treat
external decompressors identical. */
static int v4lconvert_helper_write(struct v4lconvert_data *data,
const void *b, size_t count)
{
const unsigned char *buf = b;
size_t ret, written = 0;
while (written < count) {
ret = write(data->decompress_out_pipe[WRITE_END], buf + written,
count - written);
if ((int)ret == -1) {
if (errno == EINTR)
continue;
V4LCONVERT_ERR("writing to helper: %s\n", strerror(errno));
return -1;
}
written += ret;
}
return 0;
}
static int v4lconvert_helper_read(struct v4lconvert_data *data, void *b,
size_t count)
{
unsigned char *buf = b;
size_t ret, r = 0;
while (r < count) {
ret = read(data->decompress_in_pipe[READ_END], buf + r, count - r);
if ((int)ret == -1) {
if (errno == EINTR)
continue;
V4LCONVERT_ERR("reading from helper: %s\n", strerror(errno));
return -1;
}
if (ret == 0) {
V4LCONVERT_ERR("reading from helper: unexpected EOF\n");
return -1;
}
r += ret;
}
return 0;
}
int v4lconvert_helper_decompress(struct v4lconvert_data *data,
const char *helper, const unsigned char *src, int src_size,
unsigned char *dest, int dest_size, int width, int height, int flags)
{
int r;
if (data->decompress_pid == -1) {
if (v4lconvert_helper_start(data, helper))
return -1;
}
if (v4lconvert_helper_write(data, &width, sizeof(int)))
return -1;
if (v4lconvert_helper_write(data, &height, sizeof(int)))
return -1;
if (v4lconvert_helper_write(data, &flags, sizeof(int)))
return -1;
if (v4lconvert_helper_write(data, &src_size, sizeof(int)))
return -1;
if (v4lconvert_helper_write(data, src, src_size))
return -1;
if (v4lconvert_helper_read(data, &r, sizeof(int)))
return -1;
if (r < 0) {
V4LCONVERT_ERR("decompressing frame data\n");
return -1;
}
if (dest_size < r) {
V4LCONVERT_ERR("destination buffer to small\n");
return -1;
}
return v4lconvert_helper_read(data, dest, r);
}
void v4lconvert_helper_cleanup(struct v4lconvert_data *data)
{
int status;
if (data->decompress_pid != -1) {
close(data->decompress_out_pipe[WRITE_END]);
close(data->decompress_in_pipe[READ_END]);
waitpid(data->decompress_pid, &status, 0);
data->decompress_pid = -1;
}
}

158
libv4lconvert/hm12.c Normal file
View File

@@ -0,0 +1,158 @@
/*
cx2341x HM12 conversion routines
(C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License, version 2.1,
as published by the Free Software Foundation.
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 02110-1335 USA
*/
#include "libv4lconvert-priv.h"
#include <string.h>
/* The HM12 format is used in the Conexant cx23415/6/8 MPEG encoder devices.
It is a macroblock format with separate Y and UV planes, each plane
consisting of 16x16 values. All lines are always 720 bytes long. If the
width of the image is less than 720, then the remainder is padding.
The height has to be a multiple of 32 in order to get correct chroma
values.
It is basically a by-product of the MPEG encoding inside the device,
which is available for raw video as a 'bonus feature'.
*/
#define CLIP(color) \
(unsigned char)(((color) > 0xff) ? 0xff : (((color) < 0) ? 0 : (color)))
static const int stride = 720;
static void v4lconvert_hm12_to_rgb(const unsigned char *src, unsigned char *dest,
int width, int height, int rgb)
{
unsigned int y, x, i, j;
const unsigned char *y_base = src;
const unsigned char *uv_base = src + stride * height;
const unsigned char *src_y;
const unsigned char *src_uv;
int mb_size = 256;
int r = rgb ? 0 : 2;
int b = 2 - r;
for (y = 0; y < (unsigned)height; y += 16) {
int mb_y = (y / 16) * (stride / 16);
int mb_uv = (y / 32) * (stride / 16);
int maxy = (height - y < 16 ? height - y : 16);
for (x = 0; x < (unsigned)width; x += 16, mb_y++, mb_uv++) {
int maxx = (width - x < 16 ? width - x : 16);
src_y = y_base + mb_y * mb_size;
src_uv = uv_base + mb_uv * mb_size;
if (y & 0x10)
src_uv += mb_size / 2;
for (i = 0; i < (unsigned)maxy; i++) {
int idx = (x + (y + i) * width) * 3;
for (j = 0; j < (unsigned)maxx; j++) {
int y = src_y[j];
int u = src_uv[j & ~1];
int v = src_uv[j | 1];
int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
int rg = (((u - 128) << 1) + (u - 128) +
((v - 128) << 2) + ((v - 128) << 1)) >> 3;
int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
dest[idx+r] = CLIP(y + v1);
dest[idx+1] = CLIP(y - rg);
dest[idx+b] = CLIP(y + u1);
idx += 3;
}
src_y += 16;
if (i & 1)
src_uv += 16;
}
}
}
}
void v4lconvert_hm12_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height)
{
v4lconvert_hm12_to_rgb(src, dest, width, height, 1);
}
void v4lconvert_hm12_to_bgr24(const unsigned char *src, unsigned char *dest,
int width, int height)
{
v4lconvert_hm12_to_rgb(src, dest, width, height, 0);
}
static void de_macro_uv(unsigned char *dstu, unsigned char *dstv,
const unsigned char *src, int w, int h)
{
unsigned int y, x, i, j;
for (y = 0; y < (unsigned)h; y += 16) {
for (x = 0; x < (unsigned)w; x += 8) {
const unsigned char *src_uv = src + y * stride + x * 32;
int maxy = (h - y < 16 ? h - y : 16);
int maxx = (w - x < 8 ? w - x : 8);
for (i = 0; i < (unsigned)maxy; i++) {
int idx = x + (y + i) * w;
for (j = 0; j < (unsigned)maxx; j++) {
dstu[idx+j] = src_uv[2 * j];
dstv[idx+j] = src_uv[2 * j + 1];
}
src_uv += 16;
}
}
}
}
static void de_macro_y(unsigned char *dst, const unsigned char *src,
int w, int h)
{
unsigned int y, x, i;
for (y = 0; y < (unsigned)h; y += 16) {
for (x = 0; x < (unsigned)w; x += 16) {
const unsigned char *src_y = src + y * stride + x * 16;
int maxy = (h - y < 16 ? h - y : 16);
int maxx = (w - x < 16 ? w - x : 16);
for (i = 0; i < (unsigned)maxy; i++) {
memcpy(dst + x + (y + i) * w, src_y, maxx);
src_y += 16;
}
}
}
}
void v4lconvert_hm12_to_yuv420(const unsigned char *src, unsigned char *dest,
int width, int height, int yvu)
{
de_macro_y(dest, src, width, height);
dest += width * height;
src += stride * height;
if (yvu)
de_macro_uv(dest + width * height / 4, dest, src, width / 2, height / 2);
else
de_macro_uv(dest, dest + width * height / 4, src, width / 2, height / 2);
}

284
libv4lconvert/jidctflt.c Normal file
View File

@@ -0,0 +1,284 @@
/*
* jidctflt.c
*
* Copyright (C) 1994-1998, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
*
* The authors make NO WARRANTY or representation, either express or implied,
* with respect to this software, its quality, accuracy, merchantability, or
* fitness for a particular purpose. This software is provided "AS IS", and you,
* its user, assume the entire risk as to its quality and accuracy.
*
* This software is copyright (C) 1991-1998, Thomas G. Lane.
* All Rights Reserved except as specified below.
*
* Permission is hereby granted to use, copy, modify, and distribute this
* software (or portions thereof) for any purpose, without fee, subject to these
* conditions:
* (1) If any part of the source code for this software is distributed, then this
* README file must be included, with this copyright and no-warranty notice
* unaltered; and any additions, deletions, or changes to the original files
* must be clearly indicated in accompanying documentation.
* (2) If only executable code is distributed, then the accompanying
* documentation must state that "this software is based in part on the work of
* the Independent JPEG Group".
* (3) Permission for use of this software is granted only if the user accepts
* full responsibility for any undesirable consequences; the authors accept
* NO LIABILITY for damages of any kind.
*
* These conditions apply to any software derived from or based on the IJG code,
* not just to the unmodified library. If you use our work, you ought to
* acknowledge us.
*
* Permission is NOT granted for the use of any IJG author's name or company name
* in advertising or publicity relating to this software or products derived from
* it. This software may be referred to only as "the Independent JPEG Group's
* software".
*
* We specifically permit and encourage the use of this software as the basis of
* commercial products, provided that all warranty or liability claims are
* assumed by the product vendor.
*
*
* This file contains a floating-point implementation of the
* inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
* must also perform dequantization of the input coefficients.
*
* This implementation should be more accurate than either of the integer
* IDCT implementations. However, it may not give the same results on all
* machines because of differences in roundoff behavior. Speed will depend
* on the hardware's floating point capacity.
*
* A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
* on each row (or vice versa, but it's more convenient to emit a row at
* a time). Direct algorithms are also available, but they are much more
* complex and seem not to be any faster when reduced to code.
*
* This implementation is based on Arai, Agui, and Nakajima's algorithm for
* scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
* Japanese, but the algorithm is described in the Pennebaker & Mitchell
* JPEG textbook (see REFERENCES section in file README). The following code
* is based directly on figure 4-8 in P&M.
* While an 8-point DCT cannot be done in less than 11 multiplies, it is
* possible to arrange the computation so that many of the multiplies are
* simple scalings of the final outputs. These multiplies can then be
* folded into the multiplications or divisions by the JPEG quantization
* table entries. The AA&N method leaves only 5 multiplies and 29 adds
* to be done in the DCT itself.
* The primary disadvantage of this method is that with a fixed-point
* implementation, accuracy is lost due to imprecise representation of the
* scaled quantization values. However, that problem does not arise if
* we use floating point arithmetic.
*/
#include <stdint.h>
#include "tinyjpeg-internal.h"
#define FAST_FLOAT float
#define DCTSIZE 8
#define DCTSIZE2 (DCTSIZE * DCTSIZE)
#define DEQUANTIZE(coef, quantval) (((FAST_FLOAT) (coef)) * (quantval))
#if defined(__GNUC__) && (defined(__i686__) || defined(__x86_64__))
static inline unsigned char descale_and_clamp(int x, int shift)
{
__asm__ (
"add %3,%1\n"
"\tsar %2,%1\n"
"\tsub $-128,%1\n"
"\tcmovl %5,%1\n" /* Use the sub to compare to 0 */
"\tcmpl %4,%1\n"
"\tcmovg %4,%1\n"
: "=r"(x)
: "0"(x), "Ic"((unsigned char)shift), "ir" (1U << (shift - 1)), "r" (0xff), "r" (0)
);
return x;
}
#else
static inline unsigned char descale_and_clamp(int x, int shift)
{
x += 1UL << (shift - 1);
if (x < 0)
x = (x >> shift) | ((~(0UL)) << (32 - (shift)));
else
x >>= shift;
x += 128;
if (x > 255)
return 255;
if (x < 0)
return 0;
return x;
}
#endif
/*
* Perform dequantization and inverse DCT on one block of coefficients.
*/
void tinyjpeg_idct_float(struct component *compptr, uint8_t *output_buf, int stride)
{
FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
FAST_FLOAT z5, z10, z11, z12, z13;
int16_t *inptr;
FAST_FLOAT *quantptr;
FAST_FLOAT *wsptr;
uint8_t *outptr;
int ctr;
FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
/* Pass 1: process columns from input, store into work array. */
inptr = compptr->DCT;
quantptr = compptr->Q_table;
wsptr = workspace;
for (ctr = DCTSIZE; ctr > 0; ctr--) {
/* Due to quantization, we will usually find that many of the input
* coefficients are zero, especially the AC terms. We can exploit this
* by short-circuiting the IDCT calculation for any column in which all
* the AC terms are zero. In that case each output is equal to the
* DC coefficient (with scale factor as needed).
* With typical images and quantization tables, half or more of the
* column DCT calculations can be simplified this way.
*/
if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
inptr[DCTSIZE*7] == 0) {
/* AC terms all zero */
FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
wsptr[DCTSIZE*0] = dcval;
wsptr[DCTSIZE*1] = dcval;
wsptr[DCTSIZE*2] = dcval;
wsptr[DCTSIZE*3] = dcval;
wsptr[DCTSIZE*4] = dcval;
wsptr[DCTSIZE*5] = dcval;
wsptr[DCTSIZE*6] = dcval;
wsptr[DCTSIZE*7] = dcval;
inptr++; /* advance pointers to next column */
quantptr++;
wsptr++;
continue;
}
/* Even part */
tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
tmp10 = tmp0 + tmp2; /* phase 3 */
tmp11 = tmp0 - tmp2;
tmp13 = tmp1 + tmp3; /* phases 5-3 */
tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
tmp0 = tmp10 + tmp13; /* phase 2 */
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
/* Odd part */
tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
z13 = tmp6 + tmp5; /* phase 6 */
z10 = tmp6 - tmp5;
z11 = tmp4 + tmp7;
z12 = tmp4 - tmp7;
tmp7 = z11 + z13; /* phase 5 */
tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
tmp6 = tmp12 - tmp7; /* phase 2 */
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
wsptr[DCTSIZE*0] = tmp0 + tmp7;
wsptr[DCTSIZE*7] = tmp0 - tmp7;
wsptr[DCTSIZE*1] = tmp1 + tmp6;
wsptr[DCTSIZE*6] = tmp1 - tmp6;
wsptr[DCTSIZE*2] = tmp2 + tmp5;
wsptr[DCTSIZE*5] = tmp2 - tmp5;
wsptr[DCTSIZE*4] = tmp3 + tmp4;
wsptr[DCTSIZE*3] = tmp3 - tmp4;
inptr++; /* advance pointers to next column */
quantptr++;
wsptr++;
}
/* Pass 2: process rows from work array, store into output array. */
/* Note that we must descale the results by a factor of 8 == 2**3. */
wsptr = workspace;
outptr = output_buf;
for (ctr = 0; ctr < DCTSIZE; ctr++) {
/* Rows of zeroes can be exploited in the same way as we did with columns.
* However, the column calculation has created many nonzero AC terms, so
* the simplification applies less often (typically 5% to 10% of the time).
* And testing floats for zero is relatively expensive, so we don't bother.
*/
/* Even part */
tmp10 = wsptr[0] + wsptr[4];
tmp11 = wsptr[0] - wsptr[4];
tmp13 = wsptr[2] + wsptr[6];
tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
tmp0 = tmp10 + tmp13;
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
/* Odd part */
z13 = wsptr[5] + wsptr[3];
z10 = wsptr[5] - wsptr[3];
z11 = wsptr[1] + wsptr[7];
z12 = wsptr[1] - wsptr[7];
tmp7 = z11 + z13;
tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
/* Final output stage: scale down by a factor of 8 and range-limit */
outptr[0] = descale_and_clamp((int)(tmp0 + tmp7), 3);
outptr[7] = descale_and_clamp((int)(tmp0 - tmp7), 3);
outptr[1] = descale_and_clamp((int)(tmp1 + tmp6), 3);
outptr[6] = descale_and_clamp((int)(tmp1 - tmp6), 3);
outptr[2] = descale_and_clamp((int)(tmp2 + tmp5), 3);
outptr[5] = descale_and_clamp((int)(tmp2 - tmp5), 3);
outptr[4] = descale_and_clamp((int)(tmp3 + tmp4), 3);
outptr[3] = descale_and_clamp((int)(tmp3 - tmp4), 3);
wsptr += DCTSIZE; /* advance pointer to next row */
outptr += stride;
}
}

219
libv4lconvert/jl2005bcd.c Normal file
View File

@@ -0,0 +1,219 @@
/* jl2005bcd.c
*
* Converts raw output from Jeilin JL2005B/C/D to Bayer output.
*
* The code is based upon what is found in libgphoto2/camlibs/jl2005c,
* Copyright (c) 2010 Theodore Kilgore <kilgota@auburn.edu>
*
* The decompression code used is
* Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License, version 2.1,
* as published by the Free Software Foundation.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef ANDROID
#include <android-config.h>
#else
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_JPEG
#include "libv4lconvert-priv.h"
#include "jpeg_memsrcdest.h"
#include "libv4lsyscall-priv.h"
#define JPEG_HEADER_SIZE 338
#define JPEG_HEIGHT_OFFSET 94
static int find_eoi(struct v4lconvert_data *data,
const unsigned char *jpeg_data, int jpeg_data_idx, int jpeg_data_size)
{
int i;
for (i = jpeg_data_idx; i < (jpeg_data_size - 1); i++)
if (jpeg_data[i] == 0xff && jpeg_data[i + 1] == 0xd9)
break;
if (i >= (jpeg_data_size - 1)) {
V4LCONVERT_ERR("incomplete jl2005bcd frame\n");
return -1;
}
return i + 2; /* + 2 -> Point to after EOI marker */
}
int v4lconvert_decode_jl2005bcd(struct v4lconvert_data *data,
const unsigned char *src, int src_size,
unsigned char *dest, int width, int height)
{
unsigned char jpeg_stripe[50000];
int q;
struct jpeg_compress_struct cinfo;
struct jpeg_decompress_struct dinfo;
struct jpeg_error_mgr jcerr, jderr;
JOCTET *jpeg_header = NULL;
unsigned long jpeg_header_size = 0;
int i, x, y, x1, y1, jpeg_data_size, jpeg_data_idx, eoi, size;
/* src_size had better be bigger than 16 */
if (src_size < 16)
return 1;
/* The first 16 bytes of src are a raw frame header */
q = src[13] & 0x7f;
if (height != src[4] << 3) {
V4LCONVERT_ERR("Height is %d, not %d\n", src[4] << 3, height);
return 1;
}
if (width != src[5] << 3) {
V4LCONVERT_ERR("Width is %d, not %d\n", src[5] << 3, width);
return 1;
}
/*
* And the fun begins, first of all create a dummy jpeg, which we use
* to get the headers from to feed to libjpeg when decompressing the
* stripes. This way we can use libjpeg's quant table handling
* (and built in default huffman tables).
*/
cinfo.err = jpeg_std_error (&jcerr);
jpeg_create_compress (&cinfo);
jpeg_mem_dest (&cinfo, &jpeg_header, &jpeg_header_size);
cinfo.image_width = 16;
cinfo.image_height = 16;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults (&cinfo);
/* Make comp[0] (which will be green) 1x2 subsampled */
cinfo.comp_info[0].h_samp_factor = 1;
cinfo.comp_info[0].v_samp_factor = 2;
/* Make comp[1] and [2] use huffman table and quanttable 0, as all
* components use luminance settings with the jl2005c/d/e */
cinfo.comp_info[1].quant_tbl_no = 0;
cinfo.comp_info[1].dc_tbl_no = 0;
cinfo.comp_info[1].ac_tbl_no = 0;
cinfo.comp_info[2].quant_tbl_no = 0;
cinfo.comp_info[2].dc_tbl_no = 0;
cinfo.comp_info[2].ac_tbl_no = 0;
/* Apply the quality setting from the header */
if (q <= 0)
i = 5000;
else if (q <= 50)
i = 5000 / q;
else if (q <= 100)
i = 2 * (100 - q);
else
i = 0;
jpeg_set_linear_quality(&cinfo, i, TRUE);
jpeg_start_compress (&cinfo, TRUE);
while( cinfo.next_scanline < cinfo.image_height ) {
JOCTET row[16 * 3];
JSAMPROW row_pointer[1] = { row };
jpeg_write_scanlines (&cinfo, row_pointer, 1);
}
jpeg_finish_compress (&cinfo);
jpeg_destroy_compress (&cinfo);
JSAMPLE green[8 * 16];
JSAMPLE red[8 * 8];
JSAMPLE blue[8 * 8];
JSAMPROW green_row_pointer[16];
JSAMPROW red_row_pointer[8];
JSAMPROW blue_row_pointer[8];
for (i = 0; i < 16; i++)
green_row_pointer[i] = green + i * 8;
for (i = 0; i < 8; i++) {
red_row_pointer[i] = red + i * 8;
blue_row_pointer[i] = blue + i * 8;
}
JSAMPARRAY samp_image[3] = { green_row_pointer,
red_row_pointer,
blue_row_pointer };
memcpy(jpeg_stripe, jpeg_header, JPEG_HEADER_SIZE);
jpeg_stripe[JPEG_HEIGHT_OFFSET ] = height >> 8;
jpeg_stripe[JPEG_HEIGHT_OFFSET + 1] = height;
jpeg_stripe[JPEG_HEIGHT_OFFSET + 2] = 0;
jpeg_stripe[JPEG_HEIGHT_OFFSET + 3] = 8;
free (jpeg_header);
/* Get past the raw frame header. */
src += 16;
jpeg_data_size = src_size - 16;
jpeg_data_idx = 0;
dinfo.err = jpeg_std_error (&jderr);
jpeg_create_decompress (&dinfo);
for (x = 0; x < width; x += 16) {
eoi = find_eoi(data, src, jpeg_data_idx, jpeg_data_size);
if (eoi < 0)
return eoi;
size = eoi - jpeg_data_idx;
if ((JPEG_HEADER_SIZE + size) > sizeof(jpeg_stripe)) {
V4LCONVERT_ERR("stripe size too big %d > %zd\n",
JPEG_HEADER_SIZE + size,
sizeof(jpeg_stripe));
return 1;
}
memcpy (jpeg_stripe + JPEG_HEADER_SIZE,
src + jpeg_data_idx, size);
jpeg_mem_src (&dinfo, jpeg_stripe, JPEG_HEADER_SIZE + size);
jpeg_read_header (&dinfo, TRUE);
dinfo.raw_data_out = TRUE;
#if JPEG_LIB_VERSION >= 70
dinfo.do_fancy_upsampling = FALSE;
#endif
jpeg_start_decompress (&dinfo);
for (y = 0; y < height; y += 16) {
jpeg_read_raw_data (&dinfo, samp_image, 16);
for (y1 = 0; y1 < 16; y1 += 2) {
for (x1 = 0; x1 < 16; x1 += 2) {
dest[((y + y1 + 0) * width
+ x + x1 + 0)]
= red[y1 * 4 + x1 / 2];
dest[((y + y1 + 0) * width
+ x + x1 + 1)]
= green[y1 * 8 + x1 / 2];
dest[((y + y1 + 1) * width
+ x + x1 + 0)]
= green[y1 * 8 + 8 + x1 / 2];
dest[((y + y1 + 1) * width
+ x + x1 + 1)]
= blue[y1 * 4 + x1 / 2];
}
}
}
jpeg_finish_decompress (&dinfo);
/* Set jpeg_data_idx for the next stripe */
jpeg_data_idx = (jpeg_data_idx + size + 0x0f) & ~0x0f;
}
jpeg_destroy_decompress(&dinfo);
return 0;
}
#endif /* HAVE_JPEG */

428
libv4lconvert/jpeg.c Normal file
View File

@@ -0,0 +1,428 @@
/*
# (C) 2008-2011 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#ifdef ANDROID
#include <android-config.h>
#else
#include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include "libv4lconvert-priv.h"
#ifdef HAVE_JPEG
#include "jpeg_memsrcdest.h"
#endif
int v4lconvert_decode_jpeg_tinyjpeg(struct v4lconvert_data *data,
unsigned char *src, int src_size, unsigned char *dest,
struct v4l2_format *fmt, unsigned int dest_pix_fmt, int flags)
{
int result = 0;
unsigned char *components[3];
unsigned int header_width, header_height;
unsigned int width = fmt->fmt.pix.width;
unsigned int height = fmt->fmt.pix.height;
if (!data->tinyjpeg) {
data->tinyjpeg = tinyjpeg_init();
if (!data->tinyjpeg)
return v4lconvert_oom_error(data);
}
flags |= TINYJPEG_FLAGS_MJPEG_TABLE;
tinyjpeg_set_flags(data->tinyjpeg, flags);
if (tinyjpeg_parse_header(data->tinyjpeg, src, src_size)) {
V4LCONVERT_ERR("parsing JPEG header: %s",
tinyjpeg_get_errorstring(data->tinyjpeg));
errno = EAGAIN;
return -1;
}
tinyjpeg_get_size(data->tinyjpeg, &header_width, &header_height);
if (data->control_flags & V4LCONTROL_ROTATED_90_JPEG) {
unsigned int tmp = width;
width = height;
height = tmp;
}
if (header_width != width || header_height != height) {
V4LCONVERT_ERR("unexpected width / height in JPEG header: "
"expected: %ux%u, header: %ux%u\n",
width, height, header_width, header_height);
errno = EIO;
return -1;
}
fmt->fmt.pix.width = header_width;
fmt->fmt.pix.height = header_height;
components[0] = dest;
switch (dest_pix_fmt) {
case V4L2_PIX_FMT_RGB24:
tinyjpeg_set_components(data->tinyjpeg, components, 1);
result = tinyjpeg_decode(data->tinyjpeg, TINYJPEG_FMT_RGB24);
break;
case V4L2_PIX_FMT_BGR24:
tinyjpeg_set_components(data->tinyjpeg, components, 1);
result = tinyjpeg_decode(data->tinyjpeg, TINYJPEG_FMT_BGR24);
break;
case V4L2_PIX_FMT_YUV420:
components[1] = components[0] + width * height;
components[2] = components[1] + width * height / 4;
tinyjpeg_set_components(data->tinyjpeg, components, 3);
result = tinyjpeg_decode(data->tinyjpeg, TINYJPEG_FMT_YUV420P);
break;
case V4L2_PIX_FMT_YVU420:
components[2] = components[0] + width * height;
components[1] = components[2] + width * height / 4;
tinyjpeg_set_components(data->tinyjpeg, components, 3);
result = tinyjpeg_decode(data->tinyjpeg, TINYJPEG_FMT_YUV420P);
break;
}
if (result) {
/* The JPEG header checked out ok but we got an error
during decompression. Some webcams, esp pixart and
sn9c20x based ones regulary generate corrupt frames,
which are best thrown away to avoid flashes in the
video stream. We use EPIPE to signal the upper layer
we have some video data, but it is incomplete.
The upper layer (usually libv4l2) should respond to
this by trying a number of times to get a new frame
and if that fails just passing up whatever we did
manage to decompress. */
V4LCONVERT_ERR("decompressing JPEG: %s",
tinyjpeg_get_errorstring(data->tinyjpeg));
errno = EPIPE;
return -1;
}
return 0;
}
#ifdef HAVE_JPEG
static void jerr_error_exit(j_common_ptr cinfo)
{
struct v4lconvert_data *data = cinfo->client_data;
longjmp(data->jerr_jmp_state, data->jerr_errno);
}
static void jerr_emit_message(j_common_ptr cinfo, int msg_level)
{
char buffer[JMSG_LENGTH_MAX];
struct v4lconvert_data *data = cinfo->client_data;
/* < -1 error, == -1 warning, >= 0 trace */
if (msg_level < -1)
return;
cinfo->err->format_message(cinfo, buffer);
snprintf(data->error_msg, V4LCONVERT_ERROR_MSG_SIZE,
"v4l-convert: libjpeg error: %s\n", buffer);
}
static void init_libjpeg_cinfo(struct v4lconvert_data *data)
{
struct jpeg_compress_struct cinfo;
unsigned char *jpeg_header = NULL;
unsigned long jpeg_header_size = 0;
if (data->cinfo_initialized)
return;
/* Setup our error handling */
jpeg_std_error(&data->jerr);
data->jerr.error_exit = jerr_error_exit;
data->jerr.emit_message = jerr_emit_message;
/* Create a jpeg compression object with default params and write
default jpeg headers to a mem buffer, so that we can use them to
pre-fill a jpeg_decompress_struct with default quant and huffman
tables, so that libjpeg can be used to parse [m]jpg-s with
incomplete headers */
cinfo.err = &data->jerr;
cinfo.client_data = data;
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &jpeg_header, &jpeg_header_size);
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_write_tables(&cinfo);
jpeg_destroy_compress(&cinfo);
/* Init the jpeg_decompress_struct */
data->cinfo.err = &data->jerr;
data->cinfo.client_data = data;
jpeg_create_decompress(&data->cinfo);
jpeg_mem_src(&data->cinfo, jpeg_header, jpeg_header_size);
jpeg_read_header(&data->cinfo, FALSE);
free(jpeg_header);
data->cinfo_initialized = 1;
}
static int decode_libjpeg_h_samp1(struct v4lconvert_data *data,
unsigned char *ydest, unsigned char *udest, unsigned char *vdest,
int v_samp)
{
struct jpeg_decompress_struct *cinfo = &data->cinfo;
int x, y;
unsigned char *uv_buf;
unsigned int width = cinfo->image_width;
JSAMPROW y_rows[16], u_rows[8], v_rows[8];
JSAMPARRAY rows[3] = { y_rows, u_rows, v_rows };
uv_buf = v4lconvert_alloc_buffer(width * 16,
&data->convert_pixfmt_buf,
&data->convert_pixfmt_buf_size);
if (!uv_buf)
return v4lconvert_oom_error(data);
for (y = 0; y < 8; y++) {
u_rows[y] = uv_buf;
uv_buf += width;
v_rows[y] = uv_buf;
uv_buf += width;
}
uv_buf -= width * 16;
while (cinfo->output_scanline < cinfo->image_height) {
for (y = 0; y < 8 * v_samp; y++) {
y_rows[y] = ydest;
ydest += cinfo->image_width;
}
y = jpeg_read_raw_data(cinfo, rows, 8 * v_samp);
if (y != 8 * v_samp)
return -1;
/* For v_samp == 1 skip copying uv vals every other time */
if (cinfo->output_scanline % 16)
continue;
/* Copy over every other u + v pixel for 8 lines */
for (y = 0; y < 8; y++) {
for (x = 0; x < width; x += 2) {
*udest++ = *uv_buf++;
uv_buf++;
}
for (x = 0; x < width; x += 2) {
*vdest++ = *uv_buf++;
uv_buf++;
}
}
uv_buf -= width * 16;
}
return 0;
}
static int decode_libjpeg_h_samp2(struct v4lconvert_data *data,
unsigned char *ydest, unsigned char *udest, unsigned char *vdest,
int v_samp)
{
struct jpeg_decompress_struct *cinfo = &data->cinfo;
int y;
unsigned int width = cinfo->image_width;
JSAMPROW y_rows[16], u_rows[8], v_rows[8];
JSAMPARRAY rows[3] = { y_rows, u_rows, v_rows };
while (cinfo->output_scanline < cinfo->image_height) {
for (y = 0; y < 8 * v_samp; y++) {
y_rows[y] = ydest;
ydest += width;
}
/*
* For v_samp == 1 were going to get 1 set of uv values per
* line, but we need only 1 set per 2 lines since our output
* has v_samp == 2. We store every 2 sets in 1 line,
* effectively using the second set for each output line.
*/
if (v_samp == 1) {
for (y = 0; y < 8; y++) {
u_rows[y] = udest;
v_rows[y] = vdest;
y++;
u_rows[y] = udest;
v_rows[y] = vdest;
udest += width / 2;
vdest += width / 2;
}
} else { /* v_samp == 2 */
for (y = 0; y < 8; y++) {
u_rows[y] = udest;
v_rows[y] = vdest;
udest += width / 2;
vdest += width / 2;
}
}
y = jpeg_read_raw_data(cinfo, rows, 8 * v_samp);
if (y != 8 * v_samp)
return -1;
}
return 0;
}
int v4lconvert_decode_jpeg_libjpeg(struct v4lconvert_data *data,
unsigned char *src, int src_size, unsigned char *dest,
struct v4l2_format *fmt, unsigned int dest_pix_fmt)
{
unsigned int width = fmt->fmt.pix.width;
unsigned int height = fmt->fmt.pix.height;
int result = 0;
/* libjpeg errors before decoding the first line should signal EAGAIN */
data->jerr_errno = EAGAIN;
result = setjmp(data->jerr_jmp_state);
if (result) {
if (data->cinfo_initialized)
jpeg_abort_decompress(&data->cinfo);
errno = result;
return -1;
}
init_libjpeg_cinfo(data);
jpeg_mem_src(&data->cinfo, src, src_size);
jpeg_read_header(&data->cinfo, TRUE);
if (data->cinfo.image_width != width ||
data->cinfo.image_height != height) {
V4LCONVERT_ERR("unexpected width / height in JPEG header: "
"expected: %ux%u, header: %ux%u\n", width,
height, data->cinfo.image_width,
data->cinfo.image_height);
errno = EIO;
return -1;
}
if (data->cinfo.num_components != 3) {
V4LCONVERT_ERR("unexpected no components in JPEG: %d\n",
data->cinfo.num_components);
errno = EIO;
return -1;
}
if (dest_pix_fmt == V4L2_PIX_FMT_RGB24 ||
dest_pix_fmt == V4L2_PIX_FMT_BGR24) {
JSAMPROW row_pointer[1];
#ifdef JCS_EXTENSIONS
if (dest_pix_fmt == V4L2_PIX_FMT_BGR24)
data->cinfo.out_color_space = JCS_EXT_BGR;
#endif
row_pointer[0] = dest;
jpeg_start_decompress(&data->cinfo);
/* Make libjpeg errors report that we've got some data */
data->jerr_errno = EPIPE;
while (data->cinfo.output_scanline < height) {
jpeg_read_scanlines(&data->cinfo, row_pointer, 1);
row_pointer[0] += 3 * width;
}
jpeg_finish_decompress(&data->cinfo);
#ifndef JCS_EXTENSIONS
if (dest_pix_fmt == V4L2_PIX_FMT_BGR24)
v4lconvert_swap_rgb(dest, dest, width, height);
#endif
} else {
int h_samp, v_samp;
unsigned char *udest, *vdest;
if (data->cinfo.max_h_samp_factor == 2 &&
data->cinfo.cur_comp_info[0]->h_samp_factor == 2 &&
data->cinfo.cur_comp_info[1]->h_samp_factor == 1 &&
data->cinfo.cur_comp_info[2]->h_samp_factor == 1) {
h_samp = 2;
#if 0 /* HDG: untested, disable for now */
} else if (data->cinfo.max_h_samp_factor == 1 &&
data->cinfo.cur_comp_info[0]->h_samp_factor == 1 &&
data->cinfo.cur_comp_info[1]->h_samp_factor == 1 &&
data->cinfo.cur_comp_info[2]->h_samp_factor == 1) {
h_samp = 1;
#endif
} else {
fprintf(stderr,
"libv4lconvert: unsupported jpeg h-sampling "
"factors %d:%d:%d, please report this to "
"hdegoede@redhat.com\n",
data->cinfo.cur_comp_info[0]->h_samp_factor,
data->cinfo.cur_comp_info[1]->h_samp_factor,
data->cinfo.cur_comp_info[2]->h_samp_factor);
errno = EOPNOTSUPP;
return -1;
}
if (data->cinfo.max_v_samp_factor == 2 &&
data->cinfo.cur_comp_info[0]->v_samp_factor == 2 &&
data->cinfo.cur_comp_info[1]->v_samp_factor == 1 &&
data->cinfo.cur_comp_info[2]->v_samp_factor == 1) {
v_samp = 2;
} else if (data->cinfo.max_v_samp_factor == 1 &&
data->cinfo.cur_comp_info[0]->v_samp_factor == 1 &&
data->cinfo.cur_comp_info[1]->v_samp_factor == 1 &&
data->cinfo.cur_comp_info[2]->v_samp_factor == 1) {
v_samp = 1;
} else {
fprintf(stderr,
"libv4lconvert: unsupported jpeg v-sampling "
"factors %d:%d:%d, please report this to "
"hdegoede@redhat.com\n",
data->cinfo.cur_comp_info[0]->v_samp_factor,
data->cinfo.cur_comp_info[1]->v_samp_factor,
data->cinfo.cur_comp_info[2]->v_samp_factor);
errno = EOPNOTSUPP;
return -1;
}
/* We don't want any padding as that may overflow our dest */
if (width % (8 * h_samp) || height % (8 * v_samp)) {
V4LCONVERT_ERR(
"resolution is not a multiple of dctsize");
errno = EIO;
return -1;
}
if (dest_pix_fmt == V4L2_PIX_FMT_YVU420) {
vdest = dest + width * height;
udest = vdest + (width * height) / 4;
} else {
udest = dest + width * height;
vdest = udest + (width * height) / 4;
}
data->cinfo.raw_data_out = TRUE;
data->cinfo.do_fancy_upsampling = FALSE;
jpeg_start_decompress(&data->cinfo);
/* Make libjpeg errors report that we've got some data */
data->jerr_errno = EPIPE;
if (h_samp == 1) {
result = decode_libjpeg_h_samp1(data, dest, udest,
vdest, v_samp);
} else {
result = decode_libjpeg_h_samp2(data, dest, udest,
vdest, v_samp);
}
if (result)
jpeg_abort_decompress(&data->cinfo);
else
jpeg_finish_decompress(&data->cinfo);
}
return result;
}
#endif // HAVE_JPEG

View File

@@ -0,0 +1,313 @@
/*
* memsrc.c
*
* Copyright (C) 1994-1996, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains decompression data source routines for the case of
* reading JPEG data from a memory buffer that is preloaded with the entire
* JPEG file. This would not seem especially useful at first sight, but
* a number of people have asked for it.
* This is really just a stripped-down version of jdatasrc.c. Comparison
* of this code with jdatasrc.c may be helpful in seeing how to make
* custom source managers for other purposes.
*/
/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
#ifdef ANDROID
#include <android-config.h>
#else
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_JPEG
#include <jpeglib.h>
#include <jerror.h>
#include "jpeg_memsrcdest.h"
/* libjpeg8 and later come with their own (API compatible) memory source
and dest */
#if JPEG_LIB_VERSION < 80
/* Expanded data source object for memory input */
typedef struct {
struct jpeg_source_mgr pub; /* public fields */
JOCTET eoi_buffer[2]; /* a place to put a dummy EOI */
} my_source_mgr;
typedef my_source_mgr * my_src_ptr;
/*
* Initialize source --- called by jpeg_read_header
* before any data is actually read.
*/
METHODDEF(void)
init_source (j_decompress_ptr cinfo)
{
/* No work, since jpeg_mem_src set up the buffer pointer and count.
* Indeed, if we want to read multiple JPEG images from one buffer,
* this *must* not do anything to the pointer.
*/
}
/*
* Fill the input buffer --- called whenever buffer is emptied.
*
* In this application, this routine should never be called; if it is called,
* the decompressor has overrun the end of the input buffer, implying we
* supplied an incomplete or corrupt JPEG datastream. A simple error exit
* might be the most appropriate response.
*
* But what we choose to do in this code is to supply dummy EOI markers
* in order to force the decompressor to finish processing and supply
* some sort of output image, no matter how corrupted.
*/
METHODDEF(boolean)
fill_input_buffer (j_decompress_ptr cinfo)
{
my_src_ptr src = (my_src_ptr) cinfo->src;
WARNMS(cinfo, JWRN_JPEG_EOF);
/* Create a fake EOI marker */
src->eoi_buffer[0] = (JOCTET) 0xFF;
src->eoi_buffer[1] = (JOCTET) JPEG_EOI;
src->pub.next_input_byte = src->eoi_buffer;
src->pub.bytes_in_buffer = 2;
return TRUE;
}
/*
* Skip data --- used to skip over a potentially large amount of
* uninteresting data (such as an APPn marker).
*
* If we overrun the end of the buffer, we let fill_input_buffer deal with
* it. An extremely large skip could cause some time-wasting here, but
* it really isn't supposed to happen ... and the decompressor will never
* skip more than 64K anyway.
*/
METHODDEF(void)
skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
my_src_ptr src = (my_src_ptr) cinfo->src;
if (num_bytes > 0) {
while (num_bytes > (long) src->pub.bytes_in_buffer) {
num_bytes -= (long) src->pub.bytes_in_buffer;
(void) fill_input_buffer(cinfo);
/* note we assume that fill_input_buffer will never
* return FALSE, so suspension need not be handled.
*/
}
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
/*
* An additional method that can be provided by data source modules is the
* resync_to_restart method for error recovery in the presence of RST markers.
* For the moment, this source module just uses the default resync method
* provided by the JPEG library. That method assumes that no backtracking
* is possible.
*/
/*
* Terminate source --- called by jpeg_finish_decompress
* after all data has been read. Often a no-op.
*
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
* application must deal with any cleanup that should happen even
* for error exit.
*/
METHODDEF(void)
term_source (j_decompress_ptr cinfo)
{
/* no work necessary here */
}
/*
* Prepare for input from a memory buffer.
*/
GLOBAL(void)
jpeg_mem_src (j_decompress_ptr cinfo, unsigned char * buffer,
unsigned long bufsize)
{
my_src_ptr src;
/* The source object is made permanent so that a series of JPEG images
* can be read from a single buffer by calling jpeg_mem_src
* only before the first one.
* This makes it unsafe to use this manager and a different source
* manager serially with the same JPEG object. Caveat programmer.
*/
if (cinfo->src == NULL) { /* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
JPOOL_PERMANENT,
sizeof(my_source_mgr));
}
src = (my_src_ptr) cinfo->src;
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_input_buffer;
src->pub.skip_input_data = skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->pub.term_source = term_source;
src->pub.next_input_byte = buffer;
src->pub.bytes_in_buffer = bufsize;
}
/* Memory destination source modelled after Thomas G. Lane's memory source
support and jdatadst.c
Copyright (C) 2010, Hans de Goede
This code may be used under the same conditions as Thomas G. Lane's memory
source (see the copyright header at the top of this file).
*/
typedef struct {
struct jpeg_destination_mgr pub; /* public fields */
JOCTET **buffer; /* start of buffer */
unsigned long buf_size, *outsize;
} my_destination_mgr;
typedef my_destination_mgr * my_dest_ptr;
#define OUTPUT_BUF_SIZE 32768 /* choose an efficiently fwrite'able size */
/*
* Initialize destination --- called by jpeg_start_compress
* before any data is actually written.
*/
METHODDEF(void)
init_destination (j_compress_ptr cinfo)
{
/* No work, since jpeg_mem_dest set up the buffer pointer and count.
* Indeed, if we want to write multiple JPEG images to one buffer,
* this *must* not do anything to the pointer.
*/
}
/*
* Empty the output buffer --- called whenever buffer fills up.
*
* In typical applications, this should write the entire output buffer
* (ignoring the current state of next_output_byte & free_in_buffer),
* reset the pointer & count to the start of the buffer, and return TRUE
* indicating that the buffer has been dumped.
*
* In applications that need to be able to suspend compression due to output
* overrun, a FALSE return indicates that the buffer cannot be emptied now.
* In this situation, the compressor will return to its caller (possibly with
* an indication that it has not accepted all the supplied scanlines). The
* application should resume compression after it has made more room in the
* output buffer. Note that there are substantial restrictions on the use of
* suspension --- see the documentation.
*
* When suspending, the compressor will back up to a convenient restart point
* (typically the start of the current MCU). next_output_byte & free_in_buffer
* indicate where the restart point will be if the current call returns FALSE.
* Data beyond this point will be regenerated after resumption, so do not
* write it out when emptying the buffer externally.
*/
METHODDEF(boolean)
empty_output_buffer (j_compress_ptr cinfo)
{
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
*dest->buffer = realloc (*dest->buffer, dest->buf_size + OUTPUT_BUF_SIZE);
if (!*dest->buffer)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
dest->pub.next_output_byte = *dest->buffer + dest->buf_size;
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
dest->buf_size += OUTPUT_BUF_SIZE;
return TRUE;
}
/*
* Terminate destination --- called by jpeg_finish_compress
* after all data has been written. Usually needs to flush buffer.
*
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
* application must deal with any cleanup that should happen even
* for error exit.
*/
METHODDEF(void)
term_destination (j_compress_ptr cinfo)
{
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
*dest->outsize = dest->buf_size - dest->pub.free_in_buffer;
}
GLOBAL(void)
jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer,
unsigned long * outsize)
{
my_dest_ptr dest;
/* The destination object is made permanent so that multiple JPEG images
* can be written to the same file without re-executing jpeg_stdio_dest.
* This makes it dangerous to use this manager and a different destination
* manager serially with the same JPEG object, because their private object
* sizes may be different. Caveat programmer.
*/
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
JPOOL_PERMANENT,
sizeof(my_destination_mgr));
}
dest = (my_dest_ptr) cinfo->dest;
dest->pub.init_destination = init_destination;
dest->pub.empty_output_buffer = empty_output_buffer;
dest->pub.term_destination = term_destination;
dest->buffer = outbuffer;
dest->buf_size = *outsize;
dest->outsize = outsize;
if (*dest->buffer == NULL || dest->buf_size == 0) {
/* Allocate initial buffer */
*dest->buffer = malloc(OUTPUT_BUF_SIZE);
if (*dest->buffer == NULL)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
dest->buf_size = OUTPUT_BUF_SIZE;
}
dest->pub.next_output_byte = *dest->buffer;
dest->pub.free_in_buffer = dest->buf_size;
}
#endif /* JPEG_LIB_VERSION < 80 */
#endif /* HAVE_JPEG */

View File

@@ -0,0 +1,13 @@
#include <jpeglib.h>
#if JPEG_LIB_VERSION < 80
void
jpeg_mem_src (j_decompress_ptr cinfo, unsigned char * buffer,
unsigned long bufsize);
void
jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer,
unsigned long * outsize);
#endif

727
libv4lconvert/jpgl.c Normal file
View File

@@ -0,0 +1,727 @@
/*
* Implementation of JPEG Lite decoding algorithm
*
* Author & Copyright (c) 2003 : Sylvain Munaut <nw8xx ]at[ 246tNt.com>
*
* v4l library adaptation: Jean-François Moine <moinejf@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License, version 2.1,
* as published by the Free Software Foundation.
*
* 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 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 02110-1335 USA
* Note this code was originally licensed under the GNU GPL instead of the
* GNU LGPL, its license has been changed with permission, see the permission
* mail at the end of this file.
*/
/* Original WebSite: nw802.sourceforge.net */
#include <stdlib.h>
#include "libv4lconvert-priv.h"
#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n))
#define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri)])
struct RingQueue {
const unsigned char *queue;
int length;
int ri;
};
/* ============================================================================
* RingQueue bit reader
* ============================================================================
* All what is needed to read bit by nit from the RingQueue pump
* provided by usbvideo
* Critical part are macro and not functions to speed things up
* Rem: Data are read from the RingQueue as if they were 16bits Little Endian
* words. Most Significants Bits are outputed first.
*/
/* Structure used to store what we need. */
/* (We may need multiple simultaneous instance from several cam) */
struct rqBitReader {
int cur_bit;
unsigned int cur_data;
struct RingQueue *rq;
};
static inline void rqBR_init( struct rqBitReader *br, struct RingQueue *rq )
{
br->cur_bit = 16;
br->cur_data =
RING_QUEUE_PEEK( rq, 2 ) |
RING_QUEUE_PEEK( rq, 3 ) << 8 |
RING_QUEUE_PEEK( rq, 0 ) << 16 |
RING_QUEUE_PEEK( rq, 1 ) << 24 ;
RING_QUEUE_DEQUEUE_BYTES( rq, 2 );
br->rq = rq;
}
#define rqBR_peekBits(br,n) ( br->cur_data >> (32-n) )
#define rqBR_flushBits(br,n) do { \
br->cur_data <<= n; \
if ( (br->cur_bit -= n) <= 0 ) { \
br->cur_data |= \
RING_QUEUE_PEEK( br->rq, 2 ) << -br->cur_bit | \
RING_QUEUE_PEEK( br->rq, 3 ) << (8 - br->cur_bit); \
RING_QUEUE_DEQUEUE_BYTES( br->rq, 2 ); \
br->cur_bit += 16; \
} \
} while (0)
/* ============================================================================
* Real JPEG Lite stuff
* ============================================================================
*
* Precomputed tables
* Theses are computed at init time to make real-time operations faster.
* It takes some space ( about 9k ). But believe me it worth it !
*/
/* Variable Lenght Coding related tables, used for AC coefficient decoding
* TODO Check that 7 bits is enough ! */
static signed char vlcTbl_len[1<<10]; /* Meaningful bit count */
static signed char vlcTbl_run[1<<10]; /* Run */
static signed char vlcTbl_amp[1<<10]; /* Amplitude (without the sign) */
/* YUV->RGB conversion table */
static int yuvTbl_y[256];
static int yuvTbl_u1[256];
static int yuvTbl_u2[256];
static int yuvTbl_v1[256];
static int yuvTbl_v2[256];
/* Clamping table */
#define SAFE_CLAMP
#ifdef SAFE_CLAMP
static inline unsigned char clamp(int x) {
if (x > 255)
return 255;
if (x < 0)
return 0;
return x;
}
#define clamp_adjust(x) clamp(x+128)
#else
#define clamp(x) clampTbl[(x)+512]
#define clamp_adjust(x) clampTbl[(x)+640]
static char clampTbl[1280];
#endif
/* Code to initialize those tables */
static void vlcTbl_init(void)
{
/* Bases tables used to compute the bigger one
* To understands theses, look at the VLC doc in the
* US patent document. */
static const int vlc_num = 28;
static const int vlc_len[] =
{ 2, 2, 3, 3, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7,
8 ,8 ,8 ,9, 9, 9, 10, 10, 10, 10, 10, 10 };
static const int vlc_run[] =
{ 0, 0, 0, 1, 0, 2, 3, 1, 0, 4, 0, 5, 1, 0, -1, -2,
2, 6, 0, 3, 1, 0, 1, 0, 7, 2, 0, 8 };
static const int vlc_amp[] =
{ 0, 1, 2, 1, 3, 1, 1, 2, 4, 1 ,5 ,1 ,3 ,6, -1, -2,
2, 1, 7, 2, 4, 8, 5, 9, 1 ,3, 10, 1 };
static const int vlc_cod[] =
{ 0x000, 0x002, 0x003, 0x006, 0x00E, 0x008, 0x00B, 0x012,
0x014, 0x03D, 0x03E, 0x078, 0x079, 0x07E, 0x026, 0x027,
0x054, 0x057, 0x0FF, 0x0AA, 0x0AC, 0x1FC, 0x156, 0x157,
0x15A, 0x15B, 0x3FA, 0x3FB };
/* Vars */
int i,j;
/* Main filling loop */
for ( i=0 ; i<(1<<10) ; i++ ) {
/* Find the matching one */
for ( j=0 ; j<vlc_num ; j++ ) {
if ( (i >> (10-vlc_len[j])) == vlc_cod[j] ) {
if ( vlc_run[j] >= 0 )
if ( vlc_amp[j] != 0 )
vlcTbl_len[i] = vlc_len[j] + 1;
else
vlcTbl_len[i] = vlc_len[j]; /* EOB */
else
vlcTbl_len[i] = 16;
vlcTbl_run[i] = vlc_run[j];
vlcTbl_amp[i] = vlc_amp[j];
break;
}
}
}
}
static void yuvTbl_init(void)
{
/* These tables are just pre-multiplied and pre-offseted
* YUV by the book
* R = 1.164 * (Y-16) + 1.596 * (U-128)
* G = 1.164 * (Y-16) - 0.813 * (U-128) - 0.391 * (V-128)
* B = 1.164 * (Y-16) + 2.018 * (V-128) */
int i;
/* We use fixed point << 16 */
for ( i=0 ; i < 256 ; i++ ) {
yuvTbl_y[i] = 76284 * (i- 16);
yuvTbl_u1[i] = 104595 * (i-128);
yuvTbl_u2[i] = 53281 * (i-128);
yuvTbl_v1[i] = 25625 * (i-128);
yuvTbl_v2[i] = 132252 * (i-128);
}
}
#ifndef SAFE_CLAMP
static void clampTbl_init(void)
{
/* Instead of doing if(...) to test for overrange, we use
* a clamping table */
int i;
for (i=0 ; i < 512 ; i++)
clampTbl[i] = 0;
for (i=512 ; i < 768 ; i++ )
clampTbl[i] = i - 512;
for (i=768 ; i < 1280 ; i++ )
clampTbl[i] = 255;
}
#endif
/*
* Internal helpers
*/
static inline int readAC( struct rqBitReader *br, int *run, int *amp )
{
/* Vars */
unsigned int cod;
/* Get 16 bits */
cod = rqBR_peekBits(br,16);
/* Lookup in the table */
*run = vlcTbl_run[cod>>6];
*amp = vlcTbl_amp[cod>>6];
rqBR_flushBits(br,vlcTbl_len[cod>>6]);
if (*amp > 0) {
/* Normal stuff, just correct the sign */
if (cod & (0x10000 >> vlcTbl_len[cod>>6]))
*amp = - *amp;
} else {
/* Handle special cases */
if (!*amp)
return 0;
if (*amp == -1) {
/* 0100110srrraaaaa */
*run = ( cod >> 5 ) & 0x07;
*amp = ( cod & 0x100) ?
-(cod&0x1F) : (cod&0x1F);
} else {
/* 0100111srrrraaaa */
*run = ( cod >> 4 ) & 0x0F;
*amp = ( cod & 0x100) ?
-(cod&0x0F) : (cod&0x0F);
}
}
return 1;
}
#define iDCT_column(b0,b1,b2,b3) do { \
int t0,t1,t2,t3; \
\
t0 = ( b1 + b3 ) << 5; \
t2 = t0 - (b3 << 4); \
t3 = (b1 * 47) - t0; \
t0 = b0 + b2; \
t1 = b0 - b2; \
\
b0 = ( t0 + t2 ); \
b1 = ( t1 + t3 ); \
b3 = ( t0 - t2 ); \
b2 = ( t1 - t3 ); \
} while (0)
#define iDCT_line(b0,b1,b2,b3) do { \
int t0,t1,t2,t3,bm0,bm2; \
\
bm0 = b0 << 7; \
bm2 = b2 << 7; \
\
t0 = bm0 + bm2; \
t1 = bm0 - bm2; \
t2 = b1 * 183 + b3 * 86; \
t3 = b1 * 86 - b3 * 183; \
\
b0 = ( t0 + t2 ) >> 22; \
b1 = ( t1 + t3 ) >> 22; \
b3 = ( t0 - t2 ) >> 22; \
b2 = ( t1 - t3 ) >> 22; \
} while (0)
/* Decode a block
* Basic ops : get the DC - get the ACs - deZigZag - deWeighting -
* deQuantization - iDCT
* Here they are a little mixed-up to speed all this up.
*/
static inline int decodeBlock( struct rqBitReader *br, int *block, int *dc )
{
/* Tables used for block decoding */
/* deZigZag table
*
* ZigZag: each of the coefficient of the DCT transformed 4x4
* matrix is taken in a certain order to make a linear
* array with the high frequency AC at the end
*
* / 0 1 5 6 \ .
* | 2 4 7 12 | This is the order taken. We must deZigZag
* | 3 8 11 13 | to reconstitute the original matrix
* \ 9 10 14 15 /
*/
static const int iZigZagTbl[16] =
{ 0, 1, 4, 8, 5, 2, 3, 6, 9,12, 13, 10, 7, 11, 14, 15 };
/* deQuantization, deWeighting & iDCT premultiply */
/*
* Weighting : Each DCT coefficient is weighted by a certain factor. We
* must compensate for this to rebuilt the original DCT matrix.
*
* Quantization: According to the read Q factor, DCT coefficient are
* quantized. We need to compensate for this.
*
* iDCT premultiply: Since for the first iDCT pass ( column ), we'll need
* to do some multiplication, the ones that we can
* integrate here, we do.
*
* Rem: - The factors are here presented in the ZigZaged order,
* because we will need those BEFORE the deZigZag
* - For more informations, consult jpgl_tbl.c, it's the little
* prog that computes this table
*/
static const int iQWTbl[4][16] = {
{ 32768, 17808, 794, 18618, 850, 18618, 43115, 1828,
40960, 1924, 2089, 45511, 2089, 49648, 2216, 2521 },
{ 32768, 35617, 1589, 37236, 1700, 37236, 86231, 3656,
81920, 3849, 4179, 91022, 4179, 99296, 4432, 5043 },
{ 32768, 71234, 3179, 74472, 3401, 74472, 172463, 7313,
163840, 7698, 8358, 182044, 8358, 198593, 8865, 10087 },
{ 32768, 142469, 6359, 148945, 6803, 148945, 344926, 14627,
327680, 15397, 16716, 364088, 16716, 397187, 17730, 20175 }
};
/* Vars */
int hdr;
int *eff_iQWTbl;
int cc, run, amp;
/* Read & Decode the block header ( Q, T, DC ) */
hdr = rqBR_peekBits(br,11);
if (hdr & 0x100) {
/* Differential mode */
if (hdr & 0x80)
*dc += ( hdr >> 3 ) | ~0xF;
else
*dc += ( hdr >> 3 ) & 0xF;
/* Flush the header bits */
rqBR_flushBits(br,8);
} else {
/* Direct mode */
if ( hdr & 0x80 )
*dc = hdr | ~0x7F;
else
*dc = hdr & 0x7F;
/* Flush the header bits */
rqBR_flushBits(br,11);
}
/* Clear the block & store DC ( with pre-multiply ) */
block[0] = *dc << 15;
block[1] = 0x00;
block[2] = 0x00;
block[3] = 0x00;
block[4] = 0x00;
block[5] = 0x00;
block[6] = 0x00;
block[7] = 0x00;
block[8] = 0x00;
block[9] = 0x00;
block[10] = 0x00;
block[11] = 0x00;
block[12] = 0x00;
block[13] = 0x00;
block[14] = 0x00;
block[15] = 0x00;
/* Read the AC coefficients
* at the same time, deZigZag, deQuantization, deWeighting & iDCT premultiply
*/
eff_iQWTbl = (int*) iQWTbl[hdr>>9];
cc = 0;
while ( readAC(br,&run,&amp) ) {
cc += run + 1;
if ( cc > 15 )
return -1;
block[iZigZagTbl[cc]] = amp * eff_iQWTbl[cc];
}
/* Do the column iDCT ( what's left to do ) */
iDCT_column(block[0], block[4], block[8], block[12]);
iDCT_column(block[1], block[5], block[9], block[13]);
iDCT_column(block[2], block[6], block[10], block[14]);
iDCT_column(block[3], block[7], block[11], block[15]);
/* Do the line iDCT ( complete one here ) */
iDCT_line(block[0], block[1], block[2], block[3]);
iDCT_line(block[4], block[5], block[6], block[7]);
iDCT_line(block[8], block[9], block[10], block[11]);
iDCT_line(block[12], block[13], block[14], block[15]);
return !(hdr & 0x700);
}
int v4lconvert_decode_jpgl(const unsigned char *inp, int src_size,
unsigned int dest_pix_fmt, unsigned char *fb,
int img_width, int img_height)
{
/* Vars */
struct RingQueue rq;
struct rqBitReader br;
int row, col; /* Row & Column in the image */
int x,y;
int block_idx;
unsigned char *Yline_baseptr, *Uline_baseptr, *Vline_baseptr;
unsigned char *Yline, *Uline, *Vline;
int Yline_baseofs, UVline_baseofs;
int dc_y, dc_u, dc_v; /* DC Coefficients */
int block_y[16*4]; /* Y blocks */
int block_u[16]; /* U block */
int block_v[16]; /* V block */
unsigned char *mainbuffer;
int yc,uc,vc;
/* init the decoder */
if (yuvTbl_y[0] == 0) {
vlcTbl_init();
yuvTbl_init();
#ifndef SAFE_CLAMP
clampTbl_init();
#endif
}
img_height /= 4;
/* Prepare a bit-by-bit reader */
rq.queue = inp;
rq.length = src_size;
rq.ri = 0;
rqBR_init(&br, &rq);
/* Allocate a big buffer & setup pointers */
switch (dest_pix_fmt) {
default:
/* case V4L2_PIX_FMT_RGB24: */
/* case V4L2_PIX_FMT_BGR24: */
mainbuffer = malloc(4 * (img_width + (img_width >> 1) + 2));
Yline_baseptr = mainbuffer;
Uline_baseptr = mainbuffer + (4 * img_width);
Vline_baseptr = Uline_baseptr + (img_width + 4);
break;
case V4L2_PIX_FMT_YUV420:
mainbuffer = NULL;
Yline_baseptr = fb;
Uline_baseptr = fb + img_width * img_height * 16;
Vline_baseptr = Uline_baseptr + img_width * img_height * 4;
break;
case V4L2_PIX_FMT_YVU420:
mainbuffer = NULL;
Yline_baseptr = fb;
Vline_baseptr = fb + img_width * img_height * 16;
Uline_baseptr = Vline_baseptr + img_width * img_height * 4;
break;
}
Yline_baseofs = img_width - 4;
UVline_baseofs = (img_width >> 2) - 3;
/* Process 4 lines at a time ( one block height ) */
for ( row=0 ; row<img_height ; row++ ) {
/* Line start reset DC */
dc_y = dc_u = dc_v = 0;
/* Process 16 columns at a time ( 4 block width ) */
for ( col=0 ; col<img_width ; col+=16 ) {
/* Decode blocks
* Block order : Y Y Y Y V U ( Why V before U ?
* that just depends what you call U&V ... I took the
* 'by-the-book' names and that make V and then U,
* ... just ask the DivIO folks ;) )
*/
if ( decodeBlock(&br, block_y, &dc_y) && (!col) )
/* return; * Bad block, so bad frame ... */
;
decodeBlock(&br, block_y + 16, &dc_y);
decodeBlock(&br, block_y + 32, &dc_y);
decodeBlock(&br, block_y + 48, &dc_y);
decodeBlock(&br, block_v, &dc_v);
decodeBlock(&br, block_u, &dc_u);
/* Copy data to temporary buffers ( to make a complete line ) */
block_idx = 0;
Yline = Yline_baseptr + col;
Uline = Uline_baseptr + (col >> 2);
Vline = Vline_baseptr + (col >> 2);
for ( y=0 ; y<4 ; y++) {
/* Scan line */
for ( x=0 ; x<4 ; x++ ) {
/* Y block */
Yline[ 0] = clamp_adjust(block_y[block_idx ]);
Yline[ 4] = clamp_adjust(block_y[block_idx+16]);
Yline[ 8] = clamp_adjust(block_y[block_idx+32]);
Yline[12] = clamp_adjust(block_y[block_idx+48]);
/* U block */
*Uline = clamp_adjust(block_u[block_idx]);
/* V block */
*Vline = clamp_adjust(block_v[block_idx]);
/* Ajust pointers & index */
block_idx++;
Yline++;
Uline++;
Vline++;
}
/* Adjust pointers */
Yline += Yline_baseofs;
Uline += UVline_baseofs;
Vline += UVline_baseofs;
}
}
/* Handle interpolation special case ( at the end of the lines ) */
Uline = Uline_baseptr + (UVline_baseofs+2);
Vline = Vline_baseptr + (UVline_baseofs+2);
for ( y=0 ; y<4 ; y++ ) {
/* Copy the last pixel */
Uline[1] = Uline[0];
Vline[1] = Vline[0];
/* Adjust ptr */
Uline += UVline_baseofs+4;
Vline += UVline_baseofs+4;
}
/* We have 4 complete lines, so tempbuffer<YUV> -> framebuffer<RGB>
* Go line by line */
switch (dest_pix_fmt) {
case V4L2_PIX_FMT_RGB24:
Yline = Yline_baseptr;
Uline = Uline_baseptr;
Vline = Vline_baseptr;
for ( y=0 ; y<4 ; y++ ) {
/* Process 4 pixel at a time to handle interpolation
* for U & V values */
for ( x=0 ; x<img_width ; x+=4 ) {
/* First pixel */
yc = yuvTbl_y[*(Yline++)];
uc = Uline[0];
vc = Vline[0];
*(fb++) = clamp(( yc + yuvTbl_u1[uc] ) >> 16);
*(fb++) = clamp(( yc - yuvTbl_u2[uc] - yuvTbl_v1[vc] ) >> 16);
*(fb++) = clamp(( yc + yuvTbl_v2[vc] ) >> 16);
/* Second pixel */
yc = yuvTbl_y[*(Yline++)];
uc = ( 3*Uline[0] + Uline[1] ) >> 2;
vc = ( 3*Vline[0] + Vline[1] ) >> 2;
*(fb++) = clamp(( yc + yuvTbl_u1[uc] ) >> 16);
*(fb++) = clamp(( yc - yuvTbl_u2[uc] - yuvTbl_v1[vc] ) >> 16);
*(fb++) = clamp(( yc + yuvTbl_v2[vc] ) >> 16);
/* Third pixel */
yc = yuvTbl_y[*(Yline++)];
uc = ( Uline[0] + Uline[1] ) >> 1;
vc = ( Vline[0] + Vline[1] ) >> 1;
*(fb++) = clamp(( yc + yuvTbl_u1[uc] ) >> 16);
*(fb++) = clamp(( yc - yuvTbl_u2[uc] - yuvTbl_v1[vc] ) >> 16);
*(fb++) = clamp(( yc + yuvTbl_v2[vc] ) >> 16);
/* Fourth pixel */
yc = yuvTbl_y[*(Yline++)];
uc = ( Uline[0] + 3*Uline[1] ) >> 2;
vc = ( Vline[0] + 3*Vline[1] ) >> 2;
*(fb++) = clamp(( yc + yuvTbl_u1[uc] ) >> 16);
*(fb++) = clamp(( yc - yuvTbl_u2[uc] - yuvTbl_v1[vc] ) >> 16);
*(fb++) = clamp(( yc + yuvTbl_v2[vc] ) >> 16);
/* Adjust pointers */
Uline++;
Vline++;
}
/* Adjust pointers */
Uline++;
Vline++;
}
break;
case V4L2_PIX_FMT_BGR24:
Yline = Yline_baseptr;
Uline = Uline_baseptr;
Vline = Vline_baseptr;
for ( y=0 ; y<4 ; y++ ) {
/* Process 4 pixel at a time to handle interpolation
* for U & V values */
for ( x=0 ; x<img_width ; x+=4 ) {
/* First pixel */
yc = yuvTbl_y[*(Yline++)];
uc = Uline[0];
vc = Vline[0];
*(fb++) = clamp(( yc + yuvTbl_v2[vc] ) >> 16);
*(fb++) = clamp(( yc - yuvTbl_u2[uc] - yuvTbl_v1[vc] ) >> 16);
*(fb++) = clamp(( yc + yuvTbl_u1[uc] ) >> 16);
/* Second pixel */
yc = yuvTbl_y[*(Yline++)];
uc = ( 3*Uline[0] + Uline[1] ) >> 2;
vc = ( 3*Vline[0] + Vline[1] ) >> 2;
*(fb++) = clamp(( yc + yuvTbl_v2[vc] ) >> 16);
*(fb++) = clamp(( yc - yuvTbl_u2[uc] - yuvTbl_v1[vc] ) >> 16);
*(fb++) = clamp(( yc + yuvTbl_u1[uc] ) >> 16);
/* Third pixel */
yc = yuvTbl_y[*(Yline++)];
uc = ( Uline[0] + Uline[1] ) >> 1;
vc = ( Vline[0] + Vline[1] ) >> 1;
*(fb++) = clamp(( yc + yuvTbl_v2[vc] ) >> 16);
*(fb++) = clamp(( yc - yuvTbl_u2[uc] - yuvTbl_v1[vc] ) >> 16);
*(fb++) = clamp(( yc + yuvTbl_u1[uc] ) >> 16);
/* Fourth pixel */
yc = yuvTbl_y[*(Yline++)];
uc = ( Uline[0] + 3*Uline[1] ) >> 2;
vc = ( Vline[0] + 3*Vline[1] ) >> 2;
*(fb++) = clamp(( yc + yuvTbl_v2[vc] ) >> 16);
*(fb++) = clamp(( yc - yuvTbl_u2[uc] - yuvTbl_v1[vc] ) >> 16);
*(fb++) = clamp(( yc + yuvTbl_u1[uc] ) >> 16);
/* Adjust pointers */
Uline++;
Vline++;
}
/* Adjust pointers */
Uline++;
Vline++;
}
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
Yline_baseptr += img_width * 4;
Uline_baseptr += img_width;
Vline_baseptr += img_width;
break;
}
}
/* Free our buffer */
if (mainbuffer != NULL)
free(mainbuffer);
return 0;
}
/*
Return-Path: tnt@246tNt.com
Received: from zimbra16-e3.priv.proxad.net (LHLO
zimbra16-e3.priv.proxad.net) (172.20.243.166) by
zimbra16-e3.priv.proxad.net with LMTP; Mon, 14 Feb 2011 21:10:38 +0100
(CET)
Received: from mailrelay011.isp.belgacom.be (mx26-g26.priv.proxad.net [172.20.243.96])
by zimbra16-e3.priv.proxad.net (Postfix) with ESMTP id 1A661157C5B
for <moinejf@free.fr>; Mon, 14 Feb 2011 21:10:38 +0100 (CET)
Received: from mailrelay011.isp.belgacom.be ([195.238.6.178])
by mx1-g20.free.fr (MXproxy) for moinejf@free.fr ;
Mon, 14 Feb 2011 21:10:36 +0100 (CET)
X-ProXaD-SC: state=HAM score=0
X-Belgacom-Dynamic: yes
X-IronPort-Anti-Spam-Filtered: true
X-IronPort-Anti-Spam-Result: ApIBAKsaWU1XQ5W2/2dsb2JhbAAMhBHOEpA5gSeBaYFYdgSLfw
Received: from 182.149-67-87.adsl-dyn.isp.belgacom.be (HELO [10.0.0.129]) ([87.67.149.182])
by relay.skynet.be with ESMTP; 14 Feb 2011 21:10:36 +0100
Message-ID: <4D598C7C.7080307@246tNt.com>
Date: Mon, 14 Feb 2011 21:11:40 +0100
From: Sylvain Munaut <tnt@246tNt.com>
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101219 Lightning/1.0b3pre Thunderbird/3.1.7
MIME-Version: 1.0
To: Jean-Francois Moine <moinejf@free.fr>
CC: Kjell Claesson <keyson@users.sourceforge.net>
Subject: Re: nw80x as a gspca subdriv
References: <20110209204208.4b19df88@tele> <4D53B3BF.9050908@246tNt.com> <20110214205107.18c29303@tele>
In-Reply-To: <20110214205107.18c29303@tele>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
[snip]
> May I have your permission to relicense your JPEG Lite decompression
> code under the LGPL (version 2 or later)?
Yes, sure.
"""
I hereby allow the nw80x driver code, including the jpeg lite decoding
routines, to be used and distributed under the LGPL v2 or later.
"""
[snip]
Cheers,
Sylvain
*/

View File

@@ -0,0 +1,283 @@
/*
# (C) 2008 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#ifndef __LIBV4LCONVERT_PRIV_H
#define __LIBV4LCONVERT_PRIV_H
#ifdef ANDROID
#include <android-config.h>
#else
#include <config.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#ifdef HAVE_JPEG
#include <jpeglib.h>
#endif
#include <setjmp.h>
#include "libv4l-plugin.h"
#include "libv4lconvert.h"
#include "control/libv4lcontrol.h"
#include "processing/libv4lprocessing.h"
#include "tinyjpeg.h"
#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
#define V4LCONVERT_ERROR_MSG_SIZE 256
#define V4LCONVERT_MAX_FRAMESIZES 256
#define V4LCONVERT_ERR(...) \
snprintf(data->error_msg, V4LCONVERT_ERROR_MSG_SIZE, \
"v4l-convert: error " __VA_ARGS__)
/* Card flags */
#define V4LCONVERT_IS_UVC 0x01
#define V4LCONVERT_USE_TINYJPEG 0x02
struct v4lconvert_data {
int fd;
int flags; /* bitfield */
int control_flags; /* bitfield */
unsigned int no_formats;
int64_t supported_src_formats; /* bitfield */
char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
struct jdec_private *tinyjpeg;
#ifdef HAVE_JPEG
struct jpeg_error_mgr jerr;
int jerr_errno;
jmp_buf jerr_jmp_state;
struct jpeg_decompress_struct cinfo;
int cinfo_initialized;
#endif // HAVE_JPEG
struct v4l2_frmsizeenum framesizes[V4LCONVERT_MAX_FRAMESIZES];
unsigned int no_framesizes;
int bandwidth;
int fps;
int convert1_buf_size;
int convert2_buf_size;
int rotate90_buf_size;
int flip_buf_size;
int convert_pixfmt_buf_size;
unsigned char *convert1_buf;
unsigned char *convert2_buf;
unsigned char *rotate90_buf;
unsigned char *flip_buf;
unsigned char *convert_pixfmt_buf;
struct v4lcontrol_data *control;
struct v4lprocessing_data *processing;
void *dev_ops_priv;
const struct libv4l_dev_ops *dev_ops;
/* Data for external decompression helpers code */
pid_t decompress_pid;
int decompress_in_pipe[2]; /* Data from helper to us */
int decompress_out_pipe[2]; /* Data from us to helper */
/* For mr97310a decoder */
int frames_dropped;
/* For cpia1 decoder */
unsigned char *previous_frame;
};
struct v4lconvert_pixfmt {
unsigned int fmt; /* v4l2 fourcc */
int bpp; /* bits per pixel, 0 for compressed formats */
int rgb_rank; /* rank for converting to rgb32 / bgr32 */
int yuv_rank; /* rank for converting to yuv420 / yvu420 */
int needs_conversion;
};
unsigned char *v4lconvert_alloc_buffer(int needed,
unsigned char **buf, int *buf_size);
int v4lconvert_oom_error(struct v4lconvert_data *data);
void v4lconvert_rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, int bgr, int yvu, int bpp);
void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu);
void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu);
void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dst,
int width, int height, int stride);
void v4lconvert_yuyv_to_bgr24(const unsigned char *src, unsigned char *dst,
int width, int height, int stride);
void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int stride, int yvu);
void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dst,
int width, int height, int stride);
void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dst,
int width, int height, int stride);
void v4lconvert_uyvy_to_rgb24(const unsigned char *src, unsigned char *dst,
int width, int height, int stride);
void v4lconvert_uyvy_to_bgr24(const unsigned char *src, unsigned char *dst,
int width, int height, int stride);
void v4lconvert_uyvy_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int stride, int yvu);
void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst,
int width, int height);
void v4lconvert_swap_uv(const unsigned char *src, unsigned char *dst,
const struct v4l2_format *src_fmt);
void v4lconvert_grey_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height);
void v4lconvert_grey_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt);
void v4lconvert_y16_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height, int little_endian);
void v4lconvert_y16_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, int little_endian);
void v4lconvert_rgb32_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height, int bgr);
int v4lconvert_y10b_to_rgb24(struct v4lconvert_data *data,
const unsigned char *src, unsigned char *dest, int width, int height);
int v4lconvert_y10b_to_yuv420(struct v4lconvert_data *data,
const unsigned char *src, unsigned char *dest, int width, int height);
void v4lconvert_rgb565_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height);
void v4lconvert_rgb565_to_bgr24(const unsigned char *src, unsigned char *dest,
int width, int height);
void v4lconvert_rgb565_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, int yvu);
void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu);
void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu);
void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu);
void v4lconvert_cit_yyvyuy_to_yuv420(const unsigned char *src,
unsigned char *ydest,
int width, int height, int yvu);
void v4lconvert_konica_yuv420_to_yuv420(const unsigned char *src,
unsigned char *ydest,
int width, int height, int yvu);
void v4lconvert_m420_to_yuv420(const unsigned char *src,
unsigned char *ydest,
int width, int height, int yvu);
int v4lconvert_cpia1_to_yuv420(struct v4lconvert_data *data,
const unsigned char *src, int src_size,
unsigned char *dst, int width, int height, int yvu);
void v4lconvert_sn9c20x_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu);
int v4lconvert_se401_to_rgb24(struct v4lconvert_data *data,
const unsigned char *src, int src_size,
unsigned char *dest, int width, int height);
int v4lconvert_decode_jpeg_tinyjpeg(struct v4lconvert_data *data,
unsigned char *src, int src_size, unsigned char *dest,
struct v4l2_format *fmt, unsigned int dest_pix_fmt, int flags);
int v4lconvert_decode_jpeg_libjpeg(struct v4lconvert_data *data,
unsigned char *src, int src_size, unsigned char *dest,
struct v4l2_format *fmt, unsigned int dest_pix_fmt);
int v4lconvert_decode_jpgl(const unsigned char *src, int src_size,
unsigned int dest_pix_fmt, unsigned char *dest, int width, int height);
void v4lconvert_decode_spca561(const unsigned char *src, unsigned char *dst,
int width, int height);
void v4lconvert_decode_sn9c10x(const unsigned char *src, unsigned char *dst,
int width, int height);
int v4lconvert_decode_pac207(struct v4lconvert_data *data,
const unsigned char *inp, int src_size, unsigned char *outp,
int width, int height);
int v4lconvert_decode_mr97310a(struct v4lconvert_data *data,
const unsigned char *src, int src_size, unsigned char *dst,
int width, int height);
int v4lconvert_decode_jl2005bcd(struct v4lconvert_data *data,
const unsigned char *src, int src_size,
unsigned char *dest, int width, int height);
void v4lconvert_decode_sn9c2028(const unsigned char *src, unsigned char *dst,
int width, int height);
void v4lconvert_decode_sq905c(const unsigned char *src, unsigned char *dst,
int width, int height);
void v4lconvert_decode_stv0680(const unsigned char *src, unsigned char *dst,
int width, int height);
void v4lconvert_bayer_to_rgb24(const unsigned char *bayer,
unsigned char *rgb, int width, int height, const unsigned int stride, unsigned int pixfmt);
void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
unsigned char *rgb, int width, int height, const unsigned int stride, unsigned int pixfmt);
void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv,
int width, int height, const unsigned int stride, unsigned int src_pixfmt, int yvu);
void v4lconvert_hm12_to_rgb24(const unsigned char *src,
unsigned char *dst, int width, int height);
void v4lconvert_hm12_to_bgr24(const unsigned char *src,
unsigned char *dst, int width, int height);
void v4lconvert_hm12_to_yuv420(const unsigned char *src,
unsigned char *dst, int width, int height, int yvu);
void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt);
void v4lconvert_flip(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt, int hflip, int vflip);
void v4lconvert_crop(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt);
int v4lconvert_helper_decompress(struct v4lconvert_data *data,
const char *helper, const unsigned char *src, int src_size,
unsigned char *dest, int dest_size, int width, int height, int command);
void v4lconvert_helper_cleanup(struct v4lconvert_data *data);
#endif

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
v4lconvert_get_default_dev_ops
v4lconvert_create
v4lconvert_create_with_dev_ops
v4lconvert_destroy
v4lconvert_supported_dst_fmt_only
v4lconvert_try_format
v4lconvert_enum_fmt
v4lconvert_needs_conversion
v4lconvert_convert
v4lconvert_get_error_message
v4lconvert_enum_framesizes
v4lconvert_enum_frameintervals
v4lconvert_vidioc_queryctrl
v4lconvert_vidioc_g_ctrl
v4lconvert_vidioc_s_ctrl
v4lconvert_vidioc_g_ext_ctrls
v4lconvert_vidioc_try_ext_ctrls
v4lconvert_vidioc_s_ext_ctrls
v4lconvert_supported_dst_format
v4lconvert_get_fps
v4lconvert_set_fps
v4lconvert_fixup_fmt

View File

@@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
includedir=@includedir@
libdir=@libdir@
Name: libv4lconvert
Description: v4l format conversion library
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lv4lconvert
Libs.private: -lrt -lm @JPEG_LIBS@
Cflags: -I${includedir}

View File

@@ -0,0 +1,129 @@
/*-
* Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* The following file allows for having the complete V4L stack and
* hardware drivers in userland.
*/
#ifndef _LIBV4LSYSCALL_PRIV_H_
#define _LIBV4LSYSCALL_PRIV_H_
/* Some of these headers are not needed by us, but by linux/videodev2.h,
which is broken on some systems and doesn't include them itself :( */
#ifdef linux
#include <sys/time.h>
#include <sys/syscall.h>
#include <linux/types.h>
#include <linux/ioctl.h>
/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */
#ifdef __NR_mmap2
#if !defined(SYS_mmap2)
#define SYS_mmap2 __NR_mmap2
#endif
#define MMAP2_PAGE_SHIFT 12
#else
#define SYS_mmap2 SYS_mmap
#define MMAP2_PAGE_SHIFT 0
#endif
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/time.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#define _IOC_NR(cmd) ((cmd) & 0xFF)
#define _IOC_TYPE(cmd) IOCGROUP(cmd)
#define _IOC_SIZE(cmd) IOCPARM_LEN(cmd)
#define MAP_ANONYMOUS MAP_ANON
#define MMAP2_PAGE_SHIFT 0
#endif
#undef SYS_OPEN
#undef SYS_CLOSE
#undef SYS_IOCTL
#undef SYS_READ
#undef SYS_WRITE
#undef SYS_MMAP
#undef SYS_MUNMAP
#ifndef CONFIG_SYS_WRAPPER
#ifdef SYS_openat
#define SYS_OPEN(file, oflag, mode) \
syscall(SYS_openat, AT_FDCWD, (const char *)(file), (int)(oflag), (mode_t)(mode))
#else
#define SYS_OPEN(file, oflag, mode) \
syscall(SYS_open, (const char *)(file), (int)(oflag), (mode_t)(mode))
#endif
#define SYS_CLOSE(fd) \
syscall(SYS_close, (int)(fd))
#define SYS_IOCTL(fd, cmd, arg) \
syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
#define SYS_READ(fd, buf, len) \
syscall(SYS_read, (int)(fd), (void *)(buf), (size_t)(len));
#define SYS_WRITE(fd, buf, len) \
syscall(SYS_write, (int)(fd), (const void *)(buf), (size_t)(len));
#if defined(__FreeBSD__)
#define SYS_MMAP(addr, len, prot, flags, fd, off) \
__syscall(SYS_mmap, (void *)(addr), (size_t)(len), \
(int)(prot), (int)(flags), (int)(fd), (off_t)(off))
#elif defined(__FreeBSD_kernel__)
#define SYS_MMAP(addr, len, prot, flags, fd, off) \
syscall(SYS_mmap, (void *)(addr), (size_t)(len), \
(int)(prot), (int)(flags), (int)(fd), (off_t)(off))
#else
#define SYS_MMAP(addr, len, prot, flags, fd, off) \
syscall(SYS_mmap2, (void *)(addr), (size_t)(len), \
(int)(prot), (int)(flags), (int)(fd), (off_t)((off) >> MMAP2_PAGE_SHIFT))
#endif
#define SYS_MUNMAP(addr, len) \
syscall(SYS_munmap, (void *)(addr), (size_t)(len))
#else
int v4lx_open_wrapper(const char *, int, int);
int v4lx_close_wrapper(int);
int v4lx_ioctl_wrapper(int, unsigned long, void *);
int v4lx_read_wrapper(int, void *, size_t);
int v4lx_write_wrapper(int, const void *, size_t);
void *v4lx_mmap_wrapper(void *, size_t, int, int, int, off_t);
int v4lx_munmap_wrapper(void *, size_t);
#define SYS_OPEN(...) v4lx_open_wrapper(__VA_ARGS__)
#define SYS_CLOSE(...) v4lx_close_wrapper(__VA_ARGS__)
#define SYS_IOCTL(...) v4lx_ioctl_wrapper(__VA_ARGS__)
#define SYS_READ(...) v4lx_read_wrapper(__VA_ARGS__)
#define SYS_WRITE(...) v4lx_write_wrapper(__VA_ARGS__)
#define SYS_MMAP(...) v4lx_mmap_wrapper(__VA_ARGS__)
#define SYS_MUNMAP(...) v4lx_munmap_wrapper(__VA_ARGS__)
#endif
#endif /* _LIBV4LSYSCALL_PRIV_H_ */

208
libv4lconvert/mr97310a.c Normal file
View File

@@ -0,0 +1,208 @@
/*
* MR97310A decoder
*
* Copyright (C) 2004-2009 Theodore Kilgore <kilgota@auburn.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License, version 2, as published by the Free Software Foundation.
*
* This library 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 library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
* Boston, MA 02111-1307, USA.
*/
#include <unistd.h>
#include "libv4lconvert-priv.h"
#include "libv4lsyscall-priv.h"
#define CLIP(x) ((x) < 0 ? 0 : ((x) > 0xff) ? 0xff : (x))
#define MIN_CLOCKDIV_CID V4L2_CID_PRIVATE_BASE
/* FIXME not threadsafe */
static int decoder_initialized;
static struct {
unsigned char is_abs;
unsigned char len;
signed char val;
} table[256];
static void init_mr97310a_decoder(void)
{
int i;
int is_abs, val, len;
for (i = 0; i < 256; ++i) {
is_abs = 0;
val = 0;
len = 0;
if ((i & 0x80) == 0) {
/* code 0 */
val = 0;
len = 1;
} else if ((i & 0xe0) == 0xc0) {
/* code 110 */
val = -3;
len = 3;
} else if ((i & 0xe0) == 0xa0) {
/* code 101 */
val = 3;
len = 3;
} else if ((i & 0xf0) == 0x80) {
/* code 1000 */
val = 8;
len = 4;
} else if ((i & 0xf0) == 0x90) {
/* code 1001 */
val = -8;
len = 4;
} else if ((i & 0xf0) == 0xf0) {
/* code 1111 */
val = -20;
len = 4;
} else if ((i & 0xf8) == 0xe0) {
/* code 11100 */
val = 20;
len = 5;
} else if ((i & 0xf8) == 0xe8) {
/* code 11101xxxxx */
is_abs = 1;
val = 0; /* value is calculated later */
len = 5;
}
table[i].is_abs = is_abs;
table[i].val = val;
table[i].len = len;
}
decoder_initialized = 1;
}
static inline unsigned char get_byte(const unsigned char *inp,
unsigned int bitpos)
{
const unsigned char *addr;
addr = inp + (bitpos >> 3);
return (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
}
int v4lconvert_decode_mr97310a(struct v4lconvert_data *data,
const unsigned char *inp, int src_size,
unsigned char *outp, int width, int height)
{
int row, col;
int val;
int bitpos;
unsigned char code;
unsigned char lp, tp, tlp, trp;
struct v4l2_control min_clockdiv = { .id = MIN_CLOCKDIV_CID };
if (!decoder_initialized)
init_mr97310a_decoder();
/* remove the header */
inp += 12;
bitpos = 0;
/* main decoding loop */
for (row = 0; row < height; ++row) {
col = 0;
/* first two pixels in first two rows are stored as raw 8-bit */
if (row < 2) {
code = get_byte(inp, bitpos);
bitpos += 8;
*outp++ = code;
code = get_byte(inp, bitpos);
bitpos += 8;
*outp++ = code;
col += 2;
}
while (col < width) {
/* get bitcode */
code = get_byte(inp, bitpos);
/* update bit position */
bitpos += table[code].len;
/* calculate pixel value */
if (table[code].is_abs) {
/* get 5 more bits and use them as absolute value */
code = get_byte(inp, bitpos);
val = (code & 0xf8);
bitpos += 5;
} else {
/* value is relative to top or left pixel */
val = table[code].val;
lp = outp[-2];
if (row > 1) {
tlp = outp[-2 * width - 2];
tp = outp[-2 * width];
trp = outp[-2 * width + 2];
}
if (row < 2) {
/* top row: relative to left pixel */
val += lp;
} else if (col < 2) {
/* left column: relative to top pixel */
/* initial estimate */
val += (tp + trp) / 2;
} else if (col > width - 3) {
/* left column: relative to top pixel */
val += (tp + lp + tlp + 1) / 3;
/* main area: weighted average of tlp, trp,
* lp, and tp */
} else {
tlp >>= 1;
trp >>= 1;
/* initial estimate for predictor */
val += (lp + tp + tlp + trp + 1) / 3;
}
}
/* store pixel */
*outp++ = CLIP(val);
++col;
}
/* src_size - 12 because of 12 byte footer */
if (((bitpos - 1) / 8) >= (src_size - 12)) {
data->frames_dropped++;
if (data->frames_dropped == 3) {
/* Tell the driver to go slower as
the compression engine is not able to
compress the image enough, we may
fail to do this because older
drivers don't support this */
SYS_IOCTL(data->fd, VIDIOC_G_CTRL,
&min_clockdiv);
min_clockdiv.value++;
SYS_IOCTL(data->fd, VIDIOC_S_CTRL,
&min_clockdiv);
/* We return success here, because if we
return failure for too many frames in a row
libv4l2 will return an error to the
application and some applications abort
on the first error received. */
data->frames_dropped = 0;
return 0;
}
V4LCONVERT_ERR("incomplete mr97310a frame\n");
return -1;
}
}
data->frames_dropped = 0;
return 0;
}

View File

@@ -0,0 +1,666 @@
/* We would like to embed this inside libv4l, but we cannot as I've failed
to contact Mark W. McClelland to get permission to relicense this,
so this lives in an external (GPL licensed) helper */
/* OV511 Decompression Support Module
*
* Copyright (c) 1999-2003 Mark W. McClelland. All rights reserved.
* http://alpha.dyndns.org/ov511/
*
* Original decompression code Copyright 1998-2000 OmniVision Technologies
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*/
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include "helper-funcs.h"
/******************************************************************************
* Decompression Functions
******************************************************************************/
static void DecompressYHI(unsigned char *pIn,
unsigned char *pOut,
int *iIn, /* in/out */
int *iOut, /* in/out */
const int w,
const int YUVFlag)
{
short ZigZag[64];
int temp[64];
int Zcnt_Flag = 0;
int Num8_Flag = 0;
int in_pos = *iIn;
int out_pos = *iOut;
int tmp, tmp1, tmp2, tmp3;
unsigned char header, ZTable[64];
short tmpl, tmph, half_byte, idx, count;
unsigned long ZigZag_length = 0, ZT_length, i, j;
short DeZigZag[64];
const short a = 11584;
const short b = 16068;
const short c = 15136;
const short d = 13624;
const short e = 9104;
const short f = 6270;
const short g = 3196;
int out_idx;
/* Take off every 'Zig' */
for (i = 0; i < 64; i++)
ZigZag[i] = 0;
/*****************************
* Read in the Y header byte *
*****************************/
header = pIn[in_pos];
in_pos++;
ZigZag_length = header & 0x3f;
ZigZag_length = ZigZag_length + 1;
Num8_Flag = header & 0x40;
Zcnt_Flag = header & 0x80;
/*************************
* Read in the Y content *
*************************/
if (Zcnt_Flag == 0) { /* Without Zero Table read contents directly */
/* Read in ZigZag[0] */
ZigZag[0] = pIn[in_pos++];
tmpl = pIn[in_pos++];
tmph = tmpl << 8;
ZigZag[0] = ZigZag[0] | tmph;
ZigZag[0] = ZigZag[0] << 4;
ZigZag[0] = ZigZag[0] >> 4;
if (Num8_Flag) { /* 8 Bits */
for (i = 1; i < ZigZag_length; i++) {
ZigZag[i] = pIn[in_pos++];
ZigZag[i] = ZigZag[i] << 8;
ZigZag[i] = ZigZag[i] >> 8;
}
} else { /* 12 bits and has no Zero Table */
idx = 1;
half_byte = 0;
for (i = 1; i < ZigZag_length; i++) {
if (half_byte == 0) {
ZigZag[i] = pIn[in_pos++];
tmpl = pIn[in_pos++];
tmph = tmpl << 8;
tmph = tmph & 0x0f00;
ZigZag[i] = ZigZag[i] | tmph;
ZigZag[i] = ZigZag[i] << 4;
ZigZag[i] = ZigZag[i] >> 4;
half_byte = 1;
} else {
ZigZag[i] = pIn[in_pos++];
ZigZag[i] = ZigZag[i] << 8;
tmpl = tmpl & 0x00f0;
ZigZag[i] = ZigZag[i] | tmpl;
ZigZag[i] = ZigZag[i] >> 4;
half_byte = 0;
}
}
}
} else { /* Has Zero Table */
/* Calculate Z-Table length */
ZT_length = ZigZag_length / 8;
tmp = ZigZag_length % 8;
if (tmp > 0)
ZT_length = ZT_length + 1;
/* Read in Zero Table */
for (j = 0; j < ZT_length; j++)
ZTable[j] = pIn[in_pos++];
/* Read in ZigZag[0] */
ZigZag[0] = pIn[in_pos++];
tmpl = pIn[in_pos++];
tmph = tmpl << 8;
ZigZag[0] = ZigZag[0] | tmph;
ZigZag[0] = ZigZag[0] << 4;
ZigZag[0] = ZigZag[0] >> 4;
/* Decode ZigZag */
idx = 0;
ZTable[idx] = ZTable[idx] << 1;
count = 7;
if (Num8_Flag) { /* 8 Bits and has zero table */
for (i = 1; i < ZigZag_length; i++) {
if ((ZTable[idx] & 0x80)) {
ZigZag[i] = pIn[in_pos++];
ZigZag[i] = ZigZag[i] << 8;
ZigZag[i] = ZigZag[i] >> 8;
}
ZTable[idx] = ZTable[idx]<<1;
count--;
if (count == 0) {
count = 8;
idx++;
}
}
} else { /* 12 bits and has Zero Table */
half_byte = 0;
for (i = 1; i < ZigZag_length; i++) {
if (ZTable[idx] & 0x80) {
if (half_byte == 0) {
ZigZag[i] = pIn[in_pos++];
tmpl = pIn[in_pos++];
tmph = tmpl << 8;
tmph = tmph & 0x0f00;
ZigZag[i] = ZigZag[i] | tmph;
ZigZag[i] = ZigZag[i] << 4;
ZigZag[i] = ZigZag[i] >> 4;
half_byte = 1;
} else {
ZigZag[i] = pIn[in_pos++];
ZigZag[i] = ZigZag[i] << 8;
tmpl = tmpl & 0x00f0;
ZigZag[i] = ZigZag[i] | tmpl;
ZigZag[i] = ZigZag[i] >> 4;
half_byte = 0;
}
}
ZTable[idx] = ZTable[idx] << 1;
count--;
if (count == 0) {
count = 8;
idx++;
}
}
}
}
/*************
* De-ZigZag *
*************/
for (j = 0; j < 64; j++)
DeZigZag[j] = 0;
if (YUVFlag == 1) {
DeZigZag[0] = ZigZag[0];
DeZigZag[1] = ZigZag[1] << 1;
DeZigZag[2] = ZigZag[5] << 1;
DeZigZag[3] = ZigZag[6] << 2;
DeZigZag[8] = ZigZag[2] << 1;
DeZigZag[9] = ZigZag[4] << 1;
DeZigZag[10] = ZigZag[7] << 1;
DeZigZag[11] = ZigZag[13] << 2;
DeZigZag[16] = ZigZag[3] << 1;
DeZigZag[17] = ZigZag[8] << 1;
DeZigZag[18] = ZigZag[12] << 2;
DeZigZag[19] = ZigZag[17] << 2;
DeZigZag[24] = ZigZag[9] << 2;
DeZigZag[25] = ZigZag[11] << 2;
DeZigZag[26] = ZigZag[18] << 2;
DeZigZag[27] = ZigZag[24] << 3;
} else {
DeZigZag[0] = ZigZag[0];
DeZigZag[1] = ZigZag[1] << 2;
DeZigZag[2] = ZigZag[5] << 2;
DeZigZag[3] = ZigZag[6] << 3;
DeZigZag[8] = ZigZag[2] << 2;
DeZigZag[9] = ZigZag[4] << 2;
DeZigZag[10] = ZigZag[7] << 2;
DeZigZag[11] = ZigZag[13] << 4;
DeZigZag[16] = ZigZag[3] << 2;
DeZigZag[17] = ZigZag[8] << 2;
DeZigZag[18] = ZigZag[12] << 3;
DeZigZag[19] = ZigZag[17] << 4;
DeZigZag[24] = ZigZag[9] << 3;
DeZigZag[25] = ZigZag[11] << 4;
DeZigZag[26] = ZigZag[18] << 4;
DeZigZag[27] = ZigZag[24] << 4;
}
/*****************
**** IDCT 1D ****
*****************/
#define IDCT_1D(c0, c1, c2, c3, in) \
do { \
tmp1 = ((c0) * DeZigZag[in]) + ((c2) * DeZigZag[(in) + 2]); \
tmp2 = (c1) * DeZigZag[(in) + 1]; \
tmp3 = (c3) * DeZigZag[(in) + 3]; \
} while (0)
#define COMPOSE_1(out1, out2) \
do { \
tmp = tmp1 + tmp2 + tmp3; \
temp[out1] = tmp >> 15; \
tmp = tmp1 - tmp2 - tmp3; \
temp[out2] = tmp >> 15; \
} while (0)
#define COMPOSE_2(out1, out2) \
do { \
tmp = tmp1 + tmp2 - tmp3; \
temp[out1] = tmp >> 15; \
tmp = tmp1 - tmp2 + tmp3; \
temp[out2] = tmp >> 15; \
} while (0)
/* j = 0 */
IDCT_1D(a, b, c, d, 0); COMPOSE_1(0, 56);
IDCT_1D(a, b, c, d, 8); COMPOSE_1(1, 57);
IDCT_1D(a, b, c, d, 16); COMPOSE_1(2, 58);
IDCT_1D(a, b, c, d, 24); COMPOSE_1(3, 59);
/* j = 1 */
IDCT_1D(a, d, f, g, 0); COMPOSE_2(8, 48);
IDCT_1D(a, d, f, g, 8); COMPOSE_2(9, 49);
IDCT_1D(a, d, f, g, 16); COMPOSE_2(10, 50);
IDCT_1D(a, d, f, g, 24); COMPOSE_2(11, 51);
/* j = 2 */
IDCT_1D(a, e, -f, b, 0); COMPOSE_2(16, 40);
IDCT_1D(a, e, -f, b, 8); COMPOSE_2(17, 41);
IDCT_1D(a, e, -f, b, 16); COMPOSE_2(18, 42);
IDCT_1D(a, e, -f, b, 24); COMPOSE_2(19, 43);
/* j = 3 */
IDCT_1D(a, g, -c, e, 0); COMPOSE_2(24, 32);
IDCT_1D(a, g, -c, e, 8); COMPOSE_2(25, 33);
IDCT_1D(a, g, -c, e, 16); COMPOSE_2(26, 34);
IDCT_1D(a, g, -c, e, 24); COMPOSE_2(27, 35);
#undef IDCT_1D
#undef COMPOSE_1
#undef COMPOSE_2
/*****************
**** IDCT 2D ****
*****************/
#define IDCT_2D(c0, c1, c2, c3, in) \
do { \
tmp = temp[in] * (c0) + temp[(in) + 1] * (c1) \
+ temp[(in) + 2] * (c2) + temp[(in) + 3] * (c3); \
} while (0)
#define STORE(i) \
do { \
tmp = tmp >> 15; \
tmp = tmp + 128; \
if (tmp > 255) \
tmp = 255; \
if (tmp < 0) \
tmp = 0; \
pOut[i] = (unsigned char)tmp; \
} while (0)
#define IDCT_2D_ROW(in) \
do { \
IDCT_2D(a, b, c, d, in); STORE(0 + out_idx); \
IDCT_2D(a, d, f, -g, in); STORE(1 + out_idx); \
IDCT_2D(a, e, -f, -b, in); STORE(2 + out_idx); \
IDCT_2D(a, g, -c, -e, in); STORE(3 + out_idx); \
IDCT_2D(a, -g, -c, e, in); STORE(4 + out_idx); \
IDCT_2D(a, -e, -f, b, in); STORE(5 + out_idx); \
IDCT_2D(a, -d, f, g, in); STORE(6 + out_idx); \
IDCT_2D(a, -b, c, -d, in); STORE(7 + out_idx); \
} while (0)
#define IDCT_2D_FAST(c0, c1, c2, c3, in) \
do { \
tmp1 = ((c0) * temp[in]) + ((c2) * temp[(in) + 2]); \
tmp2 = (c1) * temp[(in) + 1]; \
tmp3 = (c3) * temp[(in) + 3]; \
} while (0)
#define STORE_FAST_1(out1, out2) \
do { \
tmp = tmp1 + tmp2 + tmp3; \
STORE((out1) + out_idx); \
tmp = tmp1 - tmp2 - tmp3; \
STORE((out2) + out_idx); \
} while (0)
#define STORE_FAST_2(out1, out2) \
do { \
tmp = tmp1 + tmp2 - tmp3; \
STORE((out1) + out_idx); \
tmp = tmp1 - tmp2 + tmp3; \
STORE((out2) + out_idx); \
} while (0)
#define IDCT_2D_FAST_ROW(in) \
do { \
IDCT_2D_FAST(a, b, c, d, in); STORE_FAST_1(0, 7); \
IDCT_2D_FAST(a, d, f, g, in); STORE_FAST_2(1, 6); \
IDCT_2D_FAST(a, e, -f, b, in); STORE_FAST_2(2, 5); \
IDCT_2D_FAST(a, g, -c, e, in); STORE_FAST_2(3, 4); \
} while (0)
out_idx = out_pos;
IDCT_2D_ROW(0); out_idx += w;
IDCT_2D_ROW(8); out_idx += w;
IDCT_2D_ROW(16); out_idx += w;
IDCT_2D_ROW(24); out_idx += w;
IDCT_2D_ROW(32); out_idx += w;
IDCT_2D_ROW(40); out_idx += w;
IDCT_2D_FAST_ROW(48); out_idx += w;
IDCT_2D_FAST_ROW(56);
*iIn = in_pos;
*iOut = out_pos + 8;
}
#define DECOMP_Y() DecompressYHI(pIn, pY, &iIn, &iY, w, 1)
#define DECOMP_U() DecompressYHI(pIn, pU, &iIn, &iU, w / 2, 2)
#define DECOMP_V() DecompressYHI(pIn, pV, &iIn, &iV, w / 2, 2)
#if 0
static inline int
Decompress400HiNoMMX(unsigned char *pIn,
unsigned char *pOut,
const int w,
const int h,
const int inSize)
{
unsigned char *pY = pOut;
int x, y, iIn, iY;
iIn = 0;
for (y = 0; y < h; y += 8) {
iY = w * y;
for (x = 0; x < w; x += 8)
DECOMP_Y();
}
return 0;
}
#endif
static inline int
Decompress420HiNoMMX(unsigned char *pIn,
unsigned char *pOut,
const int w,
const int h,
const int inSize)
{
unsigned char *pY = pOut;
unsigned char *pU = pY + w * h;
unsigned char *pV = pU + w * h / 4;
int xY, xUV, iY, iU, iV, iIn, count;
const int nBlocks = (w * h) / (32 * 8);
iIn = 0;
iY = iU = iV = 0;
xY = xUV = 0;
for (count = 0; count < nBlocks; count++) {
DECOMP_U();
DECOMP_V(); xUV += 16;
if (xUV >= w) {
iU += (w * 7) / 2;
iV += (w * 7) / 2;
xUV = 0;
}
DECOMP_Y(); xY += 8;
DECOMP_Y(); xY += 8;
if (xY >= w) {
iY += w * 7;
xY = 0;
}
DECOMP_Y(); xY += 8;
DECOMP_Y(); xY += 8;
if (xY >= w) {
iY += w * 7;
xY = 0;
}
}
return 0;
}
/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
* image at pOut is specified by w.
*/
static inline void
make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
{
unsigned char *pOut1 = pOut;
int x, y;
for (y = 0; y < 8; y++) {
pOut1 = pOut;
for (x = 0; x < 8; x++)
*pOut1++ = *pIn++;
pOut += w;
}
}
#if 0
/*
* For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
* The segments represent 4 squares of 8x8 pixels as follows:
*
* 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
* 8 9 ... 15 72 73 ... 79 200 201 ... 207
* ... ... ...
* 56 57 ... 63 120 121 ... 127 248 249 ... 255
*
*/
static void
yuv400raw_to_yuv400p(struct ov511_frame *frame,
unsigned char *pIn0, unsigned char *pOut0)
{
int x, y;
unsigned char *pIn, *pOut, *pOutLine;
/* Copy Y */
pIn = pIn0;
pOutLine = pOut0;
for (y = 0; y < frame->rawheight - 1; y += 8) {
pOut = pOutLine;
for (x = 0; x < frame->rawwidth - 1; x += 8) {
make_8x8(pIn, pOut, frame->rawwidth);
pIn += 64;
pOut += 8;
}
pOutLine += 8 * frame->rawwidth;
}
}
#endif
/*
* For YUV 4:2:0 images, the data show up in 384 byte segments.
* The first 64 bytes of each segment are U, the next 64 are V. The U and
* V are arranged as follows:
*
* 0 1 ... 7
* 8 9 ... 15
* ...
* 56 57 ... 63
*
* U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
*
* The next 256 bytes are full resolution Y data and represent 4 squares
* of 8x8 pixels as follows:
*
* 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
* 8 9 ... 15 72 73 ... 79 200 201 ... 207
* ... ... ...
* 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255
*
* Note that the U and V data in one segment represent a 16 x 16 pixel
* area, but the Y data represent a 32 x 8 pixel area. If the width is not an
* even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
* next horizontal stripe.
*
* If dumppix module param is set, _parse_data just dumps the incoming segments,
* verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
* this puts the data on the standard output and can be analyzed with the
* parseppm.c utility I wrote. That's a much faster way for figuring out how
* these data are scrambled.
*/
/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
*
* FIXME: Currently only handles width and height that are multiples of 16
*/
static void
yuv420raw_to_yuv420p(unsigned char *pIn0, unsigned char *pOut0,
int width, int height)
{
int k, x, y;
unsigned char *pIn, *pOut, *pOutLine;
const unsigned int a = width * height;
const unsigned int w = width / 2;
/* Copy U and V */
pIn = pIn0;
pOutLine = pOut0 + a;
for (y = 0; y < height - 1; y += 16) {
pOut = pOutLine;
for (x = 0; x < width - 1; x += 16) {
make_8x8(pIn, pOut, w);
make_8x8(pIn + 64, pOut + a / 4, w);
pIn += 384;
pOut += 8;
}
pOutLine += 8 * w;
}
/* Copy Y */
pIn = pIn0 + 128;
pOutLine = pOut0;
k = 0;
for (y = 0; y < height - 1; y += 8) {
pOut = pOutLine;
for (x = 0; x < width - 1; x += 8) {
make_8x8(pIn, pOut, width);
pIn += 64;
pOut += 8;
if ((++k) > 3) {
k = 0;
pIn += 128;
}
}
pOutLine += 8 * width;
}
}
/* Remove all 0 blocks from input */
static void remove0blocks(unsigned char *pIn, int *inSize)
{
long long *in = (long long *)pIn;
long long *out = (long long *)pIn;
int i, j;
for (i = 0; i < *inSize; i += 32, in += 4) {
int all_zero = 1;
for (j = 0; j < 4; j++)
if (in[j]) {
all_zero = 0;
break;
}
/* Skip 32 byte blocks of all 0 */
if (all_zero)
continue;
for (j = 0; j < 4; j++)
*out++ = in[j];
}
*inSize -= (in - out) * 8;
}
static int v4lconvert_ov511_to_yuv420(unsigned char *src, unsigned char *dest,
int w, int h, int yvu, int src_size)
{
int rc = 0;
src_size -= 11; /* Remove footer */
remove0blocks(src, &src_size);
/* Compressed ? */
if (src[8] & 0x40)
rc = Decompress420HiNoMMX(src + 9, dest, w, h, src_size);
else
yuv420raw_to_yuv420p(src + 9, dest, w, h);
return rc;
}
int main(int argc, char *argv[])
{
int width, height, yvu, src_size, dest_size;
unsigned char src_buf[500000];
unsigned char dest_buf[500000];
while (1) {
if (v4lconvert_helper_read(STDIN_FILENO, &width, sizeof(int), argv[0]))
return 1; /* Erm, no way to recover without loosing sync with libv4l */
if (v4lconvert_helper_read(STDIN_FILENO, &height, sizeof(int), argv[0]))
return 1; /* Erm, no way to recover without loosing sync with libv4l */
if (v4lconvert_helper_read(STDIN_FILENO, &yvu, sizeof(int), argv[0]))
return 1; /* Erm, no way to recover without loosing sync with libv4l */
if (v4lconvert_helper_read(STDIN_FILENO, &src_size, sizeof(int), argv[0]))
return 1; /* Erm, no way to recover without loosing sync with libv4l */
if (src_size > sizeof(src_buf)) {
fprintf(stderr, "%s: error: src_buf too small, need: %d\n",
argv[0], src_size);
return 2;
}
if (v4lconvert_helper_read(STDIN_FILENO, src_buf, src_size, argv[0]))
return 1; /* Erm, no way to recover without loosing sync with libv4l */
dest_size = width * height * 3 / 2;
if (width <= 0 || width > SHRT_MAX || height <= 0 || height > SHRT_MAX) {
fprintf(stderr, "%s: error: width or height out of bounds\n",
argv[0]);
dest_size = -1;
} else if (dest_size > sizeof(dest_buf)) {
fprintf(stderr, "%s: error: dest_buf too small, need: %d\n",
argv[0], dest_size);
dest_size = -1;
} else if (v4lconvert_ov511_to_yuv420(src_buf, dest_buf, width, height,
yvu, src_size))
dest_size = -1;
if (v4lconvert_helper_write(STDOUT_FILENO, &dest_size, sizeof(int),
argv[0]))
return 1; /* Erm, no way to recover without loosing sync with libv4l */
if (dest_size == -1)
continue;
if (v4lconvert_helper_write(STDOUT_FILENO, dest_buf, dest_size, argv[0]))
return 1; /* Erm, no way to recover without loosing sync with libv4l */
}
}

1480
libv4lconvert/ov518-decomp.c Normal file
View File

File diff suppressed because it is too large Load Diff

436
libv4lconvert/pac207.c Normal file
View File

@@ -0,0 +1,436 @@
/*
# PAC207 decoder
# Bertrik.Sikken. Thomas Kaiser (C) 2005
# Copyright (C) 2003 2004 2005 Michel Xhaard
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
# Note this code was originally licensed under the GNU GPL instead of the
# GNU LGPL, its license has been changed with permission, see the permission
# mails at the end of this file.
*/
#include <string.h>
#include "libv4lconvert-priv.h"
#define CLIP(color) (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))
/* FIXME not threadsafe */
static int decoder_initialized;
static struct {
unsigned char is_abs;
unsigned char len;
signed char val;
} table[256];
static void init_pixart_decoder(void)
{
int i;
int is_abs, val, len;
for (i = 0; i < 256; i++) {
is_abs = 0;
val = 0;
len = 0;
if ((i & 0xC0) == 0) {
/* code 00 */
val = 0;
len = 2;
} else if ((i & 0xC0) == 0x40) {
/* code 01 */
val = -1;
len = 2;
} else if ((i & 0xC0) == 0x80) {
/* code 10 */
val = 1;
len = 2;
} else if ((i & 0xF0) == 0xC0) {
/* code 1100 */
val = -2;
len = 4;
} else if ((i & 0xF0) == 0xD0) {
/* code 1101 */
val = 2;
len = 4;
} else if ((i & 0xF8) == 0xE0) {
/* code 11100 */
val = -3;
len = 5;
} else if ((i & 0xF8) == 0xE8) {
/* code 11101 */
val = 3;
len = 5;
} else if ((i & 0xFC) == 0xF0) {
/* code 111100 */
val = -4;
len = 6;
} else if ((i & 0xFC) == 0xF4) {
/* code 111101 */
val = 4;
len = 6;
} else if ((i & 0xF8) == 0xF8) {
/* code 11111xxxxxx */
is_abs = 1;
val = 0;
len = 5;
}
table[i].is_abs = is_abs;
table[i].val = val;
table[i].len = len;
}
decoder_initialized = 1;
}
static inline unsigned char getByte(const unsigned char *inp,
unsigned int bitpos)
{
const unsigned char *addr;
addr = inp + (bitpos >> 3);
return (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
}
static inline unsigned short getShort(const unsigned char *pt)
{
return ((pt[0] << 8) | pt[1]);
}
static int
pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width,
int step_size, int abs_bits)
{
int col;
int val;
int bitpos;
unsigned char code;
if (!decoder_initialized)
init_pixart_decoder();
/* first two pixels are stored as raw 8-bit */
*outp++ = inp[2];
*outp++ = inp[3];
bitpos = 32;
/* main decoding loop */
for (col = 2; col < width; col++) {
/* get bitcode */
code = getByte(inp, bitpos);
bitpos += table[code].len;
/* calculate pixel value */
if (table[code].is_abs) {
/* absolute value: get 6 more bits */
code = getByte(inp, bitpos);
bitpos += abs_bits;
*outp++ = code & ~(0xff >> abs_bits);
} else {
/* relative to left pixel */
val = outp[-2] + table[code].val * step_size;
*outp++ = CLIP(val);
}
}
/* return line length, rounded up to next 16-bit word */
return 2 * ((bitpos + 15) / 16);
}
int v4lconvert_decode_pac207(struct v4lconvert_data *data,
const unsigned char *inp, int src_size, unsigned char *outp,
int width, int height)
{
/* we should received a whole frame with header and EOL marker
in myframe->data and return a GBRG pattern in frame->tmpbuffer
remove the header then copy line by line EOL is set with 0x0f 0xf0 marker
or 0x1e 0xe1 for compressed line*/
const unsigned char *end = inp + src_size;
unsigned short word;
int row;
/* iterate over all rows */
for (row = 0; row < height; row++) {
if ((inp + 2) > end) {
V4LCONVERT_ERR("incomplete pac207 frame\n");
return -1;
}
word = getShort(inp);
switch (word) {
case 0x0FF0:
memcpy(outp, inp + 2, width);
inp += (2 + width);
break;
case 0x1EE1:
inp += pac_decompress_row(inp, outp, width, 5, 6);
break;
case 0x2DD2:
inp += pac_decompress_row(inp, outp, width, 9, 5);
break;
case 0x3CC3:
inp += pac_decompress_row(inp, outp, width, 17, 4);
break;
case 0x4BB4:
/* skip or copy line? */
memcpy(outp, outp - 2 * width, width);
inp += 2;
break;
default: /* corrupt frame */
V4LCONVERT_ERR("unknown pac207 row header: 0x%04x\n", (int)word);
return -1;
}
outp += width;
}
return 0;
}
/*
Return-Path: <thomas@kaiser-linux.li>
Received: from koko.hhs.nl ([145.52.2.16] verified)
by hhs.nl (CommuniGate Pro SMTP 4.3.6)
with ESMTP id 88906346 for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 01:17:00 +0200
Received: from exim (helo=koko)
by koko.hhs.nl with local-smtp (Exim 4.62)
(envelope-from <thomas@kaiser-linux.li>)
id 1KBeEW-0001qu-H6
for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 01:17:00 +0200
Received: from [192.87.102.74] (port=41049 helo=filter6-ams.mf.surf.net)
by koko.hhs.nl with esmtp (Exim 4.62)
(envelope-from <thomas@kaiser-linux.li>)
id 1KBeEV-0001qn-2T
for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 01:17:00 +0200
Received: from smtp0.lie-comtel.li (smtp0.lie-comtel.li [217.173.238.80])
by filter6-ams.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m5PNGwSF007539
for <j.w.r.degoede@hhs.nl>; Thu, 26 Jun 2008 01:16:58 +0200
Received: from localhost (localhost.lie-comtel.li [127.0.0.1])
by smtp0.lie-comtel.li (Postfix) with ESMTP id DDB609FEC1D;
Thu, 26 Jun 2008 00:16:56 +0100 (GMT-1)
X-Virus-Scanned: Virus scanned by amavis at smtp.lie-comtel.li
Received: from [192.168.0.16] (217-173-228-198.cmts.powersurf.li [217.173.228.198])
by smtp0.lie-comtel.li (Postfix) with ESMTP id 80B589FEC19;
Thu, 26 Jun 2008 00:16:56 +0100 (GMT-1)
Message-ID: <4862D211.3000802@kaiser-linux.li>
Date: Thu, 26 Jun 2008 01:17:37 +0200
From: Thomas Kaiser <thomas@kaiser-linux.li>
User-Agent: Thunderbird 2.0.0.14 (X11/20080505)
MIME-Version: 1.0
To: Hans de Goede <j.w.r.degoede@hhs.nl>
CC: Thomas Kaiser <spca5xx@kaiser-linux.li>, bertrik@zonnet.nl,
mxhaard@magic.fr
Subject: Re: pac207 bayer decompression algorithm license question
References: <4862C0A4.3060003@hhs.nl>
In-Reply-To: <4862C0A4.3060003@hhs.nl>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-Canit-CHI2: 0.00
X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
X-Spam-Score: 0.00 () [Tag at 8.00]
X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
X-Canit-Stats-ID: 88604132 - 38b3b44cd798
X-Scanned-By: CanIt (www . roaringpenguin . com) on 192.87.102.74
X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 25062008 #787666, status: clean
Hello Hans
Hans de Goede wrote:
> Hi,
>
> As you may have seen on the mailinglist, I've created a userspace
> library to handle cam specific format handling in userspace where it
> belongs, see:
> http://hansdegoede.livejournal.com/
Yes, I saw it on the mail list and I think it is a good idea :-)
>
> I would like to also add support for decompressing the pac207's
> compressed bayer to this lib (and remove it from the kernel driver)
> for this I need permission to relicense the decompress code under the
> LGPL (version 2 or later).
Actually, this was done by Bertrik Sikken (bertrik@zonnet.nl), Michel
Xhaard (mxhaard@magic.fr) and me. But Bertrik was the one who found out
how to decode the lines :-)
>
> Can you give me permission for this, or if the code is not yours put
> me in contact with someone who can?
For me it's no problem to release it with LGPL. Maybe you have to ask
the other one's also.
>
> Thanks & Regards,
>
> Hans
Rgeards, Thomas
*/
/*
Return-Path: <mxhaard@magic.fr>
Received: from koko.hhs.nl ([145.52.2.16] verified)
by hhs.nl (CommuniGate Pro SMTP 4.3.6)
with ESMTP id 88910192 for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 09:15:37 +0200
Received: from exim (helo=koko)
by koko.hhs.nl with local-smtp (Exim 4.62)
(envelope-from <mxhaard@magic.fr>)
id 1KBlhh-0006Fi-Oe
for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 09:15:37 +0200
Received: from [194.171.167.220] (port=54180 helo=filter4-til.mf.surf.net)
by koko.hhs.nl with esmtp (Exim 4.62)
(envelope-from <mxhaard@magic.fr>)
id 1KBlhh-0006Fd-FY
for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 09:15:37 +0200
Received: from smtp4-g19.free.fr (smtp4-g19.free.fr [212.27.42.30])
by filter4-til.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m5Q7FY1I006360
for <j.w.r.degoede@hhs.nl>; Thu, 26 Jun 2008 09:15:34 +0200
Received: from smtp4-g19.free.fr (localhost.localdomain [127.0.0.1])
by smtp4-g19.free.fr (Postfix) with ESMTP id 51C683EA0E7;
Thu, 26 Jun 2008 09:15:34 +0200 (CEST)
Received: from [192.168.1.11] (lns-bzn-54-82-251-105-53.adsl.proxad.net [82.251.105.53])
by smtp4-g19.free.fr (Postfix) with ESMTP id 1149E3EA0C7;
Thu, 26 Jun 2008 09:15:34 +0200 (CEST)
From: Michel Xhaard <mxhaard@magic.fr>
To: Hans de Goede <j.w.r.degoede@hhs.nl>
Subject: Re: pac207 bayer decompression algorithm license question
Date: Thu, 26 Jun 2008 11:15:32 +0200
User-Agent: KMail/1.9.5
Cc: bertrik@zonnet.nl, spca5xx@kaiser-linux.li,
"Jean-Francois Moine" <moinejf@free.fr>
References: <48633F02.3040108@hhs.nl>
In-Reply-To: <48633F02.3040108@hhs.nl>
MIME-Version: 1.0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
Message-Id: <200806261115.32909.mxhaard@magic.fr>
X-Canit-CHI2: 0.00
X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
X-Spam-Score: 0.00 () [Tag at 8.00]
X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
X-Canit-Stats-ID: 88656338 - 0dde233cb8b5
X-Scanned-By: CanIt (www . roaringpenguin . com) on 194.171.167.220
X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 26062008 #787720, status: clean
Le jeudi 26 juin 2008 09:02, Hans de Goede a =E9crit=A0:
> Hi,
>
> As you may have seen on the mailinglist, I've created a userspace library
> to handle cam specific format handling in userspace, see:
> http://hansdegoede.livejournal.com/
>
> I would like to also add support for decompressing the pac207's compressed
> bayer to this lib (and remove it from the kernel driver) and I've heard
> from Thomas Kaiser that you are a co-author of the decompression code. In
> order to add support for decompressing pac207 compressed bayer to libv4l I
> need permission to relicense the decompression code under the LGPL (versi=
on
> 2 or later).
>
> Can you give me permission for this?
>
> Thanks & Regards,
>
> Hans
>
>
>
> p.s.
>
> Thomas has already given permission.
=46or me it is ok and a good idea for all free world familly ;-).
Bests regards
=2D-=20
Michel Xhaard
http://mxhaard.free.fr
*/
/*
Return-Path: <bertrik@sikken.nl>
Received: from koko.hhs.nl ([145.52.2.16] verified)
by hhs.nl (CommuniGate Pro SMTP 4.3.6)
with ESMTP id 88940205 for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 22:03:30 +0200
Received: from exim (helo=koko)
by koko.hhs.nl with local-smtp (Exim 4.62)
(envelope-from <bertrik@sikken.nl>)
id 1KBxgo-0003Dj-ET
for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 22:03:30 +0200
Received: from [192.87.102.69] (port=51992 helo=filter1-ams.mf.surf.net)
by koko.hhs.nl with esmtp (Exim 4.62)
(envelope-from <bertrik@sikken.nl>)
id 1KBxgo-0003Dd-5i
for j.w.r.degoede@hhs.nl; Thu, 26 Jun 2008 22:03:30 +0200
Received: from pelian.kabelfoon.nl (pelian3.kabelfoon.nl [62.45.45.106])
by filter1-ams.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m5QK3ThE007720
for <j.w.r.degoede@hhs.nl>; Thu, 26 Jun 2008 22:03:29 +0200
Received: from [192.168.1.1] (062-015-045-062.dynamic.caiway.nl [62.45.15.62])
by pelian.kabelfoon.nl (Postfix) with ESMTP id 9239B428100
for <j.w.r.degoede@hhs.nl>; Thu, 26 Jun 2008 22:03:29 +0200 (CEST)
Message-ID: <4863F611.80104@sikken.nl>
Date: Thu, 26 Jun 2008 22:03:29 +0200
From: Bertrik Sikken <bertrik@sikken.nl>
User-Agent: Thunderbird 2.0.0.14 (Windows/20080421)
MIME-Version: 1.0
To: Hans de Goede <j.w.r.degoede@hhs.nl>
Subject: Re: pac207 bayer decompression algorithm license question
References: <48633F02.3040108@hhs.nl>
In-Reply-To: <48633F02.3040108@hhs.nl>
X-Enigmail-Version: 0.95.6
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-Canit-CHI2: 0.00
X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
X-Spam-Score: 0.00 () [Tag at 8.00]
X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
X-Canit-Stats-ID: 88938005 - ef1f0836ffc7
X-Scanned-By: CanIt (www . roaringpenguin . com) on 192.87.102.69
X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 26062008 #787877, status: clean
Hallo Hans,
Hans de Goede wrote:
> Hi,
>
> As you may have seen on the mailinglist, I've created a userspace
> library to
> handle cam specific format handling in userspace, see:
> http://hansdegoede.livejournal.com/
O leuk, zoiets is naar mijn idee precies wat er nodig is voor webcam
support onder linux. Ik ben een jaar of 3 geleden heel actief geweest
met een aantal webcams, maar doe er tegenwoordig helemaal niets meer
aan.
> I would like to also add support for decompressing the pac207's compressed
> bayer to this lib (and remove it from the kernel driver) and I've heard
> from Thomas Kaiser that you are a co-author of the decompression code.
> In order to add support for decompressing pac207 compressed bayer to
> libv4l I need
> permission to relicense the decompression code under the LGPL (version 2
> or later).
>
> Can you give me permission for this?
Ja, vind ik goed.
Vriendelijke groet,
Bertrik
*/

View File

@@ -0,0 +1,217 @@
/*
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libv4lprocessing.h"
#include "libv4lprocessing-priv.h"
#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
#include "../libv4lsyscall-priv.h"
static int autogain_active(struct v4lprocessing_data *data)
{
int autogain;
autogain = v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN);
if (!autogain) {
/* Reset last_correction val */
data->last_gain_correction = 0;
}
return autogain;
}
/* Adjust ctrl value with steps steps, while not crossing limit */
static void autogain_adjust(struct v4l2_queryctrl *ctrl, int *value,
int steps, int limit, int accel)
{
int ctrl_range = (ctrl->maximum - ctrl->minimum) / ctrl->step;
/* If we are of 3 * deadzone or more, and we have a fine grained
control, take larger steps, otherwise we take ages to get to the
right setting point. We use 256 as tripping point for determining
fine grained controls here, as avg_lum has a range of 0 - 255. */
if (accel && abs(steps) >= 3 && ctrl_range > 256)
*value += steps * ctrl->step * (ctrl_range / 256);
/* If we are of by less then 3, but have a very finegrained control
still speed things up a bit */
else if (accel && ctrl_range > 1024)
*value += steps * ctrl->step * (ctrl_range / 1024);
else
*value += steps * ctrl->step;
if (steps > 0) {
if (*value > limit)
*value = limit;
} else {
if (*value < limit)
*value = limit;
}
}
/* auto gain and exposure algorithm based on the knee algorithm described here:
http://ytse.tricolour.net/docs/LowLightOptimization.html */
static int autogain_calculate_lookup_tables(
struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt)
{
int x, y, target, steps, avg_lum = 0;
int gain, exposure, orig_gain, orig_exposure, exposure_low;
struct v4l2_control ctrl;
struct v4l2_queryctrl gainctrl, expoctrl;
const int deadzone = 6;
ctrl.id = V4L2_CID_EXPOSURE;
expoctrl.id = V4L2_CID_EXPOSURE;
if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &expoctrl) ||
SYS_IOCTL(data->fd, VIDIOC_G_CTRL, &ctrl))
return 0;
exposure = orig_exposure = ctrl.value;
/* Determine a value below which we try to not lower the exposure,
as most exposure controls tend to jump with big steps in the low
range, causing oscilation, so we prefer to use gain when exposure
has hit this value */
exposure_low = (expoctrl.maximum - expoctrl.minimum) / 10;
/* If we have a fine grained exposure control only avoid the last 10 steps */
steps = exposure_low / expoctrl.step;
if (steps > 10)
steps = 10;
exposure_low = steps * expoctrl.step + expoctrl.minimum;
ctrl.id = V4L2_CID_GAIN;
gainctrl.id = V4L2_CID_GAIN;
if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &gainctrl) ||
SYS_IOCTL(data->fd, VIDIOC_G_CTRL, &ctrl))
return 0;
gain = orig_gain = ctrl.value;
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SRGGB8:
buf += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 4 +
fmt->fmt.pix.width / 4;
for (y = 0; (unsigned)y < fmt->fmt.pix.height / 2; y++) {
for (x = 0; (unsigned)x < fmt->fmt.pix.width / 2; x++)
avg_lum += *buf++;
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width / 2;
}
avg_lum /= fmt->fmt.pix.height * fmt->fmt.pix.width / 4;
break;
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
buf += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 4 +
fmt->fmt.pix.width * 3 / 4;
for (y = 0; (unsigned)y < fmt->fmt.pix.height / 2; y++) {
for (x = 0; (unsigned)x < fmt->fmt.pix.width / 2; x++) {
avg_lum += *buf++;
avg_lum += *buf++;
avg_lum += *buf++;
}
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3 / 2;
}
avg_lum /= fmt->fmt.pix.height * fmt->fmt.pix.width * 3 / 4;
break;
}
/* If we are off a multiple of deadzone, do multiple steps to reach the
desired lumination fast (with the risc of a slight overshoot) */
target = v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN_TARGET);
steps = (target - avg_lum) / deadzone;
/* If we were decreasing and are now increasing, or vica versa, half the
number of steps to avoid overshooting and oscilating */
if ((steps > 0 && data->last_gain_correction < 0) ||
(steps < 0 && data->last_gain_correction > 0))
steps /= 2;
if (steps == 0)
return 0; /* Nothing to do */
if (steps < 0) {
if (exposure > expoctrl.default_value)
autogain_adjust(&expoctrl, &exposure, steps,
expoctrl.default_value, 1);
else if (gain > gainctrl.default_value)
autogain_adjust(&gainctrl, &gain, steps,
gainctrl.default_value, 1);
else if (exposure > exposure_low)
autogain_adjust(&expoctrl, &exposure, steps,
exposure_low, 1);
else if (gain > gainctrl.minimum)
autogain_adjust(&gainctrl, &gain, steps,
gainctrl.minimum, 1);
else if (exposure > expoctrl.minimum)
autogain_adjust(&expoctrl, &exposure, steps,
expoctrl.minimum, 0);
else
steps = 0;
} else {
if (exposure < exposure_low)
autogain_adjust(&expoctrl, &exposure, steps,
exposure_low, 0);
else if (gain < gainctrl.default_value)
autogain_adjust(&gainctrl, &gain, steps,
gainctrl.default_value, 1);
else if (exposure < expoctrl.default_value)
autogain_adjust(&expoctrl, &exposure, steps,
expoctrl.default_value, 1);
else if (gain < gainctrl.maximum)
autogain_adjust(&gainctrl, &gain, steps,
gainctrl.maximum, 1);
else if (exposure < expoctrl.maximum)
autogain_adjust(&expoctrl, &exposure, steps,
expoctrl.maximum, 1);
else
steps = 0;
}
if (steps) {
data->last_gain_correction = steps;
/* We are still settling down, force the next update sooner. Note we
skip the next frame as that is still captured with the old settings,
and another one just to be sure (because if we re-adjust based
on the old settings we might overshoot). */
data->lookup_table_update_counter = V4L2PROCESSING_UPDATE_RATE - 2;
}
if (gain != orig_gain) {
ctrl.id = V4L2_CID_GAIN;
ctrl.value = gain;
SYS_IOCTL(data->fd, VIDIOC_S_CTRL, &ctrl);
}
if (exposure != orig_exposure) {
ctrl.id = V4L2_CID_EXPOSURE;
ctrl.value = exposure;
SYS_IOCTL(data->fd, VIDIOC_S_CTRL, &ctrl);
}
return 0;
}
struct v4lprocessing_filter autogain_filter = {
autogain_active, autogain_calculate_lookup_tables
};

View File

@@ -0,0 +1,61 @@
/*
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <math.h>
#include "libv4lprocessing.h"
#include "libv4lprocessing-priv.h"
#define CLIP(color) (unsigned char)(((color) > 0xff) ? 0xff : (((color) < 0) ? 0 : (color)))
static int gamma_active(struct v4lprocessing_data *data)
{
int gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA);
return gamma && gamma != 1000;
}
static int gamma_calculate_lookup_tables(
struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt)
{
int i, x, gamma;
gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA);
if (gamma == 0)
return 0;
if (gamma != data->last_gamma) {
for (i = 0; i < 256; i++) {
x = powf(i / 255.0, 1000.0 / gamma) * 255;
data->gamma_table[i] = CLIP(x);
}
data->last_gamma = gamma;
}
for (i = 0; i < 256; i++) {
data->comp1[i] = data->gamma_table[data->comp1[i]];
data->green[i] = data->gamma_table[data->green[i]];
data->comp2[i] = data->gamma_table[data->comp2[i]];
}
return 1;
}
struct v4lprocessing_filter gamma_filter = {
gamma_active, gamma_calculate_lookup_tables
};

View File

@@ -0,0 +1,67 @@
/*
# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#ifndef __LIBV4LPROCESSING_PRIV_H
#define __LIBV4LPROCESSING_PRIV_H
#include "../control/libv4lcontrol.h"
#include "../libv4lsyscall-priv.h"
#define V4L2PROCESSING_UPDATE_RATE 10
struct v4lprocessing_data {
struct v4lcontrol_data *control;
int fd;
int do_process;
int controls_changed;
/* True if any of the lookup tables does not contain
linear 0-255 */
int lookup_table_active;
/* Counts the number of processed frames until a
V4L2PROCESSING_UPDATE_RATE overflow happens */
int lookup_table_update_counter;
/* RGB/BGR lookup tables */
unsigned char comp1[256];
unsigned char green[256];
unsigned char comp2[256];
/* Filter private data for filters which need it */
/* whitebalance.c data */
int green_avg;
int comp1_avg;
int comp2_avg;
/* gamma.c data */
int last_gamma;
unsigned char gamma_table[256];
/* autogain.c data */
int last_gain_correction;
};
struct v4lprocessing_filter {
/* Returns 1 if the filter is active */
int (*active)(struct v4lprocessing_data *data);
/* Returns 1 if any of the lookup tables was changed */
int (*calculate_lookup_tables)(struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt);
};
extern struct v4lprocessing_filter whitebalance_filter;
extern struct v4lprocessing_filter autogain_filter;
extern struct v4lprocessing_filter gamma_filter;
#endif

View File

@@ -0,0 +1,187 @@
/*
# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libv4lprocessing.h"
#include "libv4lprocessing-priv.h"
#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
static struct v4lprocessing_filter *filters[] = {
&whitebalance_filter,
&autogain_filter,
&gamma_filter,
};
struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data *control)
{
struct v4lprocessing_data *data =
calloc(1, sizeof(struct v4lprocessing_data));
if (!data) {
fprintf(stderr, "libv4lprocessing: error: out of memory!\n");
return NULL;
}
data->fd = fd;
data->control = control;
return data;
}
void v4lprocessing_destroy(struct v4lprocessing_data *data)
{
free(data);
}
int v4lprocessing_pre_processing(struct v4lprocessing_data *data)
{
int i;
data->do_process = 0;
for (i = 0; i < ARRAY_SIZE(filters); i++) {
if (filters[i]->active(data))
data->do_process = 1;
}
data->controls_changed |= v4lcontrol_controls_changed(data->control);
return data->do_process;
}
static void v4lprocessing_update_lookup_tables(struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt)
{
int i;
for (i = 0; i < 256; i++) {
data->comp1[i] = i;
data->green[i] = i;
data->comp2[i] = i;
}
data->lookup_table_active = 0;
for (i = 0; i < ARRAY_SIZE(filters); i++) {
if (filters[i]->active(data)) {
if (filters[i]->calculate_lookup_tables(data, buf, fmt))
data->lookup_table_active = 1;
}
}
}
static void v4lprocessing_do_processing(struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt)
{
int x, y;
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */
for (y = 0; (unsigned)y < fmt->fmt.pix.height / 2; y++) {
for (x = 0; (unsigned)x < fmt->fmt.pix.width / 2; x++) {
*buf = data->green[*buf];
buf++;
*buf = data->comp1[*buf];
buf++;
}
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
for (x = 0; (unsigned)x < fmt->fmt.pix.width / 2; x++) {
*buf = data->comp2[*buf];
buf++;
*buf = data->green[*buf];
buf++;
}
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
}
break;
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */
for (y = 0; (unsigned)y < fmt->fmt.pix.height / 2; y++) {
for (x = 0; (unsigned)x < fmt->fmt.pix.width / 2; x++) {
*buf = data->comp1[*buf];
buf++;
*buf = data->green[*buf];
buf++;
}
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
for (x = 0; (unsigned)x < fmt->fmt.pix.width / 2; x++) {
*buf = data->green[*buf];
buf++;
*buf = data->comp2[*buf];
buf++;
}
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
}
break;
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
for (y = 0; (unsigned)y < fmt->fmt.pix.height; y++) {
for (x = 0; (unsigned)x < fmt->fmt.pix.width; x++) {
*buf = data->comp1[*buf];
buf++;
*buf = data->green[*buf];
buf++;
*buf = data->comp2[*buf];
buf++;
}
buf += fmt->fmt.pix.bytesperline - 3 * fmt->fmt.pix.width;
}
break;
}
}
void v4lprocessing_processing(struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt)
{
if (!data->do_process)
return;
/* Do we support the current pixformat? */
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SRGGB8:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
break;
default:
return; /* Non supported pix format */
}
if (data->controls_changed ||
data->lookup_table_update_counter == V4L2PROCESSING_UPDATE_RATE) {
data->controls_changed = 0;
data->lookup_table_update_counter = 0;
/* Do this after resetting lookup_table_update_counter so that filters can
force the next update to be sooner when they changed camera settings */
v4lprocessing_update_lookup_tables(data, buf, fmt);
} else
data->lookup_table_update_counter++;
if (data->lookup_table_active)
v4lprocessing_do_processing(data, buf, fmt);
data->do_process = 0;
}

View File

@@ -0,0 +1,42 @@
/*
# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#ifndef __LIBV4LPROCESSING_H
#define __LIBV4LPROCESSING_H
#include "../libv4lsyscall-priv.h"
#include <linux/videodev2.h>
struct v4lprocessing_data;
struct v4lcontrol_data;
struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data *data);
void v4lprocessing_destroy(struct v4lprocessing_data *data);
/* Prepare to process 1 frame, returns 1 if processing is necesary,
return 0 if no processing will be done */
int v4lprocessing_pre_processing(struct v4lprocessing_data *data);
/* Do the actual processing, this is a nop if v4lprocessing_pre_processing()
returned 0, or if called more then 1 time after a single
v4lprocessing_pre_processing() call. */
void v4lprocessing_processing(struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt);
#endif

View File

@@ -0,0 +1,209 @@
/*
# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libv4lprocessing.h"
#include "libv4lprocessing-priv.h"
#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
#define CLIP256(color) (((color) > 0xff) ? 0xff : (((color) < 0) ? 0 : (color)))
#define CLIP(color, min, max) (((color) > (max)) ? (max) : (((color) < (min)) ? (min) : (color)))
static int whitebalance_active(struct v4lprocessing_data *data)
{
int wb;
wb = v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE);
if (!wb) {
/* Reset cached color averages */
data->green_avg = 0;
}
return wb;
}
static int whitebalance_calculate_lookup_tables_generic(
struct v4lprocessing_data *data, int green_avg, int comp1_avg, int comp2_avg)
{
int i, avg_avg;
const int threshold = 64;
const int max_step = 128;
/* Clip averages (restricts maximum white balance correction) */
green_avg = CLIP(green_avg, 512, 3072);
comp1_avg = CLIP(comp1_avg, 512, 3072);
comp2_avg = CLIP(comp2_avg, 512, 3072);
/* First frame ? */
if (data->green_avg == 0) {
data->green_avg = green_avg;
data->comp1_avg = comp1_avg;
data->comp2_avg = comp2_avg;
} else {
/* Slowly adjust the averages used for the correction, so that
we do not get a sudden change in colors */
int throttling = 0;
if (abs(data->green_avg - green_avg) > max_step) {
if (data->green_avg < green_avg)
data->green_avg += max_step;
else
data->green_avg -= max_step;
throttling = 1;
} else
data->green_avg = green_avg;
if (abs(data->comp1_avg - comp1_avg) > max_step) {
if (data->comp1_avg < comp1_avg)
data->comp1_avg += max_step;
else
data->comp1_avg -= max_step;
throttling = 1;
} else
data->comp1_avg = comp1_avg;
if (abs(data->comp2_avg - comp2_avg) > max_step) {
if (data->comp2_avg < comp2_avg)
data->comp2_avg += max_step;
else
data->comp2_avg -= max_step;
throttling = 1;
} else
data->comp2_avg = comp2_avg;
/*
* If we are still converging to a stable update situation,
* re-calc the lookup tables next frame, but only if no
* other processing plugin has already asked for a shorter
* update cycle, as asking for an update each frame while
* some other pluging is trying to adjust hw settings is bad.
*/
if (throttling && data->lookup_table_update_counter == 0)
data->lookup_table_update_counter =
V4L2PROCESSING_UPDATE_RATE;
}
if (abs(data->green_avg - data->comp1_avg) < threshold &&
abs(data->green_avg - data->comp2_avg) < threshold &&
abs(data->comp1_avg - data->comp2_avg) < threshold)
return 0;
avg_avg = (data->green_avg + data->comp1_avg + data->comp2_avg) / 3;
for (i = 0; i < 256; i++) {
data->comp1[i] = CLIP256(data->comp1[i] * avg_avg / data->comp1_avg);
data->green[i] = CLIP256(data->green[i] * avg_avg / data->green_avg);
data->comp2[i] = CLIP256(data->comp2[i] * avg_avg / data->comp2_avg);
}
return 1;
}
static int whitebalance_calculate_lookup_tables_bayer(
struct v4lprocessing_data *data, unsigned char *buf,
const struct v4l2_format *fmt, int starts_with_green)
{
int x, y, a1 = 0, a2 = 0, b1 = 0, b2 = 0;
int green_avg, comp1_avg, comp2_avg;
for (y = 0; (unsigned)y < fmt->fmt.pix.height; y += 2) {
for (x = 0; (unsigned)x < fmt->fmt.pix.width; x += 2) {
a1 += *buf++;
a2 += *buf++;
}
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
for (x = 0; (unsigned)x < fmt->fmt.pix.width; x += 2) {
b1 += *buf++;
b2 += *buf++;
}
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
}
if (starts_with_green) {
green_avg = a1 / 2 + b2 / 2;
comp1_avg = a2;
comp2_avg = b1;
} else {
green_avg = a2 / 2 + b1 / 2;
comp1_avg = a1;
comp2_avg = b2;
}
/* Norm avg to ~ 0 - 4095 */
green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
return whitebalance_calculate_lookup_tables_generic(data, green_avg,
comp1_avg, comp2_avg);
}
static int whitebalance_calculate_lookup_tables_rgb(
struct v4lprocessing_data *data, unsigned char *buf,
const struct v4l2_format *fmt)
{
int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0;
for (y = 0; (unsigned)y < fmt->fmt.pix.height; y++) {
for (x = 0; (unsigned)x < fmt->fmt.pix.width; x++) {
comp1_avg += *buf++;
green_avg += *buf++;
comp2_avg += *buf++;
}
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3;
}
/* Norm avg to ~ 0 - 4095 */
green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
return whitebalance_calculate_lookup_tables_generic(data, green_avg,
comp1_avg, comp2_avg);
}
static int whitebalance_calculate_lookup_tables(
struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt)
{
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */
return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 1);
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */
return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 0);
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
return whitebalance_calculate_lookup_tables_rgb(data, buf, fmt);
}
return 0; /* Should never happen */
}
struct v4lprocessing_filter whitebalance_filter = {
whitebalance_active, whitebalance_calculate_lookup_tables
};

756
libv4lconvert/rgbyuv.c Normal file
View File

@@ -0,0 +1,756 @@
/*
# RGB <-> YUV conversion routines
# (C) 2008 Hans de Goede <hdegoede@redhat.com>
# RGB565 conversion routines
# (C) 2009 Mauro Carvalho Chehab
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <string.h>
#include "libv4lconvert-priv.h"
#define RGB2Y(r, g, b, y) \
(y) = ((8453 * (r) + 16594 * (g) + 3223 * (b) + 524288) >> 15)
#define RGB2UV(r, g, b, u, v) \
do { \
(u) = ((-4878 * (r) - 9578 * (g) + 14456 * (b) + 4210688) >> 15); \
(v) = ((14456 * (r) - 12105 * (g) - 2351 * (b) + 4210688) >> 15); \
} while (0)
void v4lconvert_rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, int bgr, int yvu, int bpp)
{
unsigned int x, y;
unsigned char *udest, *vdest;
/* Y */
for (y = 0; y < src_fmt->fmt.pix.height; y++) {
for (x = 0; x < src_fmt->fmt.pix.width; x++) {
if (bgr)
RGB2Y(src[2], src[1], src[0], *dest++);
else
RGB2Y(src[0], src[1], src[2], *dest++);
src += bpp;
}
src += src_fmt->fmt.pix.bytesperline - bpp * src_fmt->fmt.pix.width;
}
src -= src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline;
/* U + V */
if (yvu) {
vdest = dest;
udest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4;
} else {
udest = dest;
vdest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4;
}
for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) {
for (x = 0; x < src_fmt->fmt.pix.width / 2; x++) {
int avg_src[3];
avg_src[0] = (src[0] + src[bpp] + src[src_fmt->fmt.pix.bytesperline] +
src[src_fmt->fmt.pix.bytesperline + bpp]) / 4;
avg_src[1] = (src[1] + src[bpp + 1] + src[src_fmt->fmt.pix.bytesperline + 1] +
src[src_fmt->fmt.pix.bytesperline + bpp + 1]) / 4;
avg_src[2] = (src[2] + src[bpp + 2] + src[src_fmt->fmt.pix.bytesperline + 2] +
src[src_fmt->fmt.pix.bytesperline + bpp + 2]) / 4;
if (bgr)
RGB2UV(avg_src[2], avg_src[1], avg_src[0], *udest++, *vdest++);
else
RGB2UV(avg_src[0], avg_src[1], avg_src[2], *udest++, *vdest++);
src += 2 * bpp;
}
src += 2 * src_fmt->fmt.pix.bytesperline - bpp * src_fmt->fmt.pix.width;
}
}
#define YUV2R(y, u, v) ({ \
int r = (y) + ((((v) - 128) * 1436) >> 10); r > 255 ? 255 : r < 0 ? 0 : r; })
#define YUV2G(y, u, v) ({ \
int g = (y) - ((((u) - 128) * 352 + ((v) - 128) * 731) >> 10); g > 255 ? 255 : g < 0 ? 0 : g; })
#define YUV2B(y, u, v) ({ \
int b = (y) + ((((u) - 128) * 1814) >> 10); b > 255 ? 255 : b < 0 ? 0 : b; })
#define CLIP(color) (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))
void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dest,
int width, int height, int yvu)
{
int i, j;
const unsigned char *ysrc = src;
const unsigned char *usrc, *vsrc;
if (yvu) {
vsrc = src + width * height;
usrc = vsrc + (width * height) / 4;
} else {
usrc = src + width * height;
vsrc = usrc + (width * height) / 4;
}
for (i = 0; i < height; i++) {
for (j = 0; j < width; j += 2) {
#if 1 /* fast slightly less accurate multiplication free code */
int u1 = (((*usrc - 128) << 7) + (*usrc - 128)) >> 6;
int rg = (((*usrc - 128) << 1) + (*usrc - 128) +
((*vsrc - 128) << 2) + ((*vsrc - 128) << 1)) >> 3;
int v1 = (((*vsrc - 128) << 1) + (*vsrc - 128)) >> 1;
*dest++ = CLIP(*ysrc + u1);
*dest++ = CLIP(*ysrc - rg);
*dest++ = CLIP(*ysrc + v1);
ysrc++;
*dest++ = CLIP(*ysrc + u1);
*dest++ = CLIP(*ysrc - rg);
*dest++ = CLIP(*ysrc + v1);
#else
*dest++ = YUV2B(*ysrc, *usrc, *vsrc);
*dest++ = YUV2G(*ysrc, *usrc, *vsrc);
*dest++ = YUV2R(*ysrc, *usrc, *vsrc);
ysrc++;
*dest++ = YUV2B(*ysrc, *usrc, *vsrc);
*dest++ = YUV2G(*ysrc, *usrc, *vsrc);
*dest++ = YUV2R(*ysrc, *usrc, *vsrc);
#endif
ysrc++;
usrc++;
vsrc++;
}
/* Rewind u and v for next line */
if (!(i & 1)) {
usrc -= width / 2;
vsrc -= width / 2;
}
}
}
void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height, int yvu)
{
int i, j;
const unsigned char *ysrc = src;
const unsigned char *usrc, *vsrc;
if (yvu) {
vsrc = src + width * height;
usrc = vsrc + (width * height) / 4;
} else {
usrc = src + width * height;
vsrc = usrc + (width * height) / 4;
}
for (i = 0; i < height; i++) {
for (j = 0; j < width; j += 2) {
#if 1 /* fast slightly less accurate multiplication free code */
int u1 = (((*usrc - 128) << 7) + (*usrc - 128)) >> 6;
int rg = (((*usrc - 128) << 1) + (*usrc - 128) +
((*vsrc - 128) << 2) + ((*vsrc - 128) << 1)) >> 3;
int v1 = (((*vsrc - 128) << 1) + (*vsrc - 128)) >> 1;
*dest++ = CLIP(*ysrc + v1);
*dest++ = CLIP(*ysrc - rg);
*dest++ = CLIP(*ysrc + u1);
ysrc++;
*dest++ = CLIP(*ysrc + v1);
*dest++ = CLIP(*ysrc - rg);
*dest++ = CLIP(*ysrc + u1);
#else
*dest++ = YUV2R(*ysrc, *usrc, *vsrc);
*dest++ = YUV2G(*ysrc, *usrc, *vsrc);
*dest++ = YUV2B(*ysrc, *usrc, *vsrc);
ysrc++;
*dest++ = YUV2R(*ysrc, *usrc, *vsrc);
*dest++ = YUV2G(*ysrc, *usrc, *vsrc);
*dest++ = YUV2B(*ysrc, *usrc, *vsrc);
#endif
ysrc++;
usrc++;
vsrc++;
}
/* Rewind u and v for next line */
if (!(i&1)) {
usrc -= width / 2;
vsrc -= width / 2;
}
}
}
void v4lconvert_yuyv_to_bgr24(const unsigned char *src, unsigned char *dest,
int width, int height, int stride)
{
int j;
while (--height >= 0) {
for (j = 0; j + 1 < width; j += 2) {
int u = src[1];
int v = src[3];
int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
int rg = (((u - 128) << 1) + (u - 128) +
((v - 128) << 2) + ((v - 128) << 1)) >> 3;
int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
*dest++ = CLIP(src[0] + u1);
*dest++ = CLIP(src[0] - rg);
*dest++ = CLIP(src[0] + v1);
*dest++ = CLIP(src[2] + u1);
*dest++ = CLIP(src[2] - rg);
*dest++ = CLIP(src[2] + v1);
src += 4;
}
src += stride - width * 2;
}
}
void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height, int stride)
{
int j;
while (--height >= 0) {
for (j = 0; j + 1 < width; j += 2) {
int u = src[1];
int v = src[3];
int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
int rg = (((u - 128) << 1) + (u - 128) +
((v - 128) << 2) + ((v - 128) << 1)) >> 3;
int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
*dest++ = CLIP(src[0] + v1);
*dest++ = CLIP(src[0] - rg);
*dest++ = CLIP(src[0] + u1);
*dest++ = CLIP(src[2] + v1);
*dest++ = CLIP(src[2] - rg);
*dest++ = CLIP(src[2] + u1);
src += 4;
}
src += stride - (width * 2);
}
}
void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
int width, int height, int stride, int yvu)
{
int i, j;
const unsigned char *src1;
unsigned char *udest, *vdest;
/* copy the Y values */
src1 = src;
for (i = 0; i < height; i++) {
for (j = 0; j + 1 < width; j += 2) {
*dest++ = src1[0];
*dest++ = src1[2];
src1 += 4;
}
src1 += stride - width * 2;
}
/* copy the U and V values */
src++; /* point to V */
src1 = src + stride; /* next line */
if (yvu) {
vdest = dest;
udest = dest + width * height / 4;
} else {
udest = dest;
vdest = dest + width * height / 4;
}
for (i = 0; i < height; i += 2) {
for (j = 0; j + 1 < width; j += 2) {
*udest++ = ((int) src[0] + src1[0]) / 2; /* U */
*vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
src += 4;
src1 += 4;
}
src1 += stride - width * 2;
src = src1;
src1 += stride;
}
}
void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dest,
int width, int height, int stride)
{
int j;
while (--height >= 0) {
for (j = 0; j + 1 < width; j += 2) {
int u = src[3];
int v = src[1];
int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
int rg = (((u - 128) << 1) + (u - 128) +
((v - 128) << 2) + ((v - 128) << 1)) >> 3;
int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
*dest++ = CLIP(src[0] + u1);
*dest++ = CLIP(src[0] - rg);
*dest++ = CLIP(src[0] + v1);
*dest++ = CLIP(src[2] + u1);
*dest++ = CLIP(src[2] - rg);
*dest++ = CLIP(src[2] + v1);
src += 4;
}
src += stride - (width * 2);
}
}
void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height, int stride)
{
int j;
while (--height >= 0) {
for (j = 0; j + 1 < width; j += 2) {
int u = src[3];
int v = src[1];
int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
int rg = (((u - 128) << 1) + (u - 128) +
((v - 128) << 2) + ((v - 128) << 1)) >> 3;
int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
*dest++ = CLIP(src[0] + v1);
*dest++ = CLIP(src[0] - rg);
*dest++ = CLIP(src[0] + u1);
*dest++ = CLIP(src[2] + v1);
*dest++ = CLIP(src[2] - rg);
*dest++ = CLIP(src[2] + u1);
src += 4;
}
src += stride - (width * 2);
}
}
void v4lconvert_uyvy_to_bgr24(const unsigned char *src, unsigned char *dest,
int width, int height, int stride)
{
int j;
while (--height >= 0) {
for (j = 0; j + 1 < width; j += 2) {
int u = src[0];
int v = src[2];
int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
int rg = (((u - 128) << 1) + (u - 128) +
((v - 128) << 2) + ((v - 128) << 1)) >> 3;
int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
*dest++ = CLIP(src[1] + u1);
*dest++ = CLIP(src[1] - rg);
*dest++ = CLIP(src[1] + v1);
*dest++ = CLIP(src[3] + u1);
*dest++ = CLIP(src[3] - rg);
*dest++ = CLIP(src[3] + v1);
src += 4;
}
src += stride - width * 2;
}
}
void v4lconvert_uyvy_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height, int stride)
{
int j;
while (--height >= 0) {
for (j = 0; j + 1 < width; j += 2) {
int u = src[0];
int v = src[2];
int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
int rg = (((u - 128) << 1) + (u - 128) +
((v - 128) << 2) + ((v - 128) << 1)) >> 3;
int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
*dest++ = CLIP(src[1] + v1);
*dest++ = CLIP(src[1] - rg);
*dest++ = CLIP(src[1] + u1);
*dest++ = CLIP(src[3] + v1);
*dest++ = CLIP(src[3] - rg);
*dest++ = CLIP(src[3] + u1);
src += 4;
}
src += stride - width * 2;
}
}
void v4lconvert_uyvy_to_yuv420(const unsigned char *src, unsigned char *dest,
int width, int height, int stride, int yvu)
{
int i, j;
const unsigned char *src1;
unsigned char *udest, *vdest;
/* copy the Y values */
src1 = src;
for (i = 0; i < height; i++) {
for (j = 0; j + 1 < width; j += 2) {
*dest++ = src1[1];
*dest++ = src1[3];
src1 += 4;
}
src1 += stride - width * 2;
}
/* copy the U and V values */
src1 = src + stride; /* next line */
if (yvu) {
vdest = dest;
udest = dest + width * height / 4;
} else {
udest = dest;
vdest = dest + width * height / 4;
}
for (i = 0; i < height; i += 2) {
for (j = 0; j + 1 < width; j += 2) {
*udest++ = ((int) src[0] + src1[0]) / 2; /* U */
*vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
src += 4;
src1 += 4;
}
src1 += stride - width * 2;
src = src1;
src1 += stride;
}
}
void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst,
int width, int height)
{
int i;
for (i = 0; i < (width * height); i++) {
unsigned char tmp0, tmp1;
tmp0 = *src++;
tmp1 = *src++;
*dst++ = *src++;
*dst++ = tmp1;
*dst++ = tmp0;
}
}
void v4lconvert_swap_uv(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt)
{
unsigned int y;
/* Copy Y */
for (y = 0; y < src_fmt->fmt.pix.height; y++) {
memcpy(dest, src, src_fmt->fmt.pix.width);
dest += src_fmt->fmt.pix.width;
src += src_fmt->fmt.pix.bytesperline;
}
/* Copy component 2 */
src += src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline / 4;
for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) {
memcpy(dest, src, src_fmt->fmt.pix.width / 2);
dest += src_fmt->fmt.pix.width / 2;
src += src_fmt->fmt.pix.bytesperline / 2;
}
/* Copy component 1 */
src -= src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline / 2;
for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) {
memcpy(dest, src, src_fmt->fmt.pix.width / 2);
dest += src_fmt->fmt.pix.width / 2;
src += src_fmt->fmt.pix.bytesperline / 2;
}
}
void v4lconvert_rgb565_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height)
{
int j;
while (--height >= 0) {
for (j = 0; j < width; j++) {
unsigned short tmp = *(unsigned short *)src;
/* Original format: rrrrrggg gggbbbbb */
*dest++ = 0xf8 & (tmp >> 8);
*dest++ = 0xfc & (tmp >> 3);
*dest++ = 0xf8 & (tmp << 3);
src += 2;
}
}
}
void v4lconvert_rgb565_to_bgr24(const unsigned char *src, unsigned char *dest,
int width, int height)
{
int j;
while (--height >= 0) {
for (j = 0; j < width; j++) {
unsigned short tmp = *(unsigned short *)src;
/* Original format: rrrrrggg gggbbbbb */
*dest++ = 0xf8 & (tmp << 3);
*dest++ = 0xfc & (tmp >> 3);
*dest++ = 0xf8 & (tmp >> 8);
src += 2;
}
}
}
void v4lconvert_rgb565_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, int yvu)
{
unsigned int x, y;
unsigned short tmp;
unsigned char *udest, *vdest;
unsigned r[4], g[4], b[4];
int avg_src[3];
/* Y */
for (y = 0; y < src_fmt->fmt.pix.height; y++) {
for (x = 0; x < src_fmt->fmt.pix.width; x++) {
tmp = *(unsigned short *)src;
r[0] = 0xf8 & (tmp << 3);
g[0] = 0xfc & (tmp >> 3);
b[0] = 0xf8 & (tmp >> 8);
RGB2Y(r[0], g[0], b[0], *dest++);
src += 2;
}
src += src_fmt->fmt.pix.bytesperline - 2 * src_fmt->fmt.pix.width;
}
src -= src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline;
/* U + V */
if (yvu) {
vdest = dest;
udest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4;
} else {
udest = dest;
vdest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4;
}
for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) {
for (x = 0; x < src_fmt->fmt.pix.width / 2; x++) {
tmp = *(unsigned short *)src;
r[0] = 0xf8 & (tmp << 3);
g[0] = 0xfc & (tmp >> 3);
b[0] = 0xf8 & (tmp >> 8);
tmp = *(((unsigned short *)src) + 1);
r[1] = 0xf8 & (tmp << 3);
g[1] = 0xfc & (tmp >> 3);
b[1] = 0xf8 & (tmp >> 8);
tmp = *(((unsigned short *)src) + src_fmt->fmt.pix.bytesperline);
r[2] = 0xf8 & (tmp << 3);
g[2] = 0xfc & (tmp >> 3);
b[2] = 0xf8 & (tmp >> 8);
tmp = *(((unsigned short *)src) + src_fmt->fmt.pix.bytesperline + 1);
r[3] = 0xf8 & (tmp << 3);
g[3] = 0xfc & (tmp >> 3);
b[3] = 0xf8 & (tmp >> 8);
avg_src[0] = (r[0] + r[1] + r[2] + r[3]) / 4;
avg_src[1] = (g[0] + g[1] + g[2] + g[3]) / 4;
avg_src[2] = (b[0] + b[1] + b[2] + b[3]) / 4;
RGB2UV(avg_src[0], avg_src[1], avg_src[2], *udest++, *vdest++);
src += 4;
}
src += 2 * src_fmt->fmt.pix.bytesperline - 2 * src_fmt->fmt.pix.width;
}
}
void v4lconvert_y16_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height, int little_endian)
{
int j;
if (little_endian)
src++;
while (--height >= 0) {
for (j = 0; j < width; j++) {
*dest++ = *src;
*dest++ = *src;
*dest++ = *src;
src+=2;
}
}
}
void v4lconvert_y16_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, int little_endian)
{
unsigned int x, y;
if (little_endian)
src++;
/* Y */
for (y = 0; y < src_fmt->fmt.pix.height; y++)
for (x = 0; x < src_fmt->fmt.pix.width; x++){
*dest++ = *src;
src+=2;
}
/* Clear U/V */
memset(dest, 0x80, src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 2);
}
void v4lconvert_grey_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height)
{
int j;
while (--height >= 0) {
for (j = 0; j < width; j++) {
*dest++ = *src;
*dest++ = *src;
*dest++ = *src;
src++;
}
}
}
void v4lconvert_grey_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt)
{
unsigned int x, y;
/* Y */
for (y = 0; y < src_fmt->fmt.pix.height; y++)
for (x = 0; x < src_fmt->fmt.pix.width; x++)
*dest++ = *src++;
/* Clear U/V */
memset(dest, 0x80, src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 2);
}
/* Unpack buffer of (vw bit) data into padded 16bit buffer. */
static inline void convert_packed_to_16bit(const uint8_t *raw, uint16_t *unpacked,
int vw, int unpacked_len)
{
int mask = (1 << vw) - 1;
uint32_t buffer = 0;
int bitsIn = 0;
while (unpacked_len--) {
while (bitsIn < vw) {
buffer = (buffer << 8) | *(raw++);
bitsIn += 8;
}
bitsIn -= vw;
*(unpacked++) = (buffer >> bitsIn) & mask;
}
}
int v4lconvert_y10b_to_rgb24(struct v4lconvert_data *data,
const unsigned char *src, unsigned char *dest, int width, int height)
{
unsigned char *unpacked_buffer;
unpacked_buffer = v4lconvert_alloc_buffer(width * height * 2,
&data->convert_pixfmt_buf,
&data->convert_pixfmt_buf_size);
if (!unpacked_buffer)
return v4lconvert_oom_error(data);
convert_packed_to_16bit((uint8_t *)src, (uint16_t *)unpacked_buffer,
10, width * height);
int j;
unsigned short *tmp = (unsigned short *)unpacked_buffer;
while (--height >= 0) {
for (j = 0; j < width; j++) {
/* Only 10 useful bits, so we discard the LSBs */
*dest++ = (*tmp & 0x3ff) >> 2;
*dest++ = (*tmp & 0x3ff) >> 2;
*dest++ = (*tmp & 0x3ff) >> 2;
/* +1 means two bytes as we are dealing with (unsigned short) */
tmp += 1;
}
}
return 0;
}
int v4lconvert_y10b_to_yuv420(struct v4lconvert_data *data,
const unsigned char *src, unsigned char *dest, int width, int height)
{
unsigned char *unpacked_buffer;
unpacked_buffer = v4lconvert_alloc_buffer(width * height * 2,
&data->convert_pixfmt_buf,
&data->convert_pixfmt_buf_size);
if (!unpacked_buffer)
return v4lconvert_oom_error(data);
convert_packed_to_16bit((uint8_t *)src, (uint16_t *)unpacked_buffer,
10, width * height);
int x, y;
unsigned short *tmp = (unsigned short *)unpacked_buffer;
/* Y */
for (y = 0; y < height; y++)
for (x = 0; x < width; x++) {
/* Only 10 useful bits, so we discard the LSBs */
*dest++ = (*tmp & 0x3ff) >> 2;
/* +1 means two bytes as we are dealing with (unsigned short) */
tmp += 1;
}
/* Clear U/V */
memset(dest, 0x80, width * height / 2);
return 0;
}
void v4lconvert_rgb32_to_rgb24(const unsigned char *src, unsigned char *dest,
int width, int height,int bgr)
{
int j;
while (--height >= 0) {
for (j = 0; j < width; j++) {
if (bgr){
*dest++ = src[2];
*dest++ = src[1];
*dest++ = src[0];
src+=4;
}
else{
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
src+=1;
}
}
}
}

164
libv4lconvert/se401.c Normal file
View File

@@ -0,0 +1,164 @@
/*
# (C) 2011 Hans de Goede <hdegoede@redhat.com>
# The compression algorithm has been taken from the v4l1 se401 linux kernel
# driver by Jeroen B. Vreeken (pe1rxq@amsat.org)
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include "libv4lconvert-priv.h"
#include <errno.h>
/* The se401 compression algorithm uses a fixed quant factor, which
can be configured by setting the high nibble of the SE401_OPERATINGMODE
feature. This needs to exactly match what is in the SE401 driver! */
#define SE401_QUANT_FACT 8
static void wr_pixel(int p, uint8_t **dest, int pitch, int *x)
{
int i = *x;
/* First 3 pixels of each line are absolute */
if (i < 3) {
(*dest)[i] = p * SE401_QUANT_FACT;
} else {
(*dest)[i] = (*dest)[i - 3] + p * SE401_QUANT_FACT;
}
*x += 1;
if (*x == pitch) {
*x = 0;
*dest += pitch;
}
}
enum decode_state {
get_len,
sign_bit,
other_bits,
};
static int decode_JangGu(const uint8_t *data, int bits, int plen, int pixels,
uint8_t **dest, int pitch, int *x)
{
enum decode_state state = get_len;
int len = 0;
int value = 0;
int bitnr;
int bit;
while (plen) {
bitnr = 8;
while (bitnr && bits) {
bit = ((*data) >> (bitnr-1))&1;
switch (state) {
case get_len:
if (bit) {
len++;
} else {
if (!len) {
wr_pixel(0, dest, pitch, x);
if (!--pixels)
return 0;
} else {
state = sign_bit;
value = 0;
}
}
break;
case sign_bit:
if (bit)
value = 0;
else
value = -(1 << len) + 1;
state = other_bits;
/* fall through for positive number and
len == 1 handling */
case other_bits:
len--;
value += bit << len;
if (len == 0) {
/* Done write pixel and get bit len of
the next one */
state = get_len;
wr_pixel(value, dest, pitch, x);
if (!--pixels)
return 0;
}
break;
}
bitnr--;
bits--;
}
data++;
plen--;
}
return -1;
}
int v4lconvert_se401_to_rgb24(struct v4lconvert_data *data,
const unsigned char *src, int src_size,
unsigned char *dest, int width, int height)
{
int in, plen, bits, pixels, info;
int x = 0, total_pixels = 0;
if (!src || !dest)
goto error;
for (in = 0; in + 4 < src_size; in += plen) {
bits = src[in + 3] + (src[in + 2] << 8);
pixels = src[in + 1] + ((src[in + 0] & 0x3f) << 8);
info = (src[in + 0] & 0xc0) >> 6;
plen = ((bits + 47) >> 4) << 1;
/* Sanity checks */
if (plen > 1024) {
V4LCONVERT_ERR("invalid se401 packet len %d", plen);
goto error;
}
if (in + plen > src_size) {
V4LCONVERT_ERR("incomplete se401 packet");
goto error;
}
if (total_pixels + pixels > width * height) {
V4LCONVERT_ERR("se401 frame overflow");
goto error;
}
/* info: 0 inter packet, 1 eof, 2 sof, 3 not used */
if ((in == 0 && info != 2) ||
(in > 0 && in + plen < src_size && info != 0) ||
(in + plen == src_size && info != 1)) {
V4LCONVERT_ERR("invalid se401 frame info value");
goto error;
}
if (decode_JangGu(&src[in + 4], bits, plen, pixels * 3,
&dest, width * 3, &x)) {
V4LCONVERT_ERR("short se401 packet");
goto error;
}
total_pixels += pixels;
}
if (in != src_size || total_pixels != width * height) {
V4LCONVERT_ERR("se401 frame size mismatch");
goto error;
}
return 0;
error:
errno = EIO;
return -1;
}

273
libv4lconvert/sn9c10x.c Normal file
View File

@@ -0,0 +1,273 @@
/*
# sonix decoder
# Bertrik.Sikken. (C) 2005
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
# Note this code was originally licensed under the GNU GPL instead of the
# GNU LGPL, its license has been changed with permission, see the permission
# mail at the end of this file.
*/
#include "libv4lconvert-priv.h"
#define CLAMP(x) ((x) < 0 ? 0 : ((x) > 255) ? 255 : (x))
struct code_table {
int is_abs;
int len;
int val;
int unk;
};
/* local storage */
/* FIXME not thread safe !! */
static struct code_table table[256];
static int init_done;
/*
sonix_decompress_init
=====================
pre-calculates a locally stored table for efficient huffman-decoding.
Each entry at index x in the table represents the codeword
present at the MSB of byte x.
*/
static void sonix_decompress_init(void)
{
int i;
int is_abs, val, len, unk;
for (i = 0; i < 256; i++) {
is_abs = 0;
val = 0;
len = 0;
unk = 0;
if ((i & 0x80) == 0) {
/* code 0 */
val = 0;
len = 1;
} else if ((i & 0xE0) == 0x80) {
/* code 100 */
val = 4;
len = 3;
} else if ((i & 0xE0) == 0xA0) {
/* code 101 */
val = -4;
len = 3;
} else if ((i & 0xF0) == 0xD0) {
/* code 1101 */
val = 11;
len = 4;
} else if ((i & 0xF0) == 0xF0) {
/* code 1111 */
val = -11;
len = 4;
} else if ((i & 0xF8) == 0xC8) {
/* code 11001 */
val = 20;
len = 5;
} else if ((i & 0xFC) == 0xC0) {
/* code 110000 */
val = -20;
len = 6;
} else if ((i & 0xFC) == 0xC4) {
/* code 110001xx: unknown */
val = 0;
len = 8;
unk = 1;
} else if ((i & 0xF0) == 0xE0) {
/* code 1110xxxx */
is_abs = 1;
val = (i & 0x0F) << 4;
len = 8;
}
table[i].is_abs = is_abs;
table[i].val = val;
table[i].len = len;
table[i].unk = unk;
}
init_done = 1;
}
/*
sonix_decompress
================
decompresses an image encoded by a SN9C101 camera controller chip.
IN width
height
inp pointer to compressed frame (with header already stripped)
OUT outp pointer to decompressed frame
Returns 0 if the operation was successful.
Returns <0 if operation failed.
*/
void v4lconvert_decode_sn9c10x(const unsigned char *inp, unsigned char *outp,
int width, int height)
{
int row, col;
int val;
int bitpos;
unsigned char code;
const unsigned char *addr;
if (!init_done)
sonix_decompress_init();
bitpos = 0;
for (row = 0; row < height; row++) {
col = 0;
/* first two pixels in first two rows are stored as raw 8-bit */
if (row < 2) {
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
bitpos += 8;
*outp++ = code;
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
bitpos += 8;
*outp++ = code;
col += 2;
}
while (col < width) {
/* get bitcode from bitstream */
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
/* update bit position */
bitpos += table[code].len;
/* Skip unknown codes (most likely they indicate
a change of the delta's the various codes encode) */
if (table[code].unk)
continue;
/* calculate pixel value */
val = table[code].val;
if (!table[code].is_abs) {
/* value is relative to top and left pixel */
if (col < 2) {
/* left column: relative to top pixel */
val += outp[-2 * width];
} else if (row < 2) {
/* top row: relative to left pixel */
val += outp[-2];
} else {
/* main area: average of left pixel and top pixel */
val += (outp[-2] + outp[-2 * width]) / 2;
}
}
/* store pixel */
*outp++ = CLAMP(val);
col++;
}
}
}
/*
Return-Path: <bertrik@sikken.nl>
Received: from koko.hhs.nl ([145.52.2.16] verified)
by hhs.nl (CommuniGate Pro SMTP 4.3.6)
with ESMTP id 89132066 for j.w.r.degoede@hhs.nl; Thu, 03 Jul 2008 15:19:55 +0200
Received: from exim (helo=koko)
by koko.hhs.nl with local-smtp (Exim 4.62)
(envelope-from <bertrik@sikken.nl>)
id 1KEOj5-0000nq-KR
for j.w.r.degoede@hhs.nl; Thu, 03 Jul 2008 15:19:55 +0200
Received: from [192.87.102.69] (port=33783 helo=filter1-ams.mf.surf.net)
by koko.hhs.nl with esmtp (Exim 4.62)
(envelope-from <bertrik@sikken.nl>)
id 1KEOj5-0000nj-7r
for j.w.r.degoede@hhs.nl; Thu, 03 Jul 2008 15:19:55 +0200
Received: from cardassian.kabelfoon.nl (cardassian3.kabelfoon.nl [62.45.45.105])
by filter1-ams.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m63DJsKW032598
for <j.w.r.degoede@hhs.nl>; Thu, 3 Jul 2008 15:19:54 +0200
Received: from [192.168.1.1] (044-013-045-062.dynamic.caiway.nl [62.45.13.44])
by cardassian.kabelfoon.nl (Postfix) with ESMTP id 77761341D9A
for <j.w.r.degoede@hhs.nl>; Thu, 3 Jul 2008 15:19:54 +0200 (CEST)
Message-ID: <486CD1F9.8000307@sikken.nl>
Date: Thu, 03 Jul 2008 15:19:53 +0200
From: Bertrik Sikken <bertrik@sikken.nl>
User-Agent: Thunderbird 2.0.0.14 (Windows/20080421)
MIME-Version: 1.0
To: Hans de Goede <j.w.r.degoede@hhs.nl>
Subject: Re: pac207 bayer decompression algorithm license question
References: <48633F02.3040108@hhs.nl> <4863F611.80104@sikken.nl> <486CC6AF.7050509@hhs.nl>
In-Reply-To: <486CC6AF.7050509@hhs.nl>
X-Enigmail-Version: 0.95.6
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-Canit-CHI2: 0.00
X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
X-Spam-Score: 0.00 () [Tag at 8.00]
X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
X-Canit-Stats-ID: 90943081 - 6a9ff19e8165
X-Scanned-By: CanIt (www . roaringpenguin . com) on 192.87.102.69
X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 03072008 #811719, status: clean
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hans de Goede wrote:
| Bertrik Sikken wrote:
|> Hallo Hans,
|>
|> Hans de Goede wrote:
|>> I would like to also add support for decompressing the pac207's
|>> compressed
|>> bayer to this lib (and remove it from the kernel driver) and I've
|>> heard from Thomas Kaiser that you are a co-author of the
|>> decompression code. In order to add support for decompressing pac207
|>> compressed bayer to libv4l I need
|>> permission to relicense the decompression code under the LGPL
|>> (version 2 or later).
|>>
|>> Can you give me permission for this?
|>
|> Ja, vind ik goed.
|>
|
| Thanks!
|
| I'm currently working on adding support for the sn9c10x bayer
| compression to libv4l too, and I noticed this was written by you too.
|
| May I have your permission to relicense the sn9c10x bayer decompression
| code under the LGPL (version 2 or later)?
I hereby grant you permission to relicense the sn9c10x bayer
decompression code under the LGPL (version 2 or later).
Kind regards,
Bertrik
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFIbNH5ETD6mlrWxPURAipvAJ9sv1ZpHyb81NMFejr6x0wqHX3i7QCfRDoB
jZi2e5lUjEh5KvS0dqXbi9I=
=KQfR
-----END PGP SIGNATURE-----
*/

View File

@@ -0,0 +1,154 @@
/*
* 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 <kilgota@auburn.edu>
*
* 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 <hrx@users.sourceforge.net>. 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, version 2.1, as published by the Free Software Foundation.
*
*
* 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 <num> bits into the low bits of <to>.
* 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 <num> 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;
}
}
}

128
libv4lconvert/sn9c20x.c Normal file
View File

@@ -0,0 +1,128 @@
/*
* Sonix SN9C20X decoder
* Vasily Khoruzhick, (C) 2008-2009
* Algorithm based on Java code written by Jens on microdia google group
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License, version 2.1,
* as published by the Free Software Foundation.
*
* 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 02110-1335 USA
*
* Note this code was originally licensed under the GNU GPL instead of the
* GNU LGPL, its license has been changed by its author.
*/
#include "libv4lconvert-priv.h"
#define DO_SANITY_CHECKS 0
static const int Y_coords_624x[128][2] = {
{ 0, 0}, { 1, 0}, { 2, 0}, { 3, 0}, { 4, 0}, { 5, 0}, { 6, 0}, { 7, 0},
{ 0, 1}, { 1, 1}, { 2, 1}, { 3, 1}, { 4, 1}, { 5, 1}, { 6, 1}, { 7, 1},
{ 0, 2}, { 1, 2}, { 2, 2}, { 3, 2}, { 4, 2}, { 5, 2}, { 6, 2}, { 7, 2},
{ 0, 3}, { 1, 3}, { 2, 3}, { 3, 3}, { 4, 3}, { 5, 3}, { 6, 3}, { 7, 3},
{ 0, 4}, { 1, 4}, { 2, 4}, { 3, 4}, { 4, 4}, { 5, 4}, { 6, 4}, { 7, 4},
{ 0, 5}, { 1, 5}, { 2, 5}, { 3, 5}, { 4, 5}, { 5, 5}, { 6, 5}, { 7, 5},
{ 0, 6}, { 1, 6}, { 2, 6}, { 3, 6}, { 4, 6}, { 5, 6}, { 6, 6}, { 7, 6},
{ 0, 7}, { 1, 7}, { 2, 7}, { 3, 7}, { 4, 7}, { 5, 7}, { 6, 7}, { 7, 7},
{ 8, 0}, { 9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0}, {14, 0}, {15, 0},
{ 8, 1}, { 9, 1}, {10, 1}, {11, 1}, {12, 1}, {13, 1}, {14, 1}, {15, 1},
{ 8, 2}, { 9, 2}, {10, 2}, {11, 2}, {12, 2}, {13, 2}, {14, 2}, {15, 2},
{ 8, 3}, { 9, 3}, {10, 3}, {11, 3}, {12, 3}, {13, 3}, {14, 3}, {15, 3},
{ 8, 4}, { 9, 4}, {10, 4}, {11, 4}, {12, 4}, {13, 4}, {14, 4}, {15, 4},
{ 8, 5}, { 9, 5}, {10, 5}, {11, 5}, {12, 5}, {13, 5}, {14, 5}, {15, 5},
{ 8, 6}, { 9, 6}, {10, 6}, {11, 6}, {12, 6}, {13, 6}, {14, 6}, {15, 6},
{ 8, 7}, { 9, 7}, {10, 7}, {11, 7}, {12, 7}, {13, 7}, {14, 7}, {15, 7}
};
static void do_write_u(const unsigned char *buf, unsigned char *ptr,
int i, int j)
{
*ptr = buf[i + 128 + j];
}
static void do_write_v(const unsigned char *buf, unsigned char *ptr,
int i, int j)
{
*ptr = buf[i + 160 + j];
}
void v4lconvert_sn9c20x_to_yuv420(const unsigned char *raw, unsigned char *i420,
int width, int height, int yvu)
{
int i = 0, x = 0, y = 0, j, relX, relY, x_div2, y_div2;
const unsigned char *buf = raw;
unsigned char *ptr;
int frame_size = width * height;
int frame_size_div2 = frame_size >> 1;
int frame_size_div4 = frame_size >> 2;
int width_div2 = width >> 1;
#if (DO_SANITY_CHECKS == 1)
int height_div2 = height >> 1;
#endif
void (*do_write_uv1)(const unsigned char *buf, unsigned char *ptr, int i,
int j) = NULL;
void (*do_write_uv2)(const unsigned char *buf, unsigned char *ptr, int i,
int j) = NULL;
if (yvu) {
do_write_uv1 = do_write_v;
do_write_uv2 = do_write_u;
} else {
do_write_uv1 = do_write_u;
do_write_uv2 = do_write_v;
}
while (i < (frame_size + frame_size_div2)) {
for (j = 0; j < 128; j++) {
relX = x + Y_coords_624x[j][0];
relY = y + Y_coords_624x[j][1];
#if (DO_SANITY_CHECKS == 1)
if ((relX < width) && (relY < height)) {
#endif
ptr = i420 + relY * width + relX;
*ptr = buf[i + j];
#if (DO_SANITY_CHECKS == 1)
}
#endif
}
x_div2 = x >> 1;
y_div2 = y >> 1;
for (j = 0; j < 32; j++) {
relX = (x_div2) + (j & 0x07);
relY = (y_div2) + (j >> 3);
#if (DO_SANITY_CHECKS == 1)
if ((relX < width_div2) && (relY < height_div2)) {
#endif
ptr = i420 + frame_size +
relY * width_div2 + relX;
do_write_uv1(buf, ptr, i, j);
ptr += frame_size_div4;
do_write_uv2(buf, ptr, i, j);
#if (DO_SANITY_CHECKS == 1)
}
#endif
}
i += 192;
x += 16;
if (x >= width) {
x = 0;
y += 8;
}
}
}

250
libv4lconvert/spca501.c Normal file
View File

@@ -0,0 +1,250 @@
/*
# (C) 2008 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License, version 2.1,
# as published by the Free Software Foundation.
#
# 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 02110-1335 USA
*/
#include <string.h>
#include "libv4lconvert-priv.h"
/* YUYV per line */
void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu)
{
int i, j;
unsigned long *lsrc = (unsigned long *)src;
for (i = 0; i < height; i += 2) {
/* -128 - 127 --> 0 - 255 and copy first line Y */
unsigned long *ldst = (unsigned long *)(dst + i * width);
for (j = 0; j < width; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
/* -128 - 127 --> 0 - 255 and copy 1 line U */
if (yvu)
ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
else
ldst = (unsigned long *)(dst + width * height + i * width / 4);
for (j = 0; j < width/2; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
/* -128 - 127 --> 0 - 255 and copy second line Y */
ldst = (unsigned long *)(dst + i * width + width);
for (j = 0; j < width; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
/* -128 - 127 --> 0 - 255 and copy 1 line V */
if (yvu)
ldst = (unsigned long *)(dst + width * height + i * width / 4);
else
ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
for (j = 0; j < width/2; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
}
}
/* YYUV per line */
void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu)
{
int i, j;
unsigned long *lsrc = (unsigned long *)src;
for (i = 0; i < height; i += 2) {
/* -128 - 127 --> 0 - 255 and copy 2 lines of Y */
unsigned long *ldst = (unsigned long *)(dst + i * width);
for (j = 0; j < width*2; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
/* -128 - 127 --> 0 - 255 and copy 1 line U */
if (yvu)
ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
else
ldst = (unsigned long *)(dst + width * height + i * width / 4);
for (j = 0; j < width/2; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
/* -128 - 127 --> 0 - 255 and copy 1 line V */
if (yvu)
ldst = (unsigned long *)(dst + width * height + i * width / 4);
else
ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
for (j = 0; j < width/2; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
}
}
/* YUVY per line */
void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu)
{
int i, j;
unsigned long *lsrc = (unsigned long *)src;
for (i = 0; i < height; i += 2) {
/* -128 - 127 --> 0 - 255 and copy first line Y */
unsigned long *ldst = (unsigned long *)(dst + i * width);
for (j = 0; j < width; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
/* -128 - 127 --> 0 - 255 and copy 1 line U */
if (yvu)
ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
else
ldst = (unsigned long *)(dst + width * height + i * width / 4);
for (j = 0; j < width/2; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
/* -128 - 127 --> 0 - 255 and copy 1 line V */
if (yvu)
ldst = (unsigned long *)(dst + width * height + i * width / 4);
else
ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
for (j = 0; j < width/2; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
/* -128 - 127 --> 0 - 255 and copy second line Y */
ldst = (unsigned long *)(dst + i * width + width);
for (j = 0; j < width; j += sizeof(long)) {
*ldst = *lsrc++;
*ldst++ ^= 0x8080808080808080ULL;
}
}
}
/* Note this is not a spca specific format, bit it fits in this file in that
it is another funny yuv format */
/* one line of Y then 1 line of VYUY */
void v4lconvert_cit_yyvyuy_to_yuv420(const unsigned char *src,
unsigned char *ydest,
int width, int height, int yvu)
{
int x, y;
unsigned char *udest, *vdest;
if (yvu) {
vdest = ydest + width * height;
udest = vdest + (width * height) / 4;
} else {
udest = ydest + width * height;
vdest = udest + (width * height) / 4;
}
for (y = 0; y < height; y += 2) {
/* copy 1 line of Y */
memcpy(ydest, src, width);
src += width;
ydest += width;
/* Split one line of VYUY */
for (x = 0; x < width; x += 2) {
*vdest++ = *src++;
*ydest++ = *src++;
*udest++ = *src++;
*ydest++ = *src++;
}
}
}
/* Note this is not a spca specific format, but it fits in this file in that
it is another funny yuv format */
/* The konica gspca subdriver using cams send data in blocks of 256 pixels
in YUV420 format. */
void v4lconvert_konica_yuv420_to_yuv420(const unsigned char *src,
unsigned char *ydest,
int width, int height, int yvu)
{
int i, no_blocks;
unsigned char *udest, *vdest;
if (yvu) {
vdest = ydest + width * height;
udest = vdest + (width * height) / 4;
} else {
udest = ydest + width * height;
vdest = udest + (width * height) / 4;
}
no_blocks = width * height / 256;
for (i = 0; i < no_blocks; i++) {
/* copy 256 Y pixels */
memcpy(ydest, src, 256);
src += 256;
ydest += 256;
/* copy 64 U pixels */
memcpy(udest, src, 64);
src += 64;
udest += 64;
/* copy 64 V pixels */
memcpy(vdest, src, 64);
src += 64;
vdest += 64;
}
}
/* And another not a spca specific format, but fitting in this file in that
it is another funny yuv format */
/* Two lines of Y then 1 line of UV */
void v4lconvert_m420_to_yuv420(const unsigned char *src,
unsigned char *ydest,
int width, int height, int yvu)
{
int x, y;
unsigned char *udest, *vdest;
if (yvu) {
vdest = ydest + width * height;
udest = vdest + (width * height) / 4;
} else {
udest = ydest + width * height;
vdest = udest + (width * height) / 4;
}
for (y = 0; y < height; y += 2) {
/* copy 2 lines of Y */
memcpy(ydest, src, 2 * width);
src += 2 * width;
ydest += 2 * width;
/* Split one line of UV */
for (x = 0; x < width; x += 2) {
*udest++ = *src++;
*vdest++ = *src++;
}
}
}

View File

File diff suppressed because it is too large Load Diff

217
libv4lconvert/sq905c.c Normal file
View File

@@ -0,0 +1,217 @@
/*
* sq905c.c
*
* Here is the decompression function for the SQ905C cameras. The functions
* used are adapted from the libgphoto2 functions for the same cameras,
* which was
* Copyright (c) 2005 and 2007 Theodore Kilgore <kilgota@auburn.edu>
* This version for libv4lconvert is
* Copyright (c) 2009 Theodore Kilgore <kilgota@auburn.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License, version 2.1,
* as published by the Free Software Foundation.
*
* 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 02110-1335 USA
*/
#include <stdlib.h>
#include "libv4lconvert-priv.h"
#define CLIP(x) ((x) < 0 ? 0 : ((x) > 0xff) ? 0xff : (x))
static int
sq905c_first_decompress(unsigned char *output, const unsigned char *input,
unsigned int outputsize)
{
unsigned char parity = 0;
unsigned char nibble_to_keep[2];
unsigned char temp1 = 0, temp2 = 0;
unsigned char input_byte;
unsigned char lookup = 0;
unsigned int i = 0;
unsigned int bytes_used = 0;
unsigned int bytes_done = 0;
unsigned int bit_counter = 8;
unsigned int cycles = 0;
int table[9] = { -1, 0, 2, 6, 0x0e, 0x0e, 0x0e, 0x0e, 0xfb};
unsigned char lookup_table[16] = {
0, 2, 6, 0x0e, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4,
0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb
};
unsigned char translator[16] = {
8, 7, 9, 6, 10, 11, 12, 13,
14, 15, 5, 4, 3, 2, 1, 0
};
nibble_to_keep[0] = 0;
nibble_to_keep[1] = 0;
while (bytes_done < outputsize) {
while (parity < 2) {
while (lookup > table[cycles]) {
if (bit_counter == 8) {
input_byte = input[bytes_used];
bytes_used++;
temp1 = input_byte;
bit_counter = 0;
}
input_byte = temp1;
temp2 = (temp2 << 1) & 0xFF;
input_byte = input_byte >> 7;
temp2 = temp2 | input_byte;
temp1 = (temp1 << 1) & 0xFF;
bit_counter++;
cycles++;
if (cycles > 8)
return -1;
lookup = temp2 & 0xff;
}
temp2 = 0;
for (i = 0; i < 17; i++) {
if (i == 16)
return -1;
if (lookup == lookup_table[i]) {
nibble_to_keep[parity] = translator[i];
break;
}
}
cycles = 0;
parity++;
}
output[bytes_done] = (nibble_to_keep[0]<<4)|nibble_to_keep[1];
bytes_done++;
parity = 0;
}
return 0;
}
static int
sq905c_second_decompress(unsigned char *uncomp, unsigned char *in,
int width, int height)
{
int diff = 0;
int tempval = 0;
int i, m;
unsigned char delta_left = 0;
unsigned char delta_right = 0;
int input_counter = 0;
int delta_table[] = {
-144, -110, -77, -53, -35, -21, -11, -3,
2, 10, 20, 34, 52, 76, 110, 144
};
unsigned char *templine_red;
unsigned char *templine_green;
unsigned char *templine_blue;
templine_red = malloc(width);
if (!templine_red) {
return -1;
}
for (i = 0; i < width; i++)
templine_red[i] = 0x80;
templine_green = malloc(width);
if (!templine_green) {
free(templine_red);
return -1;
}
for (i = 0; i < width; i++)
templine_green[i] = 0x80;
templine_blue = malloc(width);
if (!templine_blue) {
free(templine_red);
free(templine_green);
return -1;
}
for (i = 0; i < width; i++)
templine_blue[i] = 0x80;
for (m = 0; m < height / 2; m++) {
/* First we do an even-numbered line */
for (i = 0; i < width / 2; i++) {
delta_right = in[input_counter] & 0x0f;
delta_left = (in[input_counter] >> 4) & 0xff;
input_counter++;
/* left pixel (red) */
diff = delta_table[delta_left];
if (!i)
tempval = templine_red[0] + diff;
else
tempval = (templine_red[i] +
uncomp[2 * m * width + 2 * i - 2]) / 2 + diff;
tempval = CLIP(tempval);
uncomp[2 * m * width + 2 * i] = tempval;
templine_red[i] = tempval;
/* right pixel (green) */
diff = delta_table[delta_right];
if (!i)
tempval = templine_green[1] + diff;
else if (2 * i == width - 2)
tempval = (templine_green[i] +
uncomp[2 * m * width + 2 * i - 1]) / 2 + diff;
else
tempval = (templine_green[i + 1] +
uncomp[2 * m * width + 2 * i - 1]) / 2 + diff;
tempval = CLIP(tempval);
uncomp[2 * m * width + 2 * i + 1] = tempval;
templine_green[i] = tempval;
}
/* then an odd-numbered line */
for (i = 0; i < width/2; i++) {
delta_right = in[input_counter] & 0x0f;
delta_left = (in[input_counter] >> 4) & 0xff;
input_counter++;
/* left pixel (green) */
diff = delta_table[delta_left];
if (!i)
tempval = templine_green[0] + diff;
else
tempval = (templine_green[i] +
uncomp[(2 * m + 1) * width + 2 * i - 2]) / 2 + diff;
tempval = CLIP(tempval);
uncomp[(2*m+1)*width+2*i] = tempval;
templine_green[i] = tempval;
/* right pixel (blue) */
diff = delta_table[delta_right];
if (!i)
tempval = templine_blue[0] + diff;
else
tempval = (templine_blue[i] +
uncomp[(2 * m + 1) * width + 2 * i - 1]) / 2 + diff;
tempval = CLIP(tempval);
uncomp[(2 * m + 1) * width + 2 * i + 1] = tempval;
templine_blue[i] = tempval;
}
}
free(templine_green);
free(templine_red);
free(templine_blue);
return 0;
}
void v4lconvert_decode_sq905c(const unsigned char *src, unsigned char *dst,
int width, int height)
{
int size;
unsigned char *temp_data;
const unsigned char *raw;
/* here we get rid of the 0x50 bytes of header in src. */
raw = src + 0x50;
size = width * height / 2;
temp_data = malloc(size);
if (!temp_data)
goto out;
sq905c_first_decompress(temp_data, raw, size);
sq905c_second_decompress(dst, temp_data, width, height);
out:
free(temp_data);
}

40
libv4lconvert/stv0680.c Normal file
View File

@@ -0,0 +1,40 @@
/*
* stv0680.c
*
* Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License, version 2.1,
* as published by the Free Software Foundation.
*
* 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 02110-1335 USA
*/
#include "libv4lconvert-priv.h"
/* The stv0640 first sends all the red/green pixels for a line (so 1/2 width)
and then all the green/blue pixels in that line, shuffle this to a regular
RGGB bayer pattern. */
void v4lconvert_decode_stv0680(const unsigned char *src, unsigned char *dst,
int width, int height)
{
int x, y;
const unsigned char *src1 = src;
const unsigned char *src2 = src + width / 2;
for (y = 0; y < height; y++) {
for (x = 0; x < width / 2; x++) {
*dst++ = *src1++;
*dst++ = *src2++;
}
src1 += width / 2;
src2 += width / 2;
}
}

View File

@@ -0,0 +1,127 @@
/*
* Small jpeg decoder library (Internal header)
*
* Copyright (c) 2006, Luc Saillard <luc@saillard.org>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __TINYJPEG_INTERNAL_H_
#define __TINYJPEG_INTERNAL_H_
#include <setjmp.h>
#define SANITY_CHECK 1
struct jdec_private;
#define HUFFMAN_HASH_NBITS 9
#define HUFFMAN_HASH_SIZE (1UL<<HUFFMAN_HASH_NBITS)
#define HUFFMAN_HASH_MASK (HUFFMAN_HASH_SIZE-1)
#define HUFFMAN_TABLES 4
#define COMPONENTS 3
#define JPEG_MAX_WIDTH 2048
#define JPEG_MAX_HEIGHT 2048
struct huffman_table {
/* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol,
* if the symbol is <0, then we need to look into the tree table */
short int lookup[HUFFMAN_HASH_SIZE];
/* code size: give the number of bits of a symbol is encoded */
unsigned char code_size[HUFFMAN_HASH_SIZE];
/* some place to store value that is not encoded in the lookup table
* IMPROVEME: Calculate if 256 value is enough to store all values
*/
uint16_t slowtable[16 - HUFFMAN_HASH_NBITS][256];
};
struct component {
unsigned int Hfactor;
unsigned int Vfactor;
float *Q_table; /* Pointer to the quantisation table to use */
struct huffman_table *AC_table;
struct huffman_table *DC_table;
short int previous_DC; /* Previous DC coefficient */
short int DCT[64]; /* DCT coef */
#if SANITY_CHECK
unsigned int cid;
#endif
};
typedef void (*decode_MCU_fct) (struct jdec_private *priv);
typedef void (*convert_colorspace_fct) (struct jdec_private *priv);
struct jdec_private {
/* Public variables */
uint8_t *components[COMPONENTS];
unsigned int width, height; /* Size of the image */
unsigned int flags;
/* Private variables */
const unsigned char *stream_end;
const unsigned char *stream; /* Pointer to the current stream */
unsigned char *stream_filtered;
int stream_filtered_bufsize;
unsigned int reservoir, nbits_in_reservoir;
struct component component_infos[COMPONENTS];
float Q_tables[COMPONENTS][64]; /* quantization tables */
struct huffman_table HTDC[HUFFMAN_TABLES]; /* DC huffman tables */
struct huffman_table HTAC[HUFFMAN_TABLES]; /* AC huffman tables */
int default_huffman_table_initialized;
int restart_interval;
int restarts_to_go; /* MCUs left in this restart interval */
int last_rst_marker_seen; /* Rst marker is incremented each time */
#if SANITY_CHECK
unsigned int current_cid; /* For planar JPEG */
#endif
unsigned char marker; /* for PJPG (Pixart JPEG) */
unsigned char first_marker; /* for PJPG (Pixart JPEG) */
/* Temp space used after the IDCT to store each components */
uint8_t Y[64 * 4], Cr[64], Cb[64];
jmp_buf jump_state;
/* Internal Pointer use for colorspace conversion, do not modify it !!! */
uint8_t *plane[COMPONENTS];
char error_string[256];
/* Temp buffers for multipass planar JPG -> RGB decoding */
unsigned int tmp_buf_y_size;
uint8_t *tmp_buf[COMPONENTS];
};
#define IDCT tinyjpeg_idct_float
void tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride);
#endif

2670
libv4lconvert/tinyjpeg.c Normal file
View File

File diff suppressed because it is too large Load Diff

76
libv4lconvert/tinyjpeg.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Small jpeg decoder library (header file)
*
* Copyright (c) 2006, Luc Saillard <luc@saillard.org>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __JPEGDEC_H__
#define __JPEGDEC_H__
#ifdef __cplusplus
extern "C" {
#endif
struct jdec_private;
/* Flags that can be set by any applications */
#define TINYJPEG_FLAGS_MJPEG_TABLE (1<<1)
#define TINYJPEG_FLAGS_PIXART_JPEG (1<<2)
#define TINYJPEG_FLAGS_PLANAR_JPEG (1<<3)
/* Format accepted in outout */
enum tinyjpeg_fmt {
TINYJPEG_FMT_GREY = 1,
TINYJPEG_FMT_BGR24,
TINYJPEG_FMT_RGB24,
TINYJPEG_FMT_YUV420P,
};
struct jdec_private *tinyjpeg_init(void);
void tinyjpeg_free(struct jdec_private *priv);
int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size);
int tinyjpeg_decode(struct jdec_private *priv, int pixel_format);
const char *tinyjpeg_get_errorstring(struct jdec_private *priv);
void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height);
int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components);
int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components,
unsigned int ncomponents);
int tinyjpeg_set_flags(struct jdec_private *priv, int flags);
#ifdef __cplusplus
}
#endif
#endif