Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:derselbst
ARToolKit_v4l
artk-v4l2-2.72.1.20101003.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File artk-v4l2-2.72.1.20101003.patch of Package ARToolKit_v4l
Index: ARToolKit/Configure =================================================================== --- ARToolKit.orig/Configure +++ ARToolKit/Configure @@ -7,7 +7,8 @@ MDIR=". \ lib/SRC \ lib/SRC/AR lib/SRC/ARMulti lib/SRC/Gl \ lib/SRC/VideoLinux1394Cam lib/SRC/VideoLinuxDV \ - lib/SRC/VideoLinuxV4L lib/SRC/VideoSGI \ + lib/SRC/VideoLinuxV4L lib/SRC/VideoLinuxV4L2 \ + lib/SRC/VideoSGI \ lib/SRC/VideoMacOSX \ lib/SRC/VideoGStreamer \ lib/SRC/ARvrml \ @@ -25,7 +26,8 @@ MDIR=". \ SED=/tmp/SED.$$ trap "rm -f $SED; exit 0" 0 1 2 3 15 - +ARCH="x86" +echo "Assuming x86 architecture (by patch of 2010/10/03)" E=`uname` if [ "$E" = "Linux" ] @@ -33,9 +35,10 @@ then echo "Select a video capture driver." echo " 1: Video4Linux" echo " 2: Video4Linux+JPEG Decompression (EyeToy)" - echo " 3: Digital Video Camcoder through IEEE 1394 (DV Format)" - echo " 4: Digital Video Camera through IEEE 1394 (VGA NONCOMPRESSED Image Format)" - echo " 5: GStreamer Media Framework" + echo " 3: Video4Linux2" + echo " 4: Digital Video Camcoder through IEEE 1394 (DV Format)" + echo " 5: Digital Video Camera through IEEE 1394 (VGA NONCOMPRESSED Image Format)" + echo " 6: GStreamer Media Framework" echo -n "Enter : " read ANS if [ "$ANS" = "1" ] @@ -86,6 +89,29 @@ then CONFIG="AR_INPUT_V4L" elif [ "$ANS" = "3" ] then + echo + echo "Color conversion should use x86 assembly (not working for 64bit)?" + echo -n "Enter : " + read ANS + if [ "$ANS" = "y" ] + then + CCVT_OBJ="ccvt_i386.o" + elif [ "$ANS" = "n" ] + then + CCVT_OBJ="ccvt_c.o" + else + echo "Please enter y or n." + exit 0 + fi + VIDEO_DRIVER="VideoLinuxV4L2" + CFLAG="$RPM_OPT_FLAGS" + LDFLAG="-L/usr/X11R6/lib" + ARFLAG="rs" + RANLIB="" + LIBS="-lglut `pkg-config glu x11 xi xmu libv4l2 --libs` -lm" + CONFIG="AR_INPUT_V4L2" + elif [ "$ANS" = "4" ] + then VIDEO_DRIVER="VideoLinuxDV" CFLAG="-O -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/X11R6/include" LDFLAG="-L/usr/X11R6/lib -L/usr/local/lib" @@ -93,7 +119,7 @@ then RANLIB="" LIBS="-lraw1394 -ldv -lpthread -lglut `pkg-config glu x11 xi xmu --libs`" CONFIG="AR_INPUT_DV" - elif [ "$ANS" = "4" ] + elif [ "$ANS" = "5" ] then VIDEO_DRIVER="VideoLinux1394Cam" CFLAG="-O -I/usr/X11R6/include" @@ -102,7 +128,7 @@ then RANLIB="" LIBS="-lglut `pkg-config glu x11 xi xmu --libs` -lraw1394 -ldc1394_control" CONFIG="AR_INPUT_1394CAM" - elif [ "$ANS" = "5" ] + elif [ "$ANS" = "6" ] then VIDEO_DRIVER="VideoGStreamer" CFLAG="$RPM_OPT_FLAGS `pkg-config --cflags gstreamer-0.10`" Index: ARToolKit/include/AR/config.h.in =================================================================== --- ARToolKit.orig/include/AR/config.h.in +++ ARToolKit/include/AR/config.h.in @@ -61,8 +61,9 @@ /*--------------------------------------------------------------*/ /* */ -/* For Linux, you should define one of below 4 input method */ +/* For Linux, you should define one of below 5 input method */ /* AR_INPUT_V4L: use of standard Video4Linux Library */ +/* AR_INPUT_V4L2: use of standard Video4Linux2 Library */ /* AR_INPUT_GSTREAMER: use of GStreamer Media Framework */ /* AR_INPUT_DV: use of DV Camera */ /* AR_INPUT_1394CAM: use of 1394 Digital Camera */ @@ -70,6 +71,7 @@ /*--------------------------------------------------------------*/ #ifdef __linux #undef AR_INPUT_V4L +#undef AR_INPUT_V4L2 #undef AR_INPUT_DV #undef AR_INPUT_1394CAM #undef AR_INPUT_GSTREAMER @@ -82,6 +84,14 @@ # endif # endif +# ifdef AR_INPUT_V4L2 +# ifdef USE_EYETOY +# define AR_DEFAULT_PIXEL_FORMAT AR_PIXEL_FORMAT_RGB +# else +# define AR_DEFAULT_PIXEL_FORMAT AR_PIXEL_FORMAT_BGR +# endif +# endif + # ifdef AR_INPUT_DV # define AR_DEFAULT_PIXEL_FORMAT AR_PIXEL_FORMAT_RGB # endif @@ -156,6 +166,17 @@ # define VIDEO_MODE_PAL 0 # define VIDEO_MODE_NTSC 1 # define VIDEO_MODE_SECAM 2 +# define DEFAULT_VIDEO_DEVICE "/dev/video0" +# define DEFAULT_VIDEO_WIDTH 640 +# define DEFAULT_VIDEO_HEIGHT 480 +# define DEFAULT_VIDEO_CHANNEL 1 +# define DEFAULT_VIDEO_MODE VIDEO_MODE_NTSC +# endif + +# ifdef AR_INPUT_V4L2 +# define VIDEO_MODE_PAL 0 +# define VIDEO_MODE_NTSC 1 +# define VIDEO_MODE_SECAM 2 # define DEFAULT_VIDEO_DEVICE "/dev/video0" # define DEFAULT_VIDEO_WIDTH 640 # define DEFAULT_VIDEO_HEIGHT 480 Index: ARToolKit/include/AR/sys/videoLinuxV4L2.h =================================================================== --- /dev/null +++ ARToolKit/include/AR/sys/videoLinuxV4L2.h @@ -0,0 +1,67 @@ +/******************************************************* + * + * Author: Hirokazu Kato + * + * kato@sys.im.hiroshima-cu.ac.jp + * + * Revision: 4.5 + * Date: 2002/01/01 + * + * 2004/11/17 Grasset adding new parameters for better controls of + * V4L driver + * 2004/11/17 Grasset adding patch done by XXX for supporting YUV 4:2:0 + * (adding #define and videoBuffer encoding parameters) + * 2006/10/04 S.Goodall: Modified for V4L2 data. + +*******************************************************/ +#ifndef AR_VIDEO_LINUX_V4L2_H +#define AR_VIDEO_LINUX_V4L2_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <linux/types.h> +#include <linux/videodev2.h> + +#include <AR/config.h> +#include <AR/ar.h> + +struct buffer { + void * start; + size_t length; +}; + +typedef struct { + //device controls + char dev[256]; + int channel; + int width; + int height; + int palette; + //image controls + int brightness; + int contrast; + int saturation; + int hue; + int gamma; + int exposure; + int gain; + + //options controls + int mode; + + int debug; + + int fd; + int video_cont_num; + ARUint8 *map; + ARUint8 *videoBuffer; + int n_buffers; + struct buffer *buffers; +} AR2VideoParamT; + +#ifdef __cplusplus +} +#endif +#endif Index: ARToolKit/include/AR/video.h =================================================================== --- ARToolKit.orig/include/AR/video.h +++ ARToolKit/include/AR/video.h @@ -101,6 +101,9 @@ extern "C" { # ifdef AR_INPUT_V4L # include <AR/sys/videoLinuxV4L.h> # endif +# ifdef AR_INPUT_V4L2 +# include <AR/sys/videoLinuxV4L2.h> +# endif # ifdef AR_INPUT_DV # include <AR/sys/videoLinuxDV.h> # endif Index: ARToolKit/lib/SRC/Makefile.in =================================================================== --- ARToolKit.orig/lib/SRC/Makefile.in +++ ARToolKit/lib/SRC/Makefile.in @@ -12,6 +12,7 @@ clean: (cd Gl; make -f Makefile clean) (cd VideoSGI; make -f Makefile clean) (cd VideoLinuxV4L; make -f Makefile clean) + (cd VideoLinuxV4L2; make -f Makefile clean) (cd VideoLinuxDV; make -f Makefile clean) (cd VideoLinux1394Cam; make -f Makefile clean) (cd VideoMacOSX; make -f Makefile clean) @@ -24,6 +25,7 @@ allclean: (cd Gl; make -f Makefile allclean) (cd VideoSGI; make -f Makefile allclean) (cd VideoLinuxV4L; make -f Makefile allclean) + (cd VideoLinuxV4L2; make -f Makefile allclean) (cd VideoLinuxDV; make -f Makefile allclean) (cd VideoLinux1394Cam; make -f Makefile allclean) (cd VideoMacOSX; make -f Makefile allclean) Index: ARToolKit/lib/SRC/VideoLinuxV4L2/Makefile.in =================================================================== --- /dev/null +++ ARToolKit/lib/SRC/VideoLinuxV4L2/Makefile.in @@ -0,0 +1,45 @@ +# +# For instalation. Change this to your settings. +# +INC_DIR = ../../../include +LIB_DIR = ../.. +# +# compiler +# +CC= cc +CFLAG= @CFLAG@ -I$(INC_DIR) -fPIC +# +# products +# +LIBNAME = libARvideo.so +MAJOR = 2 +MINOR = 72.1 +LIB= ${LIB_DIR}/${LIBNAME}.${MAJOR}.${MINOR} +INCLUDE= ${INC_DIR}/AR/video.h +# +# compilation control +# +# LIBOBJS= ${LIB}(video.o) ${LIB}(ccvt_i386.o) +LIBOBJS= @CCVT_OBJ@ ccvt_misc.o video.o + + +all: ${LIB} + +${LIBOBJS}: ${INCLUDE} + +ccvt_c.o video.o ccvt_misc.o: %.o: %.c + ${CC} -c ${CFLAG} $< + +ccvt_i386.o: %.o: %.S + ${CC} -c ${CFLAG} -I/usr/src/linux/include/ -I/usr/src/linux/arch/x86/include/ $< + +${LIB}: ${LIBOBJS} + ${CC} $^ -o $@ -shared -Wl,-soname,${LIBNAME}.${MAJOR} + ln -s ${LIBNAME}.${MAJOR}.${MINOR} ${LIB_DIR}/${LIBNAME}.${MAJOR} + ln -s ${LIBNAME}.${MAJOR} ${LIB_DIR}/${LIBNAME} + +clean: + rm -f *.o ${LIB_DIR}/${LIBNAME}* + +allclean: clean + rm -f Makefile Index: ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt.h =================================================================== --- /dev/null +++ ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt.h @@ -0,0 +1,117 @@ +/* CCVT: ColourConVerT: simple library for converting colourspaces + Copyright (C) 2002 Nemosoft Unv. + + 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 + + For questions, remarks, patches, etc. for this program, the author can be + reached at nemosoft@smcc.demon.nl. +*/ + +/* + $Log: ccvt.h,v $ + Revision 1.2 2006/12/06 00:37:23 retrakker + - Added an updated CCVT version which hopefully will work as expected on + x64 systems. + + Revision 1.1 2005/05/04 06:53:17 section314 + Added YUV420P-->RGB conversion + + Revision 1.10 2003/10/24 16:55:18 nemosoft + removed erronous log messages + + Revision 1.9 2002/11/03 22:46:25 nemosoft + Adding various RGB to RGB functions. + Adding proper copyright header too. + + Revision 1.8 2002/04/14 01:00:27 nemosoft + Finishing touches: adding const, adding libs for 'show' +*/ + + +#ifndef CCVT_H +#define CCVT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Colour ConVerT: going from one colour space to another. + ** NOTE: the set of available functions is far from complete! ** + + Format descriptions: + 420i = "4:2:0 interlaced" + YYYY UU YYYY UU even lines + YYYY VV YYYY VV odd lines + U/V data is subsampled by 2 both in horizontal + and vertical directions, and intermixed with the Y values. + + 420p = "4:2:0 planar" + YYYYYYYY N lines + UUUU N/2 lines + VVVV N/2 lines + U/V is again subsampled, but all the Ys, Us and Vs are placed + together in separate buffers. The buffers may be placed in + one piece of contiguous memory though, with Y buffer first, + followed by U, followed by V. + + yuyv = "4:2:2 interlaced" + YUYV YUYV YUYV ... N lines + The U/V data is subsampled by 2 in horizontal direction only. + + bgr24 = 3 bytes per pixel, in the order Blue Green Red (whoever came up + with that idea...) + rgb24 = 3 bytes per pixel, in the order Red Green Blue (which is sensible) + rgb32 = 4 bytes per pixel, in the order Red Green Blue Alpha, with + Alpha really being a filler byte (0) + bgr32 = last but not least, 4 bytes per pixel, in the order Blue Green Red + Alpha, Alpha again a filler byte (0) + */ + +/* 4:2:0 YUV planar to RGB/BGR */ +void ccvt_420p_bgr24(int width, int height, const void *src, void *dst); +void ccvt_420p_rgb24(int width, int height, const void *src, void *dst); +void ccvt_420p_bgr32(int width, int height, const void *src, void *dst); +void ccvt_420p_rgb32(int width, int height, const void *src, void *dst); + +/* 4:2:2 YUYV interlaced to RGB/BGR */ +void ccvt_yuyv_rgb32(int width, int height, const void *src, void *dst); +void ccvt_yuyv_rgb24(int width, int height, const void *src, void *dst); +void ccvt_yuyv_bgr32(int width, int height, const void *src, void *dst); + +/* 4:2:2 YUYV interlaced to 4:2:0 YUV planar */ +void ccvt_yuyv_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); + +/* RGB/BGR to 4:2:0 YUV interlaced */ + +/* RGB/BGR to 4:2:0 YUV planar */ +void ccvt_rgb24_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); +void ccvt_bgr24_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); + +/* RGB/BGR to RGB/BGR */ +void ccvt_bgr24_bgr32(int width, int height, const void *const src, void *const dst); +void ccvt_bgr24_rgb32(int width, int height, const void *const src, void *const dst); +void ccvt_bgr32_bgr24(int width, int height, const void *const src, void *const dst); +void ccvt_bgr32_rgb24(int width, int height, const void *const src, void *const dst); +void ccvt_rgb24_bgr32(int width, int height, const void *const src, void *const dst); +void ccvt_rgb24_rgb32(int width, int height, const void *const src, void *const dst); +void ccvt_rgb32_bgr24(int width, int height, const void *const src, void *const dst); +void ccvt_rgb32_rgb24(int width, int height, const void *const src, void *const dst); + + +#ifdef __cplusplus +} +#endif + +#endif Index: ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt_c.c =================================================================== --- /dev/null +++ ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt_c.c @@ -0,0 +1,132 @@ +/* CCVT: ColourConVerT: simple library for converting colourspaces + Copyright (C) 2002 Nemosoft Unv. + + 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 + + For questions, remarks, patches, etc. for this program, the author can be + reached at nemosoft@smcc.demon.nl. +*/ + +#include "ccvt.h" + +#define PUSH_RGB24 1 +#define PUSH_BGR24 2 +#define PUSH_RGB32 3 +#define PUSH_BGR32 4 + + +/* This is a simplistic approach. */ +static void ccvt_420p(int width, int height, const unsigned char *src, unsigned char *dst, int push) +{ + int line, col, linewidth; + int y, u, v, yy, vr, ug, vg, ub; + int r, g, b; + const unsigned char *py, *pu, *pv; + + linewidth = width >> 1; + py = src; + pu = py + (width * height); + pv = pu + (width * height) / 4; + + y = *py++; + yy = y << 8; + u = *pu - 128; + ug = 88 * u; + ub = 454 * u; + v = *pv - 128; + vg = 183 * v; + vr = 359 * v; + + for (line = 0; line < height; line++) { + for (col = 0; col < width; col++) { + r = (yy + vr) >> 8; + g = (yy - ug - vg) >> 8; + b = (yy + ub ) >> 8; + + if (r < 0) r = 0; + if (r > 255) r = 255; + if (g < 0) g = 0; + if (g > 255) g = 255; + if (b < 0) b = 0; + if (b > 255) b = 255; + + switch(push) { + case PUSH_RGB24: + *dst++ = r; + *dst++ = g; + *dst++ = b; + break; + + case PUSH_BGR24: + *dst++ = b; + *dst++ = g; + *dst++ = r; + break; + + case PUSH_RGB32: + *dst++ = r; + *dst++ = g; + *dst++ = b; + *dst++ = 0; + break; + + case PUSH_BGR32: + *dst++ = b; + *dst++ = g; + *dst++ = r; + *dst++ = 0; + break; + } + + y = *py++; + yy = y << 8; + if (col & 1) { + pu++; + pv++; + + u = *pu - 128; + ug = 88 * u; + ub = 454 * u; + v = *pv - 128; + vg = 183 * v; + vr = 359 * v; + } + } /* ..for col */ + if ((line & 1) == 0) { // even line: rewind + pu -= linewidth; + pv -= linewidth; + } + } /* ..for line */ +} + +void ccvt_420p_rgb24(int width, int height, const void *src, void *dst) +{ + ccvt_420p(width, height, (const unsigned char *)src, (unsigned char *)dst, PUSH_RGB24); +} + +void ccvt_420p_bgr24(int width, int height, const void *src, void *dst) +{ + ccvt_420p(width, height, (const unsigned char *)src, (unsigned char *)dst, PUSH_BGR24); +} + +void ccvt_420p_rgb32(int width, int height, const void *src, void *dst) +{ + ccvt_420p(width, height, (const unsigned char *)src, (unsigned char *)dst, PUSH_RGB32); +} + +void ccvt_420p_bgr32(int width, int height, const void *src, void *dst) +{ + ccvt_420p(width, height, (const unsigned char *)src, (unsigned char *)dst, PUSH_BGR32); +} Index: ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt_i386.S =================================================================== --- /dev/null +++ ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt_i386.S @@ -0,0 +1,1255 @@ +/* +Colour conversion routines (RGB <-> YUV) in x86 assembly + +(C) 2000 Nemosoft Unv. nemosoft@smcc.demon.nl + +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; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU 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. + +*/ + + +/* The ccvt_* functions always start with width and height, so these + parameters are in 8(%ebp) and 12 (%ebp). The other parameters can be + 2 to 4 pointers, and one of these combinations: + *src, *dst + *srcy, *srcu, *srv, *dst + *src, *dsty, *dstu, *dstv + */ + +#define __ASSEMBLY__ +#include <linux/linkage.h> + +#define Width 8(%ebp) +#define Height 12(%ebp) + +/* 2 parameters, 1 in, 1 out */ +#define Src2 16(%ebp) +#define Dst2 20(%ebp) + +/* 4 parameters, 3 in, 1 out */ +#define SrcY 16(%ebp) +#define SrcU 20(%ebp) +#define SrcV 24(%ebp) +#define Dst4 28(%ebp) + +/* 4 parameters, 1 in, 3 out */ +#define Src4 16(%ebp) +#define DstY 20(%ebp) +#define DstU 24(%ebp) +#define DstV 28(%ebp) + +/* This buffer space used to be staticly allocted, but this is going to + give problems with multiple cams (though I have yet to see it). + Therefor, we reserve at least 64 + 8 = 72 bytes on the stack with + `enter'. + */ + +#define PixelBuffer -64(%ebp) +#define Uptr -68(%ebp) +#define Vptr -72(%ebp) + + .text + +/* This function will load the src and destination pointers, including + Uptr/Vptr when necessary, and test the width/height parameters. + - %esi will be set to Src or SrcY + - %edi will be set to Dst or DstY + the carry flag will be set if any of these tests fail. + It assumes %ebp has been set. + */ +/* 2 parameters, src & dst */ +test_param_2: + mov Src2, %esi + mov Dst2, %edi + + cmp $0, %esi # NULL pointers? + je param_fail + cmp $0, %edi + je param_fail + + jmp test_width_height + +/* 3 inputs, 1 output */ +test_param_31: + mov Dst4, %edi # NULL pointers + cmp $0, %edi + je param_fail + + mov SrcV, %esi + cmp $0, %esi + je param_fail + mov %esi, Vptr + + mov SrcU, %esi + cmp $0, %esi + je param_fail + mov %esi, Uptr + + mov SrcY, %esi + cmp $0, %esi + je param_fail + + jmp test_width_height + +/* 1 input, 3 output */ +test_param_13: + mov Src4, %esi # NULL pointers + cmp $0, %esi + je param_fail + + mov DstV, %edi + cmp $0, %edi + je param_fail + mov %edi, Vptr + + mov DstU, %edi + cmp $0, %edi + je param_fail + mov %edi, Uptr + + mov DstY, %edi + cmp $0, %edi + je param_fail + + jmp test_width_height + + nop + +test_width_height: + cmpl $0, Width + jbe param_fail + testl $3, Width # multiple of 4? + jnz param_fail # Nope... + + cmp $0, Height # check illegal height + jbe param_fail + testl $1, Height # Odd no. of lines? + jnz param_fail # Aye + + /* fall through */ + +/* exit points */ +param_ok: + clc # Success: clear carry + ret + +param_fail: + stc # Fail: set carry + ret + + + +# This will fill PixelBuffer with 4 grey scale pixels (Y) +# In: %eax = Value (Y3Y2Y1Y0) +# Out: +# Modifies: %ecx (-4) +# Destroys: %edx +expand_4_y: + mov %eax, %edx # Keep in edx (we need eax) + lea PixelBuffer, %edi + +0: # This code is executed 4 times + movzbl %dl, %eax # move, zero extending byte-to-long + shl $8, %eax # 8 digit precision + + stosl # Expand into PixelBuffer + stosl + stosl + add $4, %edi # Skip alpha + + shr $8, %edx # next Y + + dec %ecx + test $3, %ecx + jnz 0b + + ret # from expand_4_y + +# This will add the color factors to the (grey) values in PixelBuffer +# In: %ebx (U1U0V1V0) +# Out: +# Modifies: +# Destroys: %edi, %ebx, %eax, %edx +expand_4_uv: + lea PixelBuffer, %edi # reset pointer + + # V0 + sub $128, %bl + movsbl %bl, %eax + mov $359, %edx # Vr + mul %edx + add %eax, 0x00(%edi) + add %eax, 0x10(%edi) + + movsbl %bl, %eax + mov $183, %edx # Vg + mul %edx + sub %eax, 0x04(%edi) + sub %eax, 0x14(%edi) + + # V1 + sub $128, %bh + movsbl %bh, %eax + mov $359, %edx # Vr + mul %edx + add %eax, 0x20(%edi) + add %eax, 0x30(%edi) + + movsbl %bh, %eax + mov $183, %edx # Vg + mul %edx + sub %eax, 0x24(%edi) + sub %eax, 0x34(%edi) + + # U0 + bswap %ebx # Get U values in lower half + sub $128, %bh + movsbl %bh, %eax + mov $88, %edx # Ug + mul %edx + sub %eax, 0x04(%edi) + sub %eax, 0x14(%edi) + + movsbl %bh, %eax + mov $454, %edx # Ub + mul %edx + add %eax, 0x08(%edi) + add %eax, 0x18(%edi) + + # U1 + sub $128, %bl + movsbl %bl, %eax + mov $88, %edx # Ug + mul %edx + sub %eax, 0x24(%edi) + sub %eax, 0x34(%edi) + + movsbl %bl, %eax + mov $454, %edx # Ub + mul %edx + add %eax, 0x28(%edi) + add %eax, 0x38(%edi) + ret # expand_4_uv + + +/* This function expands 4 420i pixels into PixelBuffer */ +do_four_yuvi: + push %edi + + lodsl # 4 bytes at a time + + call expand_4_y + + # now do UV values. on even lines, Y is followed by U values; on + # odd lines V values follow. The U and V values are always pushed + # on the stack in this order: + # U V + + # First, calculate offset per line (1.5 * width) + mov Width, %ebx # width + shl %ebx # 2 * + add Width, %ebx # 3 * + shr %ebx # 1.5 * + + # even or odd lines + testl $1, Height + jz 2f + + # odd line; we are at V data, but do U data first + neg %ebx # make ebx offset negative + mov (%esi,%ebx),%ax # U + push %ax + lodsw # V + push %ax + jmp 3f + +2: # even line + lodsw # U + push %ax + sub $2, %ebx + mov (%esi,%ebx), %ax # V + push %ax + +3: # Okay, so we now have the U and V values... expand into PixelBuffer + + pop %ebx + call expand_4_uv + + pop %edi + ret # from do_four_yuvi + + +# Do four pixels, in planar format +do_four_yuvp: + push %edi + + # The first part is the same as for interlaced (4 bytes Y) + lodsl # 4 bytes at a time + call expand_4_y + + # now gather U and V values... + mov Uptr, %ebx # Use Uptr/Vptr + mov (%ebx), %ax + push %ax + add $2, %ebx + mov %ebx, Uptr + + mov Vptr, %ebx + mov (%ebx), %ax + push %ax + add $2, %ebx + mov %ebx, Vptr + + pop %ebx + call expand_4_uv + + pop %edi + ret + + +# Do four pixels, in yuyv interlaced format +do_four_yuyv: + push %edi + + lodsl # v0y1u0y0 + mov %eax, %ebx + bswap %ebx # y0u0y1v0 + mov %bh, %ah # v0y1y1y0 + and $0x00ff00ff, %ebx # __u0__v0 + push %ax # y1y0 + + lodsl # v1y3u1y2 # mix register instructions + mov %eax, %edx # so CPU pipeline doesnt stall + rol $16, %eax # u1y2v1y3 + mov %dl, %dh # v1y3y2y2 + and $0xff00ff00, %eax # u1__v1__ + mov $0, %dl # v1y3y2__ + or %eax, %ebx # u1u0v1v0 + shl $8, %edx # y3y2____ + pop %dx # y3y2y1y0 + mov %edx, %eax + call expand_4_y + call expand_4_uv + + pop %edi + ret + +limit_pixels: + # Limit all values in PixelBuffer + push %esi + push %edi + push %ecx + lea PixelBuffer, %esi + mov %esi, %edi + mov $16, %ecx +0: lodsl + cmp $0, %eax # this would have been a perfect spot for CMOVxx instructions... + jl 2f # except they only work on Pentium Pro processors, + cmp $0xff00, %eax # and not even all of them + jg 3f + add $4, %edi # no use for stosl here + loop 0b + jmp 9f +2: mov $0, %eax + stosl + loop 0b + jmp 9f +3: mov $0xff00, %eax + stosl + loop 0b + jmp 9f + +9: pop %ecx + pop %edi + pop %esi + ret # from limit_pixels + +/* Copy RGB values from PixelBuffer into destination buffer, 4 bytes + with alpha + */ + +/* Push 3 pixel (12 bytes), in correct order */ +push_rgb24: + push %ecx + push %esi + lea PixelBuffer, %esi + mov $4, %ecx +0: lodsl + shr $8, %eax + mov %al, (%edi) # Red + lodsl + shr $8, %eax + mov %al, 1(%edi) # Green + lodsl + shr $8, %eax + mov %al, 2(%edi) # Blue + add $3, %edi + lodsl # dummy + loop 0b + pop %esi + pop %ecx + ret + +/* Push 3 pixels (12 bytes), in wrong order */ +push_bgr24: + push %ecx + push %esi + lea PixelBuffer, %esi + mov $4, %ecx +0: lodsl + shr $8, %eax + mov %al, 2(%edi) # Red + lodsl + shr $8, %eax + mov %al, 1(%edi) # Green + lodsl + shr $8, %eax + mov %al, (%edi) # Blue + add $3, %edi + lodsl # dummy + loop 0b + pop %esi + pop %ecx + ret + +/* The simplest format: push 4 bytes, RGBa */ +push_rgb32: + push %ecx + push %esi + mov $16, %ecx + lea PixelBuffer, %esi +0: lodsl # red + shr $8, %eax # 8 bit precision + stosb + loop 0b + pop %esi + pop %ecx + ret + + +/* Gosh. Would you believe it. They even made this format... (Qt 2.*) */ +push_bgr32: + # copy all 4 values to output buffer + push %ecx + push %esi + mov $4, %ecx + lea PixelBuffer, %esi +0: lodsl # red + shr $8, %eax # 8 bit precision + mov %al, 2(%edi) + lodsl # green + shr $8, %eax + mov %al, 1(%edi) + lodsl # blue + shr $8, %eax + mov %al, (%edi) + add $4, %edi + lodsl # dummy + loop 0b + pop %esi + pop %ecx + ret + +/*************************************/ + +/* Functions to go from YUV interlaced formats to RGB */ + +/* Go from interlaced to RGB, red first */ + +ENTRY(ccvt_420i_rgb24) + enter $72, $0 # no extra space, no stackframes + push %ebx + push %esi + push %edi + + call test_param_2 + jc 9f + +0: mov Width, %ecx # width +1: call do_four_yuvi + call limit_pixels + call push_rgb24 + + cmp $0, %ecx + jnz 1b # end of line? + decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + +/* Go from interlaced to BGR, blue first */ + +ENTRY(ccvt_420i_bgr24) + enter $72, $0 # no extra space, no stackframes + push %ebx + push %esi + push %edi + + call test_param_2 + jc 9f + +0: mov Width, %ecx # width +1: call do_four_yuvi + call limit_pixels + call push_bgr24 + + cmp $0, %ecx + jnz 1b # end of line? + decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + + +/* From interlaced to RGBa */ + +ENTRY(ccvt_420i_rgb32) + enter $72, $0 # no extra space, no stackframes + push %ebx + push %esi + push %edi + + call test_param_2 + jc 9f + +0: mov Width, %ecx # width +1: call do_four_yuvi + call limit_pixels + call push_rgb32 + + cmp $0, %ecx # end of line? + jnz 1b + decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + +/* Guess what? Go from interlaced to BGRa */ + +ENTRY(ccvt_420i_bgr32) + enter $72, $0 # no extra space, no stackframes + push %ebx + push %esi + push %edi + + call test_param_2 + jc 9f + +0: mov Width, %ecx # width +1: call do_four_yuvi + call limit_pixels + call push_bgr32 + + cmp $0, %ecx # end of line? + jnz 1b + decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + +/* From YUYV to RGBa */ +ENTRY(ccvt_yuyv_rgb24) + enter $72, $0 # no extra space, no stackframes + push %ebx + push %esi + push %edi + + call test_param_2 + jc 9f + +0: mov Width, %ecx # width +1: call do_four_yuyv + call limit_pixels + call push_rgb24 + + cmp $0, %ecx # end of line? + jnz 1b + +8: decl Height # yes ; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + +ENTRY(ccvt_yuyv_rgb32) + enter $72, $0 # no extra space, no stackframes + push %ebx + push %esi + push %edi + + call test_param_2 + jc 9f + +0: mov Width, %ecx # width +1: call do_four_yuyv + call limit_pixels + call push_rgb32 + + cmp $0, %ecx # end of line? + jnz 1b + +8: decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + +/* From YUYV to BGRa */ +ENTRY(ccvt_yuyv_bgr32) + enter $72, $0 # no extra space, no stackframes + push %ebx + push %esi + push %edi + + call test_param_2 + jc 9f + + # YUYV -> RGBa RGBa + +0: mov Width, %ecx # width +1: call do_four_yuyv + call limit_pixels + call push_bgr32 + + cmp $0, %ecx # end of line? + jnz 1b + +8: decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + + + + +/* Planar to RGBa */ + +ENTRY(ccvt_420p_rgb32) + enter $72, $0 + push %ebx + push %esi + push %edi + + call test_param_31 + jc 9f + + mov Width, %eax # width + mull Height # * height + mov SrcU, %eax # Copy U/V pointers + mov %eax, Uptr + mov SrcV, %eax + mov %eax, Vptr + +0: mov Width, %ecx # width +1: call do_four_yuvp + call limit_pixels + call push_rgb32 + + cmp $0, %ecx # end of line? + jnz 1b + + testl $1, Height # odd/even line + jnz 8f + + mov Width, %eax # Even: rewind U/V pointers + shr %eax + sub %eax, Uptr + sub %eax, Vptr + +8: decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + +/* Okay... eventually, you end up with a very complete set of conversion + routines. I just wished things were a bit simpler. */ + +/* Planar to RGB */ + +ENTRY(ccvt_420p_rgb24) + enter $72, $0 + push %ebx + push %esi + push %edi + + call test_param_31 + jc 9f + + mov Width, %eax # width + mull Height # * height + mov SrcU, %eax # Copy U/V pointers + mov %eax, Uptr + mov SrcV, %eax + mov %eax, Vptr + +0: mov Width, %ecx # width +1: call do_four_yuvp + call limit_pixels + call push_rgb24 + + cmp $0, %ecx # end of line? + jnz 1b + + testl $1, Height # odd/even line + jnz 8f + + mov Width, %eax # Even: rewind U/V pointers + shr %eax + sub %eax, Uptr + sub %eax, Vptr + +8: decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + +/* Planar to RGB */ + +ENTRY(ccvt_420p_bgr24) + enter $72, $0 + push %ebx + push %esi + push %edi + + call test_param_31 + jc 9f + + mov Width, %eax # width + mull Height # * height + mov SrcU, %eax # Copy U/V pointers + mov %eax, Uptr + mov SrcV, %eax + mov %eax, Vptr + +0: mov Width, %ecx # width +1: call do_four_yuvp + call limit_pixels + call push_bgr24 + + cmp $0, %ecx # end of line? + jnz 1b + + testl $1, Height # odd/even line + jnz 8f + + mov Width, %eax # Even: rewind U/V pointers + shr %eax + sub %eax, Uptr + sub %eax, Vptr + +8: decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + +/* Okay... eventually, you end up with a very complete set of conversion + routines. I just wished things were a bit simpler. */ + +ENTRY(ccvt_420p_bgr32) + enter $72, $0 + push %ebx + push %esi + push %edi + + call test_param_31 + jc 9f + + mov Width, %eax # width + mull Height # * height + mov SrcU, %eax # Copy U/V pointers + mov %eax, Uptr + mov SrcV, %eax + mov %eax, Vptr + +0: mov Width, %ecx # width +1: call do_four_yuvp + call limit_pixels + call push_bgr32 + + cmp $0, %ecx # end of line? + jnz 1b + + testl $1, Height # odd/even line + jnz 8f + + mov Width, %eax # Even: rewind U/V pointers + shr %eax + sub %eax, Uptr + sub %eax, Vptr + +8: decl Height # yes; decrement line counter + jnz 0b + +9: pop %edi + pop %esi + pop %ebx + leave + ret + + + + +/* Go from RGB (red first) to 4:2:0 planar. + * Note: this requires decimation of the U/V space by 2 in both directions + * Also, a matrix multiply would be QUITE convenient... + + This is the matrix: + (Y ) ( 77 150 29) (R) + (Cb) = (-43 -85 128) * (G) + (Cr) (128 -107 -21) (B) + */ + +ENTRY(ccvt_rgb24_420p) + enter $96, $0 # 24 bytes extra stack, no stackframes + push %ebx # -76: line width in bytes + push %esi # -80: height (copy) + push %edi # -84: width (copy) + # -88: red factor + # -92: green factor + # -96: blue factor + call test_param_13 + jc 9f + + mov Width, %eax + shl %eax + add Width, %eax # 3 * width = line increment + mov %eax, -76(%ebp) + + mov Height, %eax + mov %eax, -80(%ebp) # copy height into stackframe + + /* + This is a bit complicated... since U/V decimation is taking + place both in horizontal and vertical direction, we have to + process 2 lines in parallel. Also, 2 adjacent pixels are + considered. We average the U/V values over these 4 pixels + (of course, we could have just taken the U/V value of the first + pixel and be done with it, but that's not how we do things around + here) + */ + + # 1st pass: Y values. Set factors + movl $77 , -88(%ebp) # 0.299 + movl $150, -92(%ebp) # 0.587 + movl $29 , -96(%ebp) # 0.114 + +0: mov Width, %ecx # width +1: xor %ebx, %ebx # 0 + call rgb_multiply + shr $8, %ebx # divide by 256 (no need for limitor, since 77 + 150 + 29 = 256) + mov %bl, %al + stosb # store it into Y buffer + + dec %ecx # end of line? + jnz 1b + decl -80(%ebp) # end of image? + jnz 0b + + # Okay, now the U/V pointers... + # The following code is passed twice, with different factors + # Note that the %esi pointer jumps around quite a bit + + # factors for U + movl $-43, -88(%ebp) # -0.1687 + movl $-85, -92(%ebp) # -0.3313 + movl $128, -96(%ebp) # 0.5 + mov DstU, %edi # Set %edi register now + +7: mov Src4, %esi # Rewind source pointer + + mov Height, %eax # height + shr %eax # / 2 + mov %eax, -80(%ebp) # copy + +2: mov Width, %eax # width + shr %eax # / 2 + mov %eax, -84(%ebp) # copy + +3: xor %ebx, %ebx # 0 + mov $4, %ecx # average over 4 pixels + +4: call rgb_multiply + + dec %ecx + jz 5f # done? + cmp $2, %ecx # 3rd pixel.. move %esi to next line, with offset + jne 4b + sub $6, %esi # backup to where we started + add -76(%ebp), %esi # add line increment + jmp 4b + +5: # okay, 4 pixels done... + sub -76(%ebp), %esi # Get %esi back to its proper place + + add $0x20000, %ebx # add 0.5 factor + shr $10, %ebx # Divide by 4 * 256 + mov %bl, %al + stosb # store it! + + decl -84(%ebp) # end of line? + jnz 3b + add -76(%ebp), %esi # %esi to next line (actually, 2 lines further) + decl -80(%ebp) # end of image? + jnz 2b + + # check if 3rd pass has been done + cmpl $128, -88(%ebp) + je 9f # Done! + # Set factors for V pass + movl $128 , -88(%ebp) # 0.5 + movl $-107, -92(%ebp) # -0.4187 + movl $-21 , -96(%ebp) # -0.0813 + mov DstV, %edi # %edi to V buffer + jmp 7b # "Do it to me one more time..." + +9: pop %edi + pop %esi + pop %ebx + leave + ret + + + + +ENTRY(ccvt_bgr24_420p) + enter $96, $0 # 24 bytes extra stack, no stackframes + push %ebx # -4: line width in bytes + push %esi # -8: height (copy) + push %edi # -12: width (copy) + # -16: red factor + # -20: green factor + # -24: blue factor + call test_param_13 + jc 9f + + /* No surprise, this code looks just like rgb24_420p, but with swapped factors */ + + mov Width, %eax + shl %eax + add Width, %eax # 3 * width = line increment + mov %eax, -76(%ebp) + + mov Height, %eax + mov %eax, -80(%ebp) # copy height into stackframe + + # 1st pass: Y values. Set factors + movl $29 , -88(%ebp) # 0.114 + movl $150, -92(%ebp) # 0.587 + movl $77 , -96(%ebp) # 0.299 + +0: mov Width, %ecx # width +1: xor %ebx, %ebx # 0 + call rgb_multiply + shr $8, %ebx # divide by 256 (no need for limitor, since 77 + 150 + 29 = 256) + mov %bl, %al + stosb # store it into Y buffer + + dec %ecx # end of line? + jnz 1b + decl -80(%ebp) # end of image? + jnz 0b + + # Okay, now the U/V pointers... + # The following code is passed twice, with different factors + # Note that the %esi pointer jumps around quite a bit + + # factors for U + movl $123, -88(%ebp) # 0.5 + movl $-85, -92(%ebp) # -0.3313 + movl $-43, -96(%ebp) # -0.1687 + mov DstU, %edi # Set %edi register now + +7: mov Src4, %esi # Rewind source pointer + + mov Height, %eax # height + shr %eax # / 2 + mov %eax, -80(%ebp) # copy + +2: mov Width, %eax # width + shr %eax # / 2 + mov %eax, -84(%ebp) # copy + +3: xor %ebx, %ebx # 0 + mov $4, %ecx # average over 4 pixels + +4: call rgb_multiply + + dec %ecx + jz 5f # done? + cmp $2, %ecx # 3rd pixel.. move %esi to next line, with offset + jne 4b + sub $6, %esi # backup to where we started + add -76(%ebp), %esi # add line increment + jmp 4b + +5: # okay, 4 pixels done... + sub -76(%ebp), %esi # Get %esi back to its proper place + + add $0x20000, %ebx # add 0.5 factor + shr $10, %ebx # Divide by 4 * 256 + mov %bl, %al + stosb # store it! + + decl -84(%ebp) # end of line? + jnz 3b + add -76(%ebp), %esi # %esi to next line (actually, 2 lines further) + decl -80(%ebp) # end of image? + jnz 2b + + # check if 3rd pass has been done + cmpl $-21, -88(%ebp) + je 9f # Done! + # Set factors for V pass + movl $-21 , -88(%ebp) # -0.0813 + movl $-107, -92(%ebp) # -0.4187 + movl $128 , -96(%ebp) # 0.5 + mov DstV, %edi # %edi to V buffer + jmp 7b # "Do it to me one more time..." + +9: pop %edi + pop %esi + pop %ebx + leave + ret + + +/* RGB-to-YUV helper functions */ + +rgb_multiply: + # do one RGB vector multiplication; its assumed the RGB factors + # are set on the stack. The data is accumulated in ebx. + lodsb # red byte + and $0xff, %eax + mov -88(%ebp), %edx # red factor + mul %edx + add %eax, %ebx + lodsb # green byte + and $0xff, %eax + mov -92(%ebp), %edx # green factor + mul %edx + add %eax, %ebx + lodsb # blue byte + and $0xff, %eax + mov -96(%ebp), %edx # blue factor + mul %edx + add %eax, %ebx # ebx now contains sum + ret + + + +/**************************************************************************/ + + +/* Go from 'interlaced' (YYYY UU/VV) format to planar */ + +ENTRY(ccvt_420i_420p) + enter $76, $0 # 4 bytes extra space, no stackframes + push %ebx # -4: width / 4 + push %esi + push %edi + + call test_param_13 + jc 9f + + # Okay, this is fairly easy... we first grab the Y values (4 bytes + # at a time), then rewind and do the U values, and repeat for V. + # This leaves us with a nice planar format + + mov Width, %eax + shr %eax + shr %eax # width / 4 + mov %eax, -76(%ebp) # Store + + # Y + mov Height, %edx # line counter +0: mov -76(%ebp), %ecx +1: lodsl # get 4 bytes... + stosl # ...push 4 bytes + add $2, %esi # Skip U or V + loop 1b + dec %edx + jnz 0b + + # U + mov Src4, %esi # rewind source pointer + mov DstU, %edi + add $4, %esi # set to U + mov Height, %edx + shr %edx # height / 2 + mov Width, %ebx + shl %ebx + add Width, %ebx + shr %ebx # Width * 1.5 (line offset) + +2: mov -76(%ebp), %ecx # width / 4 +3: lodsw # 2 bytes at a time + stosw + add $4, %esi # skip Y + loop 3b + add %ebx, %esi # Skip line (U is on even lines) + dec %edx + jnz 2b + + # V + mov Src4, %esi # rewind, set to V in first odd line + add $4, %esi + add %ebx, %esi # register re-use; no compiler can beat that :) + mov DstV, %edi # V ptr + mov Height, %edx + shr %edx # height / 2 + +4: mov -76(%ebp), %ecx # Get width/4 +5: lodsw + stosw + add $4, %esi # Skip Y + loop 5b + add %ebx, %esi # Skip line (V is on odd lines) + dec %edx + jnz 4b + + /* That's it! */ + +9: pop %edi + pop %esi + pop %ebx + leave + ret + + +/* Go from 4:2:0 interlaced to 'normal' YUYV */ + +ENTRY(ccvt_420i_yuyv) + enter $80, $0 # 8 bytes extra space, no stackframes + push %ebx + push %esi + push %edi + + call test_param_2 + jc 9f + + mov Width, %ecx # -4: width / 4 = no. loops per line + shr %ecx + shr %ecx + mov %ecx, -76(%ebp) + + mov Width, %ebx # -8: width * 1.5 = line offset + shl %ebx + add Width, %ebx + shr %ebx + mov %ebx, -80(%ebp) + + # Okay, this requires a bit of byte shuffling... we go from + # YYYY UU + # YYYY VV + # to + # YUYV YUYV + # YUYV YUYV + # which indeed takes up more space + + # + +0: mov -76(%ebp), %ecx + +1: lodsl # 4 Y in eax + testl $1, Height # even or odd line? + jnz 2f + + # Even + mov -80(%ebp), %ebx + mov (%ebx, %esi), %dx # 16 bits V + shl $16, %edx # store in high word + mov (%esi), %dx # 16 bits U + add $2, %esi + jmp 3f + +2: # Odd + mov -80(%ebp), %ebx + neg %ebx # negative offset + mov (%esi), %dx # 16 bits V + shl $16, %edx # store in high word + mov (%ebx, %esi), %dx # 16 bits U + add $2, %esi + +3: # eax = Y3Y2Y1Y0, edx = V1V0U1U0, ebx is free + push %eax + + movzbl %al, %ebx # ______y0 + and $0xFF00, %eax # ____y1__ + shl $8, %eax # __y1____ + or %ebx, %eax # __y1__y0 + mov %edx, %ebx # v1v0u1u0 + shl $8, %ebx # v0u1u0__ + and $0xff00ff00, %ebx # v0__u0__ + or %ebx, %eax # v0y1u0y0 + stosl + + pop %eax # y3y2y1y0 + # Second half + shr $8, %eax # __y3y2y1 + shr $8, %ax # __y3__y2 + and $0xff00ff00, %edx # v1__u1__ + or %edx, %eax # v1y3u1y2 + stosl + + loop 1b + + + decl Height # height-- + jnz 0b + # Done + +9: pop %edi + pop %esi + pop %ebx + leave + ret Index: ARToolKit/lib/SRC/VideoLinuxV4L2/jpegtorgb.h =================================================================== --- /dev/null +++ ARToolKit/lib/SRC/VideoLinuxV4L2/jpegtorgb.h @@ -0,0 +1,272 @@ +/* JPEG To RGB interface --Raphael Grasset - 04/07/16 - 2004 Hitlab NZ. All Rights reserved-- + +This file define simple routine functions for converting a JPEG image to RGB format. +It use is ONLY for EyeToy Camera. + +WARNING : It use a static image area : at each call of conversion, the new +image is copying on the same memory area (limited dynamic allocation mamagement). +So be careful when you manipulating the pointer on the image !! + +USAGE : +Based on libjpeg (providing hardware decompression), you need just add few things on your code: + +#include "jpegtorgb.h" //this file + +int xsiwe=640;//video image format +int ysize=480;//video image format +.... +JPEGToRGBInit(xsize,ysize); //init function with image size in parameters +.... + +ARUint8* decompressed_image=JPEGToRGB(video_image,xsize,ysize); //converting function (converted image return) + +don't be care with ARUint8, equivalent to an unsigned char format. + +*/ + +#include "jpeglib.h" +#include "jerror.h" +#include <setjmp.h> + + +/*---------------- Direct Input Functions for libjpeg --------------*/ + +/* we overload the interface for open a jpeg file : the libjpeg +file is limited for only FILE* input. Since we have a JPEG image +in memory we need a new interface for libjpeg. For these we overload +differents functions. +I have modified the code for jpeg_stdio_src, and providing +new functions name EyeToy_XXX (XXX template + +Need to be optimized, cleaned. +*/ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + unsigned char* image; + int image_size; + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +EyeToy_init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +EyeToy_fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + src->pub.next_input_byte = src->image; + src->pub.bytes_in_buffer = src->image_size; + + src->start_of_file = FALSE; + + return TRUE; +} + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +EyeToy_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) EyeToy_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) +EyeToy_term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* +The new jpeg access function : directly read the memory +buffer instead of a FILE* input. Since all the image +is in memory we put all the buffer in one pass. +*/ + +GLOBAL(void) +EyeToy_jpeg_stdio_src(j_decompress_ptr cinfo,unsigned char *image,int count) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next 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->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = EyeToy_init_source; + src->pub.fill_input_buffer = EyeToy_fill_input_buffer; + src->pub.skip_input_data = EyeToy_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = EyeToy_term_source; + src->image=image; + src->image_size=count; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + +static ARUint8* TransfertBufferImage; + +/*---------------- Main Functions --------------*/ + +void JPEGToRGBInit(int xsize,int ysize) +{ + TransfertBufferImage = malloc(xsize*ysize*3); +} + + +ARUint8* JPEGToRGB(ARUint8* image, int xsize,int ysize) +{ + + int image_height=xsize; /* Number of rows in image */ + int image_width=ysize; /* Number of columns in image */ + + struct jpeg_error_mgr jerr; + struct jpeg_decompress_struct cinfo; + + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in output buffer */ + int crows=0; + + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_decompress(&cinfo); + + ssize_t count; + count=(image[0]+image[1]*65536)/8; + + EyeToy_jpeg_stdio_src(&cinfo,image+2,count); + + (void) jpeg_read_header(&cinfo, TRUE); + + (void) jpeg_start_decompress(&cinfo); + + row_stride = cinfo.output_width * cinfo.output_components; + /* Make a one-row-high sample array that will go away when done with image */ + + while (cinfo.output_scanline < cinfo.output_height) + { + row_pointer[0] = & TransfertBufferImage[crows * row_stride]; + (void) jpeg_read_scanlines(&cinfo, row_pointer, 1); + crows++; + } + + (void) jpeg_finish_decompress(&cinfo); + + jpeg_destroy_decompress(&cinfo); + + return TransfertBufferImage; +} Index: ARToolKit/lib/SRC/VideoLinuxV4L2/video.c =================================================================== --- /dev/null +++ ARToolKit/lib/SRC/VideoLinuxV4L2/video.c @@ -0,0 +1,739 @@ +/* + * Video capture subrutine for Linux/Video4Linux2 devices + * Based upon the V4L 1 artoolkit code and v4l2 spec example + * at http://v4l2spec.bytesex.org/spec/a13010.htm + * Simon Goodall <sg@ecs.soton.ac.uk> + */ +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <linux/types.h> +#include <linux/videodev2.h> +#include <AR/video.h> +#include "ccvt.h" + +#define MAXCHANNEL 10 + +static AR2VideoParamT *gVid = NULL; + +static void printPalette(int p) { + switch(p) { +//YUV formats + case (V4L2_PIX_FMT_GREY): printf(" Pix Fmt: Grey\n"); break; + case (V4L2_PIX_FMT_YUYV): printf(" Pix Fmt: YUYV\n"); break; + case (V4L2_PIX_FMT_UYVY): printf(" Pix Fmt: UYVY\n"); break; + case (V4L2_PIX_FMT_Y41P): printf(" Pix Fmt: Y41P\n"); break; + case (V4L2_PIX_FMT_YVU420): printf(" Pix Fmt: YVU420\n"); break; + case (V4L2_PIX_FMT_YVU410): printf(" Pix Fmt: YVU410\n"); break; + case (V4L2_PIX_FMT_YUV422P): printf(" Pix Fmt: YUV422P\n"); break; + case (V4L2_PIX_FMT_YUV411P): printf(" Pix Fmt: YUV411P\n"); break; + case (V4L2_PIX_FMT_NV12): printf(" Pix Fmt: NV12\n"); break; + case (V4L2_PIX_FMT_NV21): printf(" Pix Fmt: NV21\n"); break; +// RGB formats + case (V4L2_PIX_FMT_RGB332): printf(" Pix Fmt: RGB332\n"); break; + case (V4L2_PIX_FMT_RGB555): printf(" Pix Fmt: RGB555\n"); break; + case (V4L2_PIX_FMT_RGB565): printf(" Pix Fmt: RGB565\n"); break; + case (V4L2_PIX_FMT_RGB555X): printf(" Pix Fmt: RGB555X\n"); break; + case (V4L2_PIX_FMT_RGB565X): printf(" Pix Fmt: RGB565X\n"); break; + case (V4L2_PIX_FMT_BGR24): printf(" Pix Fmt: BGR24\n"); break; + case (V4L2_PIX_FMT_RGB24): printf(" Pix Fmt: RGB24\n"); break; + case (V4L2_PIX_FMT_BGR32): printf(" Pix Fmt: BGR32\n"); break; + case (V4L2_PIX_FMT_RGB32): printf(" Pix Fmt: RGB32\n"); break; + }; + +} + +static int getControl(int fd, int type, int *value) { + struct v4l2_queryctrl queryctrl; + struct v4l2_control control; + + memset (&queryctrl, 0, sizeof (queryctrl)); + // TODO: Manke sure this is a correct value + queryctrl.id = type; + + if (-1 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) { + if (errno != EINVAL) { + fprintf(stderr, "Error calling VIDIOC_QUERYCTRL\n"); + return 1; + } else { + printf ("Control %d is not supported\n", type); + return 1; + } + } else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { + printf ("Control %s is not supported\n", queryctrl.name); + return 1; + } else { + memset (&control, 0, sizeof (control)); + control.id = type; + + if (-1 == ioctl (fd, VIDIOC_G_CTRL, &control)) { + fprintf(stderr, "Error getting control %s value\n", queryctrl.name); + return 1; + } + *value = control.value; + } + return 0; +} + + +static int setControl(int fd, int type, int value) { + struct v4l2_queryctrl queryctrl; + struct v4l2_control control; + + memset (&queryctrl, 0, sizeof (queryctrl)); + // TODO: Manke sure this is a correct value + queryctrl.id = type; + + if (-1 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) { + if (errno != EINVAL) { + fprintf(stderr, "Error calling VIDIOC_QUERYCTRL\n"); + return 1; + } else { + printf ("Control %d is not supported\n", type); + return 1; + } + } else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { + printf ("Control %s is not supported\n", queryctrl.name); + return 1; + } else { + memset (&control, 0, sizeof (control)); + control.id = type; + // TODO check min/max range + // If value is -1, then we use the default value + control.value = (value == -1) ? (queryctrl.default_value) : (value); + + if (-1 == ioctl (fd, VIDIOC_S_CTRL, &control)) { + fprintf(stderr, "Error setting control %s to %d\n", queryctrl.name, value); + return 1; + } + } + return 0; +} + +int arVideoDispOption( void ) +{ + return ar2VideoDispOption(); +} + +int arVideoOpen( char *config ) +{ + if( gVid != NULL ) { + printf("Device has been opened!!\n"); + return -1; + } + gVid = ar2VideoOpen( config ); + if( gVid == NULL ) return -1; + + return 0; +} + +int arVideoClose( void ) +{ + int result; + + if( gVid == NULL ) return -1; + + result = ar2VideoClose(gVid); + gVid = NULL; + return (result); +} + +int arVideoInqSize( int *x, int *y ) +{ + if( gVid == NULL ) return -1; + + return ar2VideoInqSize( gVid, x, y ); +} + +ARUint8 *arVideoGetImage( void ) +{ + if( gVid == NULL ) return NULL; + + return ar2VideoGetImage( gVid ); +} + +int arVideoCapStart( void ) +{ + if( gVid == NULL ) return -1; + + return ar2VideoCapStart( gVid ); +} + +int arVideoCapStop( void ) +{ + if( gVid == NULL ) return -1; + + return ar2VideoCapStop( gVid ); +} + +int arVideoCapNext( void ) +{ + if( gVid == NULL ) return -1; + + return ar2VideoCapNext( gVid ); +} + +/*-------------------------------------------*/ + +int ar2VideoDispOption( void ) +{ + printf("ARVideo may be configured using one or more of the following options,\n"); + printf("separated by a space:\n\n"); + printf("DEVICE CONTROLS:\n"); + printf(" -dev=filepath\n"); + printf(" specifies device file.\n"); + printf(" -channel=N\n"); + printf(" specifies source channel.\n"); + printf(" -width=N\n"); + printf(" specifies expected width of image.\n"); + printf(" -height=N\n"); + printf(" specifies expected height of image.\n"); + printf(" -palette=[RGB|YUV420P]\n"); + printf(" specifies the camera palette (WARNING:all are not supported on each camera !!).\n"); + printf("IMAGE CONTROLS (WARNING: every options are not supported by all camera !!):\n"); + printf(" -brightness=N\n"); + printf(" specifies brightness. (0.0 <-> 1.0)\n"); + printf(" -contrast=N\n"); + printf(" specifies contrast. (0.0 <-> 1.0)\n"); + printf(" -saturation=N\n"); + printf(" specifies saturation (color). (0.0 <-> 1.0) (for color camera only)\n"); + printf(" -hue=N\n"); + printf(" specifies hue. (0.0 <-> 1.0) (for color camera only)\n"); + printf("OPTION CONTROLS:\n"); + printf(" -mode=[PAL|NTSC|SECAM]\n"); + printf(" specifies TV signal mode (for tv/capture card).\n"); + printf("\n"); + + return 0; +} + +AR2VideoParamT *ar2VideoOpen( char *config_in ) +{ + +// Warning, this function leaks badly when an error occurs. + AR2VideoParamT *vid; + struct v4l2_capability vd; + struct v4l2_format fmt; + struct v4l2_input ipt; + struct v4l2_requestbuffers req; + + char *config, *a, line[256]; + int value; + + /* If no config string is supplied, we should use the environment variable, otherwise set a sane default */ + if (!config_in || !(config_in[0])) { + /* None suppplied, lets see if the user supplied one from the shell */ + char *envconf = getenv ("ARTOOLKIT_CONFIG"); + if (envconf && envconf[0]) { + config = envconf; + printf ("Using config string from environment [%s].\n", envconf); + } else { + config = NULL; + printf ("No video config string supplied, using defaults.\n"); + } + } else { + config = config_in; + printf ("Using supplied video config string [%s].\n", config_in); + } + + arMalloc( vid, AR2VideoParamT, 1 ); + strcpy( vid->dev, DEFAULT_VIDEO_DEVICE ); + vid->width = DEFAULT_VIDEO_WIDTH; + vid->height = DEFAULT_VIDEO_HEIGHT; + vid->palette = V4L2_PIX_FMT_YUYV; /* palette format */ + vid->contrast = -1; + vid->brightness = -1; + vid->saturation = -1; + vid->hue = -1; + vid->gamma = -1; + vid->exposure = -1; + vid->gain = -1; + vid->mode = V4L2_STD_NTSC; + //vid->debug = 0; + vid->debug = 1; + vid->channel = 0; + vid->videoBuffer=NULL; + + a = config; + if( a != NULL) { + for(;;) { + while( *a == ' ' || *a == '\t' ) a++; + if( *a == '\0' ) break; + if( strncmp( a, "-dev=", 5 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[5], "%s", vid->dev ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-channel=", 9 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[9], "%d", &vid->channel ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-width=", 7 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[7], "%d", &vid->width ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-height=", 8 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[8], "%d", &vid->height ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-palette=", 9 ) == 0 ) { + if( strncmp( &a[9], "GREY", 4) == 0 ) { + vid->palette = V4L2_PIX_FMT_GREY; + } else if( strncmp( &a[9], "HI240", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_HI240; + } else if( strncmp( &a[9], "RGB565", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_RGB565; + } else if( strncmp( &a[9], "RGB555", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_RGB555; + } else if( strncmp( &a[9], "BGR24", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_BGR24; + } else if( strncmp( &a[9], "BGR32", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_BGR32; + } else if( strncmp( &a[9], "YUYV", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_YUYV; + } else if( strncmp( &a[9], "UYVY", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_UYVY; + } else if( strncmp( &a[9], "Y41P", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_Y41P; + } else if( strncmp( &a[9], "YUV422P", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_YUV422P; + } else if( strncmp( &a[9], "YUV411P", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_YUV411P; + } else if( strncmp( &a[9], "YVU420", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_YVU420; + } else if( strncmp( &a[9], "YVU410", 3) == 0 ) { + vid->palette = V4L2_PIX_FMT_YVU410; + } + } + else if( strncmp( a, "-contrast=", 10 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[10], "%d", &vid->contrast ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-brightness=", 12 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[12], "%d", &vid->brightness ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-saturation=", 12 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[12], "%d", &vid->saturation ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-hue=", 5 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[5], "%d", &vid->hue ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-gamma=", 7 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[7], "%d", &vid->gamma ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-exposure=", 10 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[10], "%d", &vid->exposure ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-gain=", 6 ) == 0 ) { + sscanf( a, "%s", line ); + if( sscanf( &line[6], "%d", &vid->gain ) == 0 ) { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-mode=", 6 ) == 0 ) { + if( strncmp( &a[6], "PAL", 3 ) == 0 ) vid->mode = V4L2_STD_PAL; + else if( strncmp( &a[6], "NTSC", 4 ) == 0 ) vid->mode = V4L2_STD_NTSC; + else if( strncmp( &a[6], "SECAM", 5 ) == 0 ) vid->mode = V4L2_STD_SECAM; + else { + ar2VideoDispOption(); + free( vid ); + return 0; + } + } + else if( strncmp( a, "-debug", 6 ) == 0 ) { + vid->debug = 1; + } + else { + ar2VideoDispOption(); + free( vid ); + return 0; + } + + while( *a != ' ' && *a != '\t' && *a != '\0') a++; + } + } + + vid->fd = open(vid->dev, O_RDWR);// O_RDONLY ? + if(vid->fd < 0){ + printf("video device (%s) open failed\n",vid->dev); + free( vid ); + return 0; + } + + if(ioctl(vid->fd,VIDIOC_QUERYCAP,&vd) < 0){ + printf("ioctl failed\n"); + free( vid ); + return 0; + } + + if (!(vd.capabilities & V4L2_CAP_STREAMING)) { + fprintf (stderr, "Device does not support streaming i/o\n"); + } + + if(vid->debug ) { + printf("=== debug info ===\n"); + printf(" vd.driver = %s\n",vd.driver); + printf(" vd.card = %s\n",vd.card); + printf(" vd.bus_info = %s\n",vd.bus_info); + printf(" vd.version = %d\n",vd.version); + printf(" vd.capabilities = %d\n",vd.capabilities); + } + + memset(&fmt, 0, sizeof(fmt)); + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +#if 0 + fmt.fmt.pix.width = vid->width; + fmt.fmt.pix.height = vid->height; + fmt.fmt.pix.pixelformat = vid->palette; + fmt.fmt.pix.field = V4L2_FIELD_NONE; +#else + fmt.fmt.pix.width = 640; + fmt.fmt.pix.height = 480; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; +#endif + + if (ioctl (vid->fd, VIDIOC_S_FMT, &fmt) < 0) { + close(vid->fd); + free( vid ); + printf("ar2VideoOpen: Error setting video format (%d)\n", errno); + return 0; + } + + // Get actual camera settings + vid->palette = fmt.fmt.pix.pixelformat; + vid->width = fmt.fmt.pix.width; + vid->height = fmt.fmt.pix.height; + + if (vid->debug) { + printf(" Width: %d\n", fmt.fmt.pix.width); + printf(" Height: %d\n", fmt.fmt.pix.height); + printPalette(fmt.fmt.pix.pixelformat); + } + + memset(&ipt, 0, sizeof(ipt)); + + ipt.index = vid->channel; + ipt.std = vid->mode; + + if(ioctl(vid->fd,VIDIOC_ENUMINPUT,&ipt) < 0) { + printf("arVideoOpen: Error querying input device type\n"); + close(vid->fd); + free( vid ); + return 0; + } + + if (vid->debug) { + if (ipt.type == V4L2_INPUT_TYPE_TUNER) { + printf(" Type: Tuner\n"); + } + if (ipt.type == V4L2_INPUT_TYPE_CAMERA) { + printf(" Type: Camera\n"); + } + } + + // Set channel + if (ioctl(vid->fd, VIDIOC_S_INPUT, &ipt)) { + printf("arVideoOpen: Error setting video input\n"); + close(vid->fd); + free( vid ); + return 0; + } + + + // Attempt to set some camera controls + setControl(vid->fd, V4L2_CID_BRIGHTNESS, vid->brightness); + setControl(vid->fd, V4L2_CID_CONTRAST, vid->contrast); + setControl(vid->fd, V4L2_CID_SATURATION, vid->saturation); + setControl(vid->fd, V4L2_CID_HUE, vid->hue); + setControl(vid->fd, V4L2_CID_GAMMA, vid->gamma); + setControl(vid->fd, V4L2_CID_EXPOSURE, vid->exposure); + setControl(vid->fd, V4L2_CID_GAIN, vid->gain); + + // Print out current control values + if(vid->debug ) { + if (!getControl(vid->fd, V4L2_CID_BRIGHTNESS, &value)) { + printf("Brightness: %d\n", value); + } + if (!getControl(vid->fd, V4L2_CID_CONTRAST, &value)) { + printf("Contrast: %d\n", value); + } + if (!getControl(vid->fd, V4L2_CID_SATURATION, &value)) { + printf("Saturation: %d\n", value); + } + if (!getControl(vid->fd, V4L2_CID_HUE, &value)) { + printf("Hue: %d\n", value); + } + if (!getControl(vid->fd, V4L2_CID_GAMMA, &value)) { + printf("Gamma: %d\n", value); + } + if (!getControl(vid->fd, V4L2_CID_EXPOSURE, &value)) { + printf("Exposure: %d\n", value); + } + if (!getControl(vid->fd, V4L2_CID_GAIN, &value)) { + printf("Gain: %d\n", value); + } + } + +// if (vid->palette==V4L2_PIX_FMT_YUYV) + arMalloc( vid->videoBuffer, ARUint8, vid->width*vid->height*3 ); + + // Setup memory mapping + memset(&req, 0, sizeof(req)); + req.count = 2; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + + if (ioctl(vid->fd, VIDIOC_REQBUFS, &req)) { + printf("Error calling VIDIOC_REQBUFS\n"); + close(vid->fd); + if(vid->videoBuffer!=NULL) free(vid->videoBuffer); + free( vid ); + return 0; + } + + if (req.count < 2) { + printf("this device can not be supported by libARvideo.\n"); + printf("(req.count < 2)\n"); + close(vid->fd); + if(vid->videoBuffer!=NULL) free(vid->videoBuffer); + free( vid ); + + return 0; + } + + vid->buffers = (struct buffer*)calloc(req.count , sizeof(*vid->buffers)); + + if (vid->buffers == NULL ) { + printf("ar2VideoOpen: Error allocating buffer memory\n"); + close(vid->fd); + if(vid->videoBuffer!=NULL) free(vid->videoBuffer); + free( vid ); + return 0; + } + + for (vid->n_buffers = 0; vid->n_buffers < req.count; ++vid->n_buffers) { + struct v4l2_buffer buf; + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = vid->n_buffers; + + if (ioctl (vid->fd, VIDIOC_QUERYBUF, &buf)) { + printf ("error VIDIOC_QUERYBUF\n"); + close(vid->fd); + if(vid->videoBuffer!=NULL) free(vid->videoBuffer); + free( vid ); + return 0; + } + + vid->buffers[vid->n_buffers].length = buf.length; + vid->buffers[vid->n_buffers].start = + mmap (NULL /* start anywhere */, + buf.length, + PROT_READ | PROT_WRITE /* required */, + MAP_SHARED /* recommended */, + vid->fd, buf.m.offset); + + if (MAP_FAILED == vid->buffers[vid->n_buffers].start) { + printf("Error mmap\n"); + close(vid->fd); + if(vid->videoBuffer!=NULL) free(vid->videoBuffer); + free( vid ); + return 0; + } + } + + vid->video_cont_num = -1; + + return vid; +} + +int ar2VideoClose( AR2VideoParamT *vid ) +{ + if(vid->video_cont_num >= 0){ + ar2VideoCapStop( vid ); + } + close(vid->fd); + if(vid->videoBuffer!=NULL) + free(vid->videoBuffer); + free( vid ); + + return 0; +} + + +int ar2VideoCapStart( AR2VideoParamT *vid ) +{ + enum v4l2_buf_type type; + struct v4l2_buffer buf; + int i; + + if (vid->video_cont_num >= 0){ + printf("arVideoCapStart has already been called.\n"); + return -1; + } + + vid->video_cont_num = 0; + + for (i = 0; i < vid->n_buffers; ++i) { + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + if (ioctl(vid->fd, VIDIOC_QBUF, &buf)) { + printf("ar2VideoCapStart: Error calling VIDIOC_QBUF: %d\n", errno); + return -1; + } + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(vid->fd, VIDIOC_STREAMON, &type)) { + printf("ar2VideoCapStart: Error calling VIDIOC_STREAMON\n"); + return -1; + } + + return 0; +} + +int ar2VideoCapNext( AR2VideoParamT *vid ) +{ + struct v4l2_buffer buf; + + if (vid->video_cont_num < 0){ + printf("arVideoCapStart has never been called.\n"); + return -1; + } + + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = vid->video_cont_num; + + if (ioctl(vid->fd, VIDIOC_QBUF, &buf)) { + printf("ar2VideoCapNext: Error calling VIDIOC_QBUF: %d\n", errno); + return 1; + } + + return 0; +} + +int ar2VideoCapStop( AR2VideoParamT *vid ) +{ + enum v4l2_buf_type type; + if(vid->video_cont_num < 0){ + printf("arVideoCapStart has never been called.\n"); + return -1; + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (ioctl(vid->fd, VIDIOC_STREAMOFF, &type)) { + printf("Error calling VIDIOC_STREAMOFF\n"); + return -1; + } + + vid->video_cont_num = -1; + + return 0; +} + + +ARUint8 *ar2VideoGetImage( AR2VideoParamT *vid ) +{ + ARUint8 *buffer; + struct v4l2_buffer buf; + + if(vid->video_cont_num < 0){ + printf("arVideoCapStart has never been called.\n"); + return NULL; + } + + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + if (ioctl(vid->fd, VIDIOC_DQBUF, &buf) < 0) { + printf("Error calling VIDIOC_DQBUF: %d\n", errno); + return NULL; + } + + buffer = (ARUint8*)vid->buffers[buf.index].start; + vid->video_cont_num = buf.index; + + // TODO: Add other video format conversions. + if (vid->palette == V4L2_PIX_FMT_YUYV) { +#if defined(AR_PIX_FORMAT_BGRA) + ccvt_yuyv_rgb32(vid->width, vid->height, buffer, vid->videoBuffer); +#else + ccvt_yuyv_rgb24(vid->width, vid->height, buffer, vid->videoBuffer); +#endif + return vid->videoBuffer; + } + + return buffer; + +} + +int ar2VideoInqSize(AR2VideoParamT *vid, int *x,int *y) +{ + *x = vid->width; + *y = vid->height; + + return 0; +} + Index: ARToolKit/util/calib_camera2/main.c =================================================================== --- ARToolKit.orig/util/calib_camera2/main.c +++ ARToolKit/util/calib_camera2/main.c @@ -64,6 +64,8 @@ static char *vconf = "-size=F char *vconf = "videotestsrc ! capsfilter caps=video/x-raw-rgb,bpp=24 ! identity name=artoolkit ! fakesink"; # elif defined(AR_INPUT_V4L) static char *vconf = "-width=640 -height=480"; +# elif defined(AR_INPUT_V4L2) +static char *vconf = "-width=640 -height=480"; # elif defined(AR_INPUT_1394CAM) static char *vconf = "-mode=640x480_YUV411"; # elif defined(AR_INPUT_DV) Index: ARToolKit/util/calib_cparam/calib_cparam.c =================================================================== --- ARToolKit.orig/util/calib_cparam/calib_cparam.c +++ ARToolKit/util/calib_cparam/calib_cparam.c @@ -64,6 +64,8 @@ char *vconf = "-size=FULL"; char *vconf = "videotestsrc"; # elif defined(AR_INPUT_V4L) char *vconf = "-width=640 -height=480"; +# elif defined(AR_INPUT_V4L2) +char *vconf = "-width=640 -height=480"; # elif defined(AR_INPUT_1394CAM) char *vconf = "-mode=640x480_YUV411"; # elif defined(AR_INPUT_DV) Index: ARToolKit/util/calib_distortion/calib_dist.c =================================================================== --- ARToolKit.orig/util/calib_distortion/calib_dist.c +++ ARToolKit/util/calib_distortion/calib_dist.c @@ -64,6 +64,8 @@ char *vconf = "-size=FULL"; char *vconf = "videotestsrc"; # elif defined(AR_INPUT_V4L) char *vconf = "-width=640 -height=480"; +# elif defined(AR_INPUT_V4L2) +char *vconf = "-width=640 -height=480"; # elif defined(AR_INPUT_1394CAM) char *vconf = "-mode=640x480_YUV411"; # elif defined(AR_INPUT_DV) Index: ARToolKit/util/mk_patt/mk_patt.c =================================================================== --- ARToolKit.orig/util/mk_patt/mk_patt.c +++ ARToolKit/util/mk_patt/mk_patt.c @@ -61,6 +61,8 @@ char *vconf = "-size=FULL"; char *vconf = "videotestsrc"; # elif defined(AR_INPUT_V4L) char *vconf = "-width=640 -height=480"; +# elif defined(AR_INPUT_V4L2) +char *vconf = "-width=640 -height=480"; # elif defined(AR_INPUT_1394CAM) char *vconf = "-mode=640x480_YUV411"; # elif defined(AR_INPUT_DV) Index: ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt_misc.c =================================================================== --- /dev/null +++ ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt_misc.c @@ -0,0 +1,333 @@ +/* CCVT: ColourConVerT: simple library for converting colourspaces + Copyright (C) 2002 Nemosoft Unv. + + 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 + + For questions, remarks, patches, etc. for this program, the author can be + reached at nemosoft@smcc.demon.nl. +*/ + +/* This file contains CCVT functions that aren't available in assembly yet + (or are not worth programming) + */ + +/* + + * $Log: ccvt_misc.c,v $ + * Revision 1.1.1.1 2005/11/30 18:56:20 modin + * initial release + * + * Revision 1.8 2005/09/20 00:00:00 mkalten@iua.upf.es + * fixed ccvt_yuyv_bgr32 + * implemented ccvt_yuyv_bgr24, ccvt_yuyv_rgb24, ccvt_yuyv_rgb32 + * + * $Log: ccvt_misc.c,v $ + * Revision 1.1.1.1 2005/11/30 18:56:20 modin + * initial release + * + * Revision 1.7 2003/01/02 04:10:19 nemosoft + * Adding ''upside down" conversion to rgb/bgr routines + * + * Revision 1.6 2002/12/03 23:29:11 nemosoft + * *** empty log message *** + * + * Revision 1.5 2002/12/03 23:27:41 nemosoft + * fixing log messages (gcc 3.2 complaining) + * + Revision 1.4 2002/12/03 22:29:07 nemosoft + Fixing up FTP stuff and some video + + Revision 1.3 2002/11/03 22:46:25 nemosoft + Adding various RGB to RGB functions. + Adding proper copyright header too. + */ + + +#include "ccvt.h" +#include "ccvt_types.h" + + +void ccvt_yuyv_bgr32(int width, int height, const void *src, void *dst) +{ + const unsigned char *s; + PIXTYPE_bgr32 *d; + int l, c; + int r, g, b, cr, cg, cb, y1, y2; + + l = height; + s = src; + d = dst; + while (l--) { + c = width >> 2; + while (c--) { + cb = ((*s - 128) * 454) >> 8; + cg = (*s++ - 128) * 88; + y1 = *s++; + cr = ((*s - 128) * 359) >> 8; + cg = (cg + (*s++ - 128) * 183) >> 8; + y2 = *s++; + + r = y1 + cr; + b = y1 + cb; + g = y1 - cg; + SAT(r); + SAT(g); + SAT(b); + d->b = b; + d->g = g; + d->r = r; + d++; + r = y2 + cr; + b = y2 + cb; + g = y2 - cg; + SAT(r); + SAT(g); + SAT(b); + d->b = b; + d->g = g; + d->r = r; + d++; + } + } + +} + +void ccvt_yuyv_bgr24(int width, int height, const void *src, void *dst) +{ + const unsigned char *s; + PIXTYPE_bgr24 *d; + int l, c; + int r, g, b, cr, cg, cb, y1, y2; + + l = height; + s = src; + d = dst; + while (l--) { + c = width >> 2; + while (c--) { + cb = ((*s - 128) * 454) >> 8; + cg = (*s++ - 128) * 88; + y1 = *s++; + cr = ((*s - 128) * 359) >> 8; + cg = (cg + (*s++ - 128) * 183) >> 8; + y2 = *s++; + + r = y1 + cr; + b = y1 + cb; + g = y1 - cg; + SAT(r); + SAT(g); + SAT(b); + d->b = b; + d->g = g; + d->r = r; + d++; + r = y2 + cr; + b = y2 + cb; + g = y2 - cg; + SAT(r); + SAT(g); + SAT(b); + d->b = b; + d->g = g; + d->r = r; + d++; + } + } + +} + +void ccvt_yuyv_rgb32(int width, int height, const void *src, void *dst) +{ + const unsigned char *s; + PIXTYPE_rgb32 *d; + int l, c; + int r, g, b, cr, cg, cb, y1, y2; + + l = height; + s = src; + d = dst; + while (l--) { + c = width >> 2; + while (c--) { + cb = ((*s - 128) * 454) >> 8; + cg = (*s++ - 128) * 88; + y1 = *s++; + cr = ((*s - 128) * 359) >> 8; + cg = (cg + (*s++ - 128) * 183) >> 8; + y2 = *s++; + + r = y1 + cr; + b = y1 + cb; + g = y1 - cg; + SAT(r); + SAT(g); + SAT(b); + d->r = r; + d->g = g; + d->b = b; + d++; + r = y2 + cr; + b = y2 + cb; + g = y2 - cg; + SAT(r); + SAT(g); + SAT(b); + d->r = r; + d->g = g; + d->b = b; + d++; + } + } + +} + +void ccvt_yuyv_rgb24(int width, int height, const void *src, void *dst) +{ + const unsigned char *s; + unsigned char *d; + //PIXTYPE_rgb24 *d; + int l, c; + int r, g, b, cr, cg, cb, y1, y2; + + l = height; + s = src; + d = dst; + while (l--) { + c = width >> 2; + while (c--) { + cb = ((*s - 128) * 454) >> 8; + cg = (*s++ - 128) * 88; + y1 = *s++; + cr = ((*s - 128) * 359) >> 8; + cg = (cg + (*s++ - 128) * 183) >> 8; + y2 = *s++; + + r = y1 + cr; + b = y1 + cb; + g = y1 - cg; + SAT(r); + SAT(g); + SAT(b); + *d++ = r; + *d++ = g; + *d++ = b; + r = y2 + cr; + b = y2 + cb; + g = y2 - cg; + SAT(r); + SAT(g); + SAT(b); + *d++ = r; + *d++ = g; + *d++ = b; + } + } + +} + +void ccvt_yuyv_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv) +{ + int n, l, j; + const unsigned char *s1, *s2; + unsigned char *dy, *du, *dv; + + dy = (unsigned char *)dsty; + du = (unsigned char *)dstu; + dv = (unsigned char *)dstv; + s1 = (unsigned char *)src; + s2 = s1; // keep pointer + n = width * height; + for (; n > 0; n--) { + *dy = *s1; + dy++; + s1 += 2; + } + + /* Two options here: average U/V values, or skip every second row */ + s1 = s2; // restore pointer + s1++; // point to U + for (l = 0; l < height; l += 2) { + s2 = s1 + width * 2; // odd line + for (j = 0; j < width; j += 2) { + *du = (*s1 + *s2) / 2; + du++; + s1 += 2; + s2 += 2; + *dv = (*s1 + *s2) / 2; + dv++; + s1 += 2; + s2 += 2; + } + s1 = s2; + } +} + +/* RGB/BGR to RGB/BGR */ + +#define RGBBGR_BODY24(TIN, TOUT) \ +void ccvt_ ## TIN ## _ ## TOUT (int width, int height, const void *const src, void *const dst) \ +{ \ + const PIXTYPE_ ## TIN *in = src; \ + PIXTYPE_ ## TOUT *out = dst; \ + int l, c, stride = 0; \ + \ + if (height < 0) { stride = width; height = -height; } \ + out += ((height - 1) * width); \ + stride *= 2; \ + for (l = 0; l < height; l++) { \ + for (c = 0; c < width; c++) { \ + out->r = in->r; \ + out->g = in->g; \ + out->b = in->b; \ + in++; \ + out++; \ + } \ + out -= stride; \ + } \ +} + +#define RGBBGR_BODY32(TIN, TOUT) \ +void ccvt_ ## TIN ## _ ## TOUT (int width, int height, const void *const src, void *const dst) \ +{ \ + const PIXTYPE_ ## TIN *in = src; \ + PIXTYPE_ ## TOUT *out = dst; \ + int l, c, stride = 0; \ + \ + if (height < 0) { stride = width; height = -height; } \ + out += ((height - 1) * width); \ + stride *= 2; \ + for (l = 0; l < height; l++) { \ + for (c = 0; c < width; c++) { \ + out->r = in->r; \ + out->g = in->g; \ + out->b = in->b; \ + out->z = 0; \ + in++; \ + out++; \ + } \ + out -= stride; \ + } \ +} + +RGBBGR_BODY32(bgr24, bgr32) +RGBBGR_BODY32(bgr24, rgb32) +RGBBGR_BODY32(rgb24, bgr32) +RGBBGR_BODY32(rgb24, rgb32) + +RGBBGR_BODY24(bgr32, bgr24) +RGBBGR_BODY24(bgr32, rgb24) +RGBBGR_BODY24(rgb32, bgr24) +RGBBGR_BODY24(rgb32, rgb24) Index: ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt_types.h =================================================================== --- /dev/null +++ ARToolKit/lib/SRC/VideoLinuxV4L2/ccvt_types.h @@ -0,0 +1,61 @@ +/* CCVT: ColourConVerT: simple library for converting colourspaces + Copyright (C) 2002 Nemosoft Unv. + + 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 + + For questions, remarks, patches, etc. for this program, the author can be + reached at nemosoft@smcc.demon.nl. +*/ + +#ifndef CCVT_TYPES_H +#define CCVT_TYPES_H + +typedef struct +{ + unsigned char b; + unsigned char g; + unsigned char r; + unsigned char z; +} PIXTYPE_bgr32; + +typedef struct +{ + unsigned char b; + unsigned char g; + unsigned char r; +} PIXTYPE_bgr24; + +typedef struct +{ + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char z; +} PIXTYPE_rgb32; + +typedef struct +{ + unsigned char r; + unsigned char g; + unsigned char b; +} PIXTYPE_rgb24; + + +#define SAT(c) \ + if (c & (~255)) { if (c < 0) c = 0; else c = 255; } + + + +#endif
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor