mirror of
git://nv-tegra.nvidia.com/tegra/v4l2-src/v4l2_libs.git
synced 2025-12-22 09:21:28 +03:00
Updating prebuilts and/or headers
22fd03618c218ae14ba59a5aab5f30b0acd2b6ea - 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 752cb342c44989a8c172e3280e220a6fa2ec86b5 - libv4l2/Makefile ffecae84262f548deac1da0fa51f1aba6b6f96a0 - libv4l2/Makefile.dGPU 766aaca553b0166eb736557e44ad42b69464aa53 - libv4l2/libv4l2.export e6516370c43e4869e05a540d2e4ef584ac64890a - libv4l2/v4l2-plugin.c 8e335567bf404eeb3d180dd384309f687f2ab944 - libv4l2/Makefile.am d1f2b6f016cfb90c616d848418feb915e3737fa7 - libv4l2/libv4l2.c 7fa618184ff89737d13164be0b79e227d81f398c - libv4l2/log.c cbcee4426c19c168c6f49d04af3a0b2e30c0b681 - libv4l2/libv4l2.pc.in 9d456d1772885d900865a8958c0291e13d509de5 - libv4l2/v4l2convert.c Change-Id: Ib9c2be8c51af3ac26ffd9f230946bf7bff65a02b
This commit is contained in:
67
libv4lconvert/Makefile
Normal file
67
libv4lconvert/Makefile
Normal file
@@ -0,0 +1,67 @@
|
||||
###############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
SO_NAME := libnvv4lconvert.so
|
||||
DEST_DIR ?= /usr/lib/aarch64-linux-gnu/tegra
|
||||
|
||||
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/tegra
|
||||
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 tegra/$(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
31
libv4lconvert/Makefile.am
Normal 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
|
||||
41
libv4lconvert/Makefile.dGPU
Normal file
41
libv4lconvert/Makefile.dGPU
Normal 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
632
libv4lconvert/bayer.c
Normal 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);
|
||||
}
|
||||
79
libv4lconvert/control/libv4lcontrol-priv.h
Normal file
79
libv4lconvert/control/libv4lcontrol-priv.h
Normal 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
|
||||
1120
libv4lconvert/control/libv4lcontrol.c
Normal file
1120
libv4lconvert/control/libv4lcontrol.c
Normal file
File diff suppressed because it is too large
Load Diff
78
libv4lconvert/control/libv4lcontrol.h
Normal file
78
libv4lconvert/control/libv4lcontrol.h
Normal 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
213
libv4lconvert/cpia1.c
Normal 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
287
libv4lconvert/crop.c
Normal 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
266
libv4lconvert/flip.c
Normal 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);
|
||||
}
|
||||
79
libv4lconvert/helper-funcs.h
Normal file
79
libv4lconvert/helper-funcs.h
Normal 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
219
libv4lconvert/helper.c
Normal 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
158
libv4lconvert/hm12.c
Normal 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
284
libv4lconvert/jidctflt.c
Normal 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
219
libv4lconvert/jl2005bcd.c
Normal 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
428
libv4lconvert/jpeg.c
Normal 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
|
||||
313
libv4lconvert/jpeg_memsrcdest.c
Normal file
313
libv4lconvert/jpeg_memsrcdest.c
Normal 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 */
|
||||
13
libv4lconvert/jpeg_memsrcdest.h
Normal file
13
libv4lconvert/jpeg_memsrcdest.h
Normal 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
727
libv4lconvert/jpgl.c
Normal 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,&) ) {
|
||||
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
|
||||
*/
|
||||
283
libv4lconvert/libv4lconvert-priv.h
Normal file
283
libv4lconvert/libv4lconvert-priv.h
Normal 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
|
||||
1701
libv4lconvert/libv4lconvert.c
Normal file
1701
libv4lconvert/libv4lconvert.c
Normal file
File diff suppressed because it is too large
Load Diff
23
libv4lconvert/libv4lconvert.export
Normal file
23
libv4lconvert/libv4lconvert.export
Normal 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
|
||||
11
libv4lconvert/libv4lconvert.pc.in
Normal file
11
libv4lconvert/libv4lconvert.pc.in
Normal 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}
|
||||
129
libv4lconvert/libv4lsyscall-priv.h
Normal file
129
libv4lconvert/libv4lsyscall-priv.h
Normal 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
208
libv4lconvert/mr97310a.c
Normal 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;
|
||||
}
|
||||
666
libv4lconvert/ov511-decomp.c
Normal file
666
libv4lconvert/ov511-decomp.c
Normal 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
1480
libv4lconvert/ov518-decomp.c
Normal file
File diff suppressed because it is too large
Load Diff
436
libv4lconvert/pac207.c
Normal file
436
libv4lconvert/pac207.c
Normal 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
|
||||
*/
|
||||
217
libv4lconvert/processing/autogain.c
Normal file
217
libv4lconvert/processing/autogain.c
Normal 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
|
||||
};
|
||||
61
libv4lconvert/processing/gamma.c
Normal file
61
libv4lconvert/processing/gamma.c
Normal 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
|
||||
};
|
||||
67
libv4lconvert/processing/libv4lprocessing-priv.h
Normal file
67
libv4lconvert/processing/libv4lprocessing-priv.h
Normal 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
|
||||
187
libv4lconvert/processing/libv4lprocessing.c
Normal file
187
libv4lconvert/processing/libv4lprocessing.c
Normal 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;
|
||||
}
|
||||
42
libv4lconvert/processing/libv4lprocessing.h
Normal file
42
libv4lconvert/processing/libv4lprocessing.h
Normal 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
|
||||
209
libv4lconvert/processing/whitebalance.c
Normal file
209
libv4lconvert/processing/whitebalance.c
Normal 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
756
libv4lconvert/rgbyuv.c
Normal 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
164
libv4lconvert/se401.c
Normal 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
273
libv4lconvert/sn9c10x.c
Normal 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-----
|
||||
*/
|
||||
154
libv4lconvert/sn9c2028-decomp.c
Normal file
154
libv4lconvert/sn9c2028-decomp.c
Normal 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
128
libv4lconvert/sn9c20x.c
Normal 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
250
libv4lconvert/spca501.c
Normal 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
1006
libv4lconvert/spca561-decompress.c
Normal file
1006
libv4lconvert/spca561-decompress.c
Normal file
File diff suppressed because it is too large
Load Diff
217
libv4lconvert/sq905c.c
Normal file
217
libv4lconvert/sq905c.c
Normal 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
40
libv4lconvert/stv0680.c
Normal 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;
|
||||
}
|
||||
}
|
||||
127
libv4lconvert/tinyjpeg-internal.h
Normal file
127
libv4lconvert/tinyjpeg-internal.h
Normal 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
2670
libv4lconvert/tinyjpeg.c
Normal file
File diff suppressed because it is too large
Load Diff
76
libv4lconvert/tinyjpeg.h
Normal file
76
libv4lconvert/tinyjpeg.h
Normal 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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user