diff options
31 files changed, 7113 insertions, 5 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6719f8eb3..20ffd29b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -474,7 +474,7 @@ IF(WANT_KDE4) INCLUDE_DIRECTORIES(${KDE4_INCLUDES}) ADD_DEFINITIONS(${KDE4_DEFINITIONS}) SET(COMPILE_KDE_SUPPORT 1) - LIST(APPEND LIBS ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBRARY} ${KDE4_KPARTS_LIBRARY} ${KDE4_KFILE_LIBRARY} ${KDE4_KIO_LIBRARY}) + LIST(APPEND LIBS ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBRARY} ${KDE4_KPARTS_LIBRARY} ${KDE4_KFILE_LIBRARY} ${KDE4_KIO_LIBRARY} ${KDE4_SOLID_LIBRARY}) SET(CMAKE_STATUS_KDE4_SUPPORT "Yes") LIST(APPEND CMAKE_KVIRC_BUILD_FLAGS COMPILE_KDE_SUPPORT) @@ -757,6 +757,30 @@ ELSE() ENDIF() ############################################################################ +# Dcc video support + extended webcam support (LibV4L2) +############################################################################ +OPTION(WANT_DCC_VIDEO "Compile DCC Video Support" OFF) +IF(WITHOUT_DCC_VIDEO) + SET(WANT_DCC_VIDEO OFF) +ENDIF() + +FIND_PACKAGE(LibV4L2) + +IF(WANT_DCC_VIDEO) + IF(LIBV4L2_FOUND) + SET(CMAKE_STATUS_DCC_VIDEO_SUPPORT "Yes, with LibV4L2") + SET(HAVE_LIBV4L2 1) + SET(V4L2_CAP_VIDEO_CAPTURE 1) + ELSE() + SET(CMAKE_STATUS_DCC_VIDEO_SUPPORT "Yes, without LibV4L2") + ENDIF() +ELSE() + SET(COMPILE_DISABLE_DCC_VIDEO 1) + LIST(APPEND CMAKE_KVIRC_BUILD_FLAGS WITHOUT_DCC_VIDEO) + SET(CMAKE_STATUS_DCC_VIDEO_SUPPORT "User disabled") +ENDIF() + +############################################################################ # ix86 asm support ############################################################################ OPTION(WANT_IX86_ASM "Compile ix86 (NOT x86_64!) asm Support" OFF) @@ -1197,6 +1221,7 @@ MESSAGE(STATUS " IPC Support : ${CMAKE_STATUS_IPC_SUPPORT}") MESSAGE(STATUS " System memmove Support : ${CMAKE_STATUS_SYSTEM_MEMMOVE_SUPPORT}") MESSAGE(STATUS " GSM Support : ${CMAKE_STATUS_GSM_SUPPORT}") MESSAGE(STATUS " DCC Voice Support : ${CMAKE_STATUS_DCC_VOICE_SUPPORT}") +MESSAGE(STATUS " DCC Video Support : ${CMAKE_STATUS_DCC_VIDEO_SUPPORT}") MESSAGE(STATUS " Apple Universal Binary : ${CMAKE_STATUS_BUILD_UNIVERSAL_BINARY}") MESSAGE(STATUS " ix86 asm Support : ${CMAKE_STATUS_ix86_ASM_SUPPORT}") MESSAGE(STATUS " Memory Profile Support : ${CMAKE_STATUS_MEMORY_PROFILE_SUPPORT}") diff --git a/cmake/modules/FindLibV4L2.cmake b/cmake/modules/FindLibV4L2.cmake new file mode 100644 index 000000000..3eec66ccd --- /dev/null +++ b/cmake/modules/FindLibV4L2.cmake @@ -0,0 +1,32 @@ +# cmake macro to test LibV4L2 + +# Copyright (c) 2009, Jaroslav Reznik <jreznik@redhat.com> +# +# LIBV4L2_FOUND +# LIBV4L2_INCLUDE_DIR +# LIBV4L2_LIBRARY +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +INCLUDE (FindPackageHandleStandardArgs) + +IF (LIBV4L2_INCLUDE_DIR AND LIBV4L2_LIBRARY) + # Already in cache, be silent + SET (LIBV4L2_FIND_QUIETLY TRUE) +ENDIF (LIBV4L2_INCLUDE_DIR AND LIBV4L2_LIBRARY) + +IF (NOT LIBV4L2_FOUND) + FIND_PATH (LIBV4L2_INCLUDE_DIR libv4l2.h) + FIND_LIBRARY (LIBV4L2_LIBRARY NAMES v4l2) + + IF (LIBV4L2_INCLUDE_DIR AND LIBV4L2_LIBRARY) + SET (LIBV4L2_FOUND TRUE) + ENDIF( LIBV4L2_INCLUDE_DIR AND LIBV4L2_LIBRARY ) +ENDIF ( NOT LIBV4L2_FOUND) + +IF( LIBV4L2_FOUND ) + IF( NOT LIBV4L2_FIND_QUIETLY ) + MESSAGE( STATUS "Found LIBV4L2: ${LIBV4L2_LIBRARY}") + ENDIF( NOT LIBV4L2_FIND_QUIETLY ) +ENDIF( LIBV4L2_FOUND ) diff --git a/src/kvilib/CMakeLists.txt b/src/kvilib/CMakeLists.txt index 97dcd5881..8a9e97e32 100644 --- a/src/kvilib/CMakeLists.txt +++ b/src/kvilib/CMakeLists.txt @@ -19,6 +19,7 @@ SET(kvilib_MOC_HDRS ext/kvi_crypt.h ext/kvi_regusersdb.h ext/kvi_sharedfiles.h + ext/avdevice/videodevicepool.h irc/kvi_ircuserdb.h net/kvi_dns.h net/kvi_http.h @@ -76,6 +77,14 @@ SET(kvilib_SRCS ext/kvi_regusersdb.cpp ext/kvi_sharedfiles.cpp ext/kvi_stringconversion.cpp + ext/avdevice/videodevice.cpp + ext/avdevice/videoinput.cpp + ext/avdevice/dummyvideodevice.cpp + ext/avdevice/videodevicevector.cpp + ext/avdevice/videodevicepool.cpp + ext/avdevice/videodevicemodelpool.cpp + ext/avdevice/bayer.cpp + ext/avdevice/sonix_compress.cpp file/kvi_file.cpp file/kvi_fileutils.cpp file/kvi_packagefile.cpp diff --git a/src/kvilib/ext/avdevice/bayer.cpp b/src/kvilib/ext/avdevice/bayer.cpp new file mode 100644 index 000000000..11183a4ff --- /dev/null +++ b/src/kvilib/ext/avdevice/bayer.cpp @@ -0,0 +1,144 @@ +//============================================================================= +// +// File : bayer.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + * BAYER2RGB24 ROUTINE TAKEN FROM: + * + * Sonix SN9C101 based webcam basic I/F routines + * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp> + * + * 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. + */ + +void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT) +{ + long int i; + unsigned char *rawpt, *scanpt; + long int size; + + rawpt = src; + scanpt = dst; + size = WIDTH*HEIGHT; + + for ( i = 0; i < size; i++ ) + { + if ( (i/WIDTH) % 2 == 0 ) + { + if ( (i % 2) == 0 ) + { + // B + if ( (i > WIDTH) && ((i % WIDTH) > 0) ) + { + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+*(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; // R + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+*(rawpt+WIDTH)+*(rawpt-WIDTH))/4; // G + *scanpt++ = *rawpt; // B + } + else + { + // first line or left column + *scanpt++ = *(rawpt+WIDTH+1); // R + *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2; // G + *scanpt++ = *rawpt; // B + } + } + else + { + // (B)G + if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) + { + *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; // R + *scanpt++ = *rawpt; // G + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; // B + } + else + { + // first line or right column + *scanpt++ = *(rawpt+WIDTH); // R + *scanpt++ = *rawpt; // G + *scanpt++ = *(rawpt-1); // B + } + } + } + else + { + if ( (i % 2) == 0 ) + { + // G(R) + if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) + { + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; // R + *scanpt++ = *rawpt; // G + *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; // B + } + else + { + // bottom line or left column + *scanpt++ = *(rawpt+1); /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt-WIDTH); /* B */ + } + } + else + { + // R + if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) + { + *scanpt++ = *rawpt; // R + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+*(rawpt-WIDTH)+*(rawpt+WIDTH))/4; // G + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+*(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; // B + } + else + { + // bottom line or right column + *scanpt++ = *rawpt; /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2; /* G */ + *scanpt++ = *(rawpt-WIDTH-1); /* B */ + } + } + } + rawpt++; + } +} + diff --git a/src/kvilib/ext/avdevice/bayer.h b/src/kvilib/ext/avdevice/bayer.h new file mode 100644 index 000000000..6df2f679f --- /dev/null +++ b/src/kvilib/ext/avdevice/bayer.h @@ -0,0 +1,56 @@ +//============================================================================= +// +// File : bayer.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + * BAYER2RGB24 ROUTINE TAKEN FROM: + * + * Sonix SN9C101 based webcam basic I/F routines + * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp> + * + * 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. + */ + + +void bayer2rgb24 (unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT); diff --git a/src/kvilib/ext/avdevice/dummyvideodevice.cpp b/src/kvilib/ext/avdevice/dummyvideodevice.cpp new file mode 100644 index 000000000..6ad36ce19 --- /dev/null +++ b/src/kvilib/ext/avdevice/dummyvideodevice.cpp @@ -0,0 +1,222 @@ +//============================================================================= +// +// File : dummyvideodevice.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + dummyvideodevice.cpp - Dummy Video Device + + Copyright (c) 2009 by Alan Jones <skyphyr@gmail.com> + + Kopete (c) 2002-2009 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 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, see <http://www.gnu.org/licenses/>. * + ************************************************************************* +*/ + +#include "dummyvideodevice.h" +#include "videoinput.h" + +namespace Kopete { + +namespace AV { + +DummyVideoDevice::DummyVideoDevice() + { + //need to set a bunch of defaults for members + m_pixelformat = PIXELFORMAT_RGB32; + m_driver=VIDEODEV_DRIVER_NONE; + m_input.append(VideoInput()); + minwidth = 160; + maxwidth = 1280; + minheight = 120; + maxheight = 960; + //let's be opened by default seeing this is a fallback + opened = true; + setSize(320, 240); + } + +int DummyVideoDevice::open() + { + //wow - we always succeed in opening our dummy device + opened = true; + return EXIT_SUCCESS; + } + +bool DummyVideoDevice::isOpen() + { + //we'll track it just incase there is situations where it's expected not to be open + return opened; + } + +int DummyVideoDevice::checkDevice() + { + //again this is just incase anything ever relies on it failing when closed + if(isOpen()) + { + //need to check which, if any, of these need to be enabled for this to function properly + m_videocapture=false; + m_videochromakey=false; + m_videoscale=false; + m_videooverlay=false; + m_videoread=false; + m_videoasyncio=false; + m_videostream=false; + + m_driver=VIDEODEV_DRIVER_NONE; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } + +int DummyVideoDevice::initDevice() + { + //again this is just incase anything ever relies on it failing when closed + if(isOpen()) + { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } + +int DummyVideoDevice::setSize( int newwidth, int newheight) + { + if (isOpen()) + { + if(newwidth > maxwidth ) newwidth = maxwidth; + if(newheight > maxheight) newheight = maxheight; + if(newwidth < minwidth ) newwidth = minwidth; + if(newheight < minheight) newheight = minheight; + + currentwidth = newwidth; + currentheight = newheight; + + m_currentbuffer.width = currentwidth; + m_currentbuffer.height = currentheight; + m_currentbuffer.pixelformat = m_pixelformat; + + //let's fill the buffer up with something + //TODO: replace this with an .svg that says there is no camera available + m_currentbuffer.data.resize(currentwidth * currentheight * 4); + for (int i=0; i<m_currentbuffer.data.size(); i++) + { + m_currentbuffer.data[i] = 255; + } + + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } + +pixel_format DummyVideoDevice::setPixelFormat(pixel_format newformat) + { + pixel_format ret = PIXELFORMAT_NONE; + + if (newformat == PIXELFORMAT_RGB32) + { + m_pixelformat = newformat; + ret = m_pixelformat; + } + + return ret; + } + +int DummyVideoDevice::startCapturing() + { + //again this is just incase anything ever relies on it failing when closed + if(isOpen()) + { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } + +int DummyVideoDevice::getFrame() + { + //again this is just incase anything ever relies on it failing when closed + if(isOpen()) + { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } + +int DummyVideoDevice::getFrame(imagebuffer *imgbuffer) + { + if(imgbuffer) + { + imgbuffer->height = m_currentbuffer.height; + imgbuffer->width = m_currentbuffer.width; + imgbuffer->pixelformat = m_currentbuffer.pixelformat; + imgbuffer->data = m_currentbuffer.data; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } + +int DummyVideoDevice::getImage(QImage *qimage) + { + // do NOT delete qimage here, as it is received as a parameter + if (qimage->width() != width() || qimage->height() != height()) + *qimage = QImage(width(), height(), QImage::Format_RGB32); + + uchar *bits=qimage->bits(); + memcpy(bits,&m_currentbuffer.data[0], m_currentbuffer.data.size()); + + return EXIT_SUCCESS; + } + +int DummyVideoDevice::stopCapturing() + { + //again this is just incase anything ever relies on it failing when closed + if(isOpen()) + { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } + +int DummyVideoDevice::close() + { + //we always manage to close it too - amazing :) + opened = false; + return EXIT_SUCCESS; + } + +} + +} diff --git a/src/kvilib/ext/avdevice/dummyvideodevice.h b/src/kvilib/ext/avdevice/dummyvideodevice.h new file mode 100644 index 000000000..96498b661 --- /dev/null +++ b/src/kvilib/ext/avdevice/dummyvideodevice.h @@ -0,0 +1,96 @@ +//============================================================================= +// +// File : dummyvideodevice.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + dummyvideodevice.h - Kopete Dummy Video Device + + Copyright (c) 2009 by Alan Jones <skyphyr@gmail.com> + + Kopete (c) 2002-2009 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 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, see <http://www.gnu.org/licenses/>. * + ************************************************************************* +*/ + +#ifndef KOPETE_AVDUMMYVIDEODEVICE_H +#define KOPETE_AVDUMMYVIDEODEVICE_H + +#include "videodevice.h" + +namespace Kopete { + +namespace AV { + +/** +@author Kopete Developers +*/ + +class DummyVideoDevice : public VideoDevice +{ + +public: + DummyVideoDevice(); + virtual ~DummyVideoDevice() {} + + virtual int open(); + virtual bool isOpen(); + virtual int checkDevice(); + virtual int initDevice(); + + virtual int setSize( int newwidth, int newheight); + + virtual pixel_format setPixelFormat(pixel_format newformat); + + virtual int startCapturing(); + virtual int getFrame(); + virtual int getFrame(imagebuffer *imgbuffer); + virtual int getImage(QImage *qimage); + virtual int stopCapturing(); + virtual int close(); + + +private: + bool opened; +}; + +} + +} + +#endif diff --git a/src/kvilib/ext/avdevice/kopete_export.h b/src/kvilib/ext/avdevice/kopete_export.h new file mode 100644 index 000000000..029e74dc3 --- /dev/null +++ b/src/kvilib/ext/avdevice/kopete_export.h @@ -0,0 +1,4 @@ +#define KOPETE_EXPORT + +#define __linux__ 1 +#define ENABLE_AV
\ No newline at end of file diff --git a/src/kvilib/ext/avdevice/sonix_compress.cpp b/src/kvilib/ext/avdevice/sonix_compress.cpp new file mode 100644 index 000000000..653cb951b --- /dev/null +++ b/src/kvilib/ext/avdevice/sonix_compress.cpp @@ -0,0 +1,206 @@ +//============================================================================= +// +// File : sonix_compress.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original file had no copyright header. +//============================================================================= + +#include "sonix_compress.h" + +#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x)) + +typedef struct { + int is_abs; + int len; + int val; + int unk; +} code_table_t; + + +/* local storage */ +static code_table_t table[256]; +static int init_done = 0; + +/* global variable */ +int sonix_unknown = 0; + +/* + 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. + +*/ +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; + } + + sonix_unknown = 0; + 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. + +*/ +int sonix_decompress(int width, int height, unsigned char *inp, unsigned char *outp) +{ + int row, col; + int val; + int bitpos; + unsigned char code; + unsigned char *addr; + + if (!init_done) { + /* do sonix_decompress_init first! */ + return -1; + } + + 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; + + /* update code statistics */ + sonix_unknown += table[code].unk; + + /* 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 0; +} diff --git a/src/kvilib/ext/avdevice/sonix_compress.h b/src/kvilib/ext/avdevice/sonix_compress.h new file mode 100644 index 000000000..70058d657 --- /dev/null +++ b/src/kvilib/ext/avdevice/sonix_compress.h @@ -0,0 +1,34 @@ +//============================================================================= +// +// File : sonix_compress.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original file had no copyright header. +//============================================================================= + +// Call this function first (just once is needed), before calling sonix_decompress +void sonix_decompress_init(void); + +// decompresses data at inp until a full image of widthxheight has been written to outp +int sonix_decompress(int width, int height, unsigned char *inp, unsigned char *outp); + +// counter to detect presence of currently unknown huffman codes +extern int sonix_unknown; diff --git a/src/kvilib/ext/avdevice/videodevice.cpp b/src/kvilib/ext/avdevice/videodevice.cpp new file mode 100644 index 000000000..7116e2954 --- /dev/null +++ b/src/kvilib/ext/avdevice/videodevice.cpp @@ -0,0 +1,2976 @@ +//============================================================================= +// +// File : videodevice.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videodevice.cpp - Kopete Video Device Low-level Support + + Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro <taupter@gmail.com> + + Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#define ENABLE_AV + +#include <cstdlib> +#include <cerrno> +#include <cstring> + +#include <kdebug.h> + +#include "videoinput.h" +#include "videodevice.h" + +#include "bayer.h" +#include "sonix_compress.h" + +#define CLEAR(x) memset (&(x), 0, sizeof (x)) + +namespace Kopete { + +namespace AV { + +VideoDevice::VideoDevice() +{ +// kDebug() << "libkopete (avdevice): VideoDevice() called"; + descriptor = -1; + m_streambuffers = 0; + m_current_input = 0; +// kDebug() << "libkopete (avdevice): VideoDevice() exited successfuly"; +} + + +VideoDevice::~VideoDevice() +{ +} + +#ifdef V4L2_CAP_VIDEO_CAPTURE + +void VideoDevice::enumerateControls (void) +{ +// ----------------------------------------------------------------------------------------------------------------- +// This must turn up to be a proper method to check for controls' existence. + CLEAR (queryctrl); +// v4l2_queryctrl may zero the .id in some cases, even if the IOCTL returns EXIT_SUCCESS (tested with a bttv card, when testing for V4L2_CID_AUDIO_VOLUME). +// As of 6th Aug 2007, according to the V4L2 specification version 0.21, this behavior is undocumented, and the example 1-8 code found at +// http://www.linuxtv.org/downloads/video4linux/API/V4L2_API/spec/x519.htm fails because of this behavior with a bttv card. + + int currentid = V4L2_CID_BASE; + +kDebug() << "Checking CID controls"; + + for (currentid = V4L2_CID_BASE; currentid < V4L2_CID_LASTP1; currentid++) +//for (queryctrl.id = 9963776; queryctrl.id < 9963800; queryctrl.id++) + { + queryctrl.id = currentid; + if (0 == xioctl (VIDIOC_QUERYCTRL, &queryctrl)) + { + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + continue; + +kDebug() << " Control: " << QString::fromLocal8Bit((const char*)queryctrl.name) << " Values from " << queryctrl.minimum << " to " << queryctrl.maximum << " with steps of " << queryctrl.step << ". Default: " << queryctrl.default_value; + +// switch (queryctrl.type) +// { +// case V4L2_CTRL_TYPE_INTEGER : +// } + if (queryctrl.type == V4L2_CTRL_TYPE_MENU) + enumerateMenu (); + } + else + { + if (errno == EINVAL) + continue; + + perror ("VIDIOC_QUERYCTRL"); +// exit (EXIT_FAILURE); + } + } + +kDebug() << "Checking CID private controls"; + + for (currentid = V4L2_CID_PRIVATE_BASE;; currentid++) + { + queryctrl.id = currentid; + if ( 0 == xioctl (VIDIOC_QUERYCTRL, &queryctrl)) + { + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + continue; + +kDebug() << " Control: " << QString::fromLocal8Bit((const char*)queryctrl.name) << " Values from " << queryctrl.minimum << " to " << queryctrl.maximum << " with steps of " << queryctrl.step << ". Default: " << queryctrl.default_value; + + if (queryctrl.type == V4L2_CTRL_TYPE_MENU) + enumerateMenu (); + } + else + { + if (errno == EINVAL) + break; + + perror ("VIDIOC_QUERYCTRL"); +// exit (EXIT_FAILURE); + } + } +} + +void VideoDevice::enumerateMenu (void) +{ + kDebug() << " Menu items:"; + + memset (&querymenu, 0, sizeof (querymenu)); + querymenu.id = queryctrl.id; + + for (querymenu.index = queryctrl.minimum; querymenu.index <= (unsigned int) queryctrl.maximum; ++querymenu.index) + { + if (0 == xioctl (VIDIOC_QUERYMENU, &querymenu)) + { + kDebug() << " " << QString::fromLocal8Bit((const char*)querymenu.name); + } + else + { + perror ("VIDIOC_QUERYMENU"); + exit (EXIT_FAILURE); + } + } +} +#endif + +/*! + \fn VideoDevice::xioctl(int fd, int request, void *arg) + */ +int VideoDevice::xioctl(int request, void *arg) +{ + int r; + +#ifdef HAVE_LIBV4L2 + do r = v4l2_ioctl (descriptor, request, arg); +#else + do r = ioctl (descriptor, request, arg); +#endif + while (-1 == r && EINTR == errno); + return r; +} + +/*! + \fn VideoDevice::errnoReturn(const char* s) + */ +int VideoDevice::errnoReturn(const char* s) +{ + /// @todo implement me + fprintf (stderr, "%s error %d, %s\n",s, errno, strerror (errno)); + return EXIT_FAILURE; +} + +/*! + \fn VideoDevice::setFileName(QString name) + */ +int VideoDevice::setFileName(QString filename) +{ + /// @todo implement me + full_filename=filename; + return EXIT_SUCCESS; +} + +/*! + \fn VideoDevice::open() + */ +int VideoDevice::open() +{ + /// @todo implement me + + kDebug() << "called"; + if(-1 != descriptor) + { + kDebug() << "Device is already open"; + return EXIT_SUCCESS; + } +#ifdef HAVE_LIBV4L2 + descriptor = ::v4l2_open (QFile::encodeName(full_filename), O_RDWR, 0); +#else + descriptor = ::open (QFile::encodeName(full_filename), O_RDWR, 0); +#endif + if(isOpen()) + { + kDebug() << "File " << full_filename << " was opened successfuly"; + if(EXIT_FAILURE==checkDevice()) + { + kDebug() << "File " << full_filename << " could not be opened"; + close(); + return EXIT_FAILURE; + } + } + else + { + kDebug() << "Unable to open file " << full_filename << "Err: "<< errno; + return EXIT_FAILURE; + } + + initDevice(); + selectInput(m_current_input); + kDebug() << "exited successfuly"; + return EXIT_SUCCESS; +} + +bool VideoDevice::isOpen() +{ + if(-1 == descriptor) + { +// kDebug() << "VideoDevice::isOpen() File is not open"; + return false; + } +// kDebug() << "VideoDevice::isOpen() File is open"; + return true; +} + +int VideoDevice::checkDevice() +{ + kDebug() << "checkDevice() called."; + if(isOpen()) + { + m_videocapture=false; + m_videochromakey=false; + m_videoscale=false; + m_videooverlay=false; + m_videoread=false; + m_videoasyncio=false; + m_videostream=false; + + m_driver=VIDEODEV_DRIVER_NONE; +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + + CLEAR(V4L2_capabilities); + + if (-1 != xioctl (VIDIOC_QUERYCAP, &V4L2_capabilities)) + { + if (!(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_CAPTURE)) + { + kDebug() << "checkDevice(): " << full_filename << " is not a video capture device."; + m_driver = VIDEODEV_DRIVER_NONE; + return EXIT_FAILURE; + } + m_videocapture=true; + kDebug() << "checkDevice(): " << full_filename << " is a V4L2 device."; + m_driver = VIDEODEV_DRIVER_V4L2; + m_model=QString::fromLocal8Bit((const char*)V4L2_capabilities.card); + + +// Detect maximum and minimum resolution supported by the V4L2 device. VIDIOC_ENUM_FRAMESIZES is still experimental. + CLEAR (fmt); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (VIDIOC_G_FMT, &fmt)) + { + kDebug() << "VIDIOC_G_FMT failed (" << errno << ")."; + } + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = 32767; + fmt.fmt.pix.height = 32767; + fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (-1 == xioctl (VIDIOC_S_FMT, &fmt)) + { + kDebug() << "Detecting maximum size with VIDIOC_S_FMT failed (" << errno << ").Returned maxwidth: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; + // Note VIDIOC_S_FMT may change width and height. + } + else + { + maxwidth = fmt.fmt.pix.width; + maxheight = fmt.fmt.pix.height; + } + if (-1 == xioctl (VIDIOC_G_FMT, &fmt)) + { + kDebug() << "VIDIOC_G_FMT failed (" << errno << ")."; + } + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = 1; + fmt.fmt.pix.height = 1; + fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (-1 == xioctl (VIDIOC_S_FMT, &fmt)) + { + kDebug() << "Detecting minimum size with VIDIOC_S_FMT failed (" << errno << ").Returned maxwidth: " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; + // Note VIDIOC_S_FMT may change width and height. + } + else + { + minwidth = fmt.fmt.pix.width; + minheight = fmt.fmt.pix.height; + } + +// Buggy driver paranoia +/* min = fmt.fmt.pix.width * 2; + if (fmt.fmt.pix.bytesperline < min) + fmt.fmt.pix.bytesperline = min; + min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; + if (fmt.fmt.pix.sizeimage < min) + fmt.fmt.pix.sizeimage = min; + m_buffer_size=fmt.fmt.pix.sizeimage ;*/ + + int inputisok=EXIT_SUCCESS; + m_input.clear(); + for(unsigned int loop=0; inputisok==EXIT_SUCCESS; loop++) + { + struct v4l2_input videoinput; + CLEAR(videoinput); + videoinput.index = loop; + inputisok=xioctl(VIDIOC_ENUMINPUT, &videoinput); + if(inputisok==EXIT_SUCCESS) + { + VideoInput tempinput; + tempinput.name = QString::fromLocal8Bit((const char*)videoinput.name); + tempinput.hastuner = videoinput.type & V4L2_INPUT_TYPE_TUNER; +detectSignalStandards(); + tempinput.m_standards = videoinput.std; + m_input.push_back(tempinput); + kDebug() << "Input " << loop << ": " << tempinput.name << " (tuner: " << ((videoinput.type & V4L2_INPUT_TYPE_TUNER) != 0) << ")"; + if((videoinput.type & V4L2_INPUT_TYPE_TUNER) != 0) + { +// _tunerForInput[name] = desc.tuner; +// _isTuner = true; + } + else + { +// _tunerForInput[name] = -1; + } + } + } + } + else + { +// V4L-only drivers should return an EINVAL in errno to indicate they cannot handle V4L2 calls. Not every driver is compliant, so +// it will try the V4L api even if the error code is different than expected. + kDebug() << "checkDevice(): " << full_filename << " is not a V4L2 device."; + } + +#endif + + CLEAR(V4L_capabilities); + + if(m_driver==VIDEODEV_DRIVER_NONE) + { + kDebug() << "checkDevice(): " << full_filename << " Trying V4L API."; + if (-1 == xioctl (VIDIOCGCAP, &V4L_capabilities)) + { + perror ("ioctl (VIDIOCGCAP)"); + m_driver = VIDEODEV_DRIVER_NONE; + return EXIT_FAILURE; + } + else + { + kDebug() << full_filename << " is a V4L device."; + m_driver = VIDEODEV_DRIVER_V4L; + m_model=QString::fromLocal8Bit((const char*)V4L_capabilities.name); + if(V4L_capabilities.type & VID_TYPE_CAPTURE) + m_videocapture=true; + if(V4L_capabilities.type & VID_TYPE_CHROMAKEY) + m_videochromakey=true; + if(V4L_capabilities.type & VID_TYPE_SCALES) + m_videoscale=true; + if(V4L_capabilities.type & VID_TYPE_OVERLAY) + m_videooverlay=true; +// kDebug() << "libkopete (avdevice): Inputs : " << V4L_capabilities.channels; +// kDebug() << "libkopete (avdevice): Audios : " << V4L_capabilities.audios; + minwidth = V4L_capabilities.minwidth; + maxwidth = V4L_capabilities.maxwidth; + minheight = V4L_capabilities.minheight; + maxheight = V4L_capabilities.maxheight; + + + int inputisok=EXIT_SUCCESS; + m_input.clear(); + for(int loop=0; loop < V4L_capabilities.channels; loop++) + { + struct video_channel videoinput; + CLEAR(videoinput); + videoinput.channel = loop; + videoinput.norm = 1; + inputisok=xioctl(VIDIOCGCHAN, &videoinput); + if(inputisok==EXIT_SUCCESS) + { + VideoInput tempinput; + tempinput.name = QString::fromLocal8Bit((const char*)videoinput.name); + tempinput.hastuner=videoinput.flags & VIDEO_VC_TUNER; +// TODO: The routine to detect the appropriate video standards for V4L must be placed here + m_input.push_back(tempinput); +// kDebug() << "libkopete (avdevice): Input " << loop << ": " << tempinput.name << " (tuner: " << ((videoinput.flags & VIDEO_VC_TUNER) != 0) << ")"; +/* if((input.type & V4L2_INPUT_TYPE_TUNER) != 0) + { +// _tunerForInput[name] = desc.tuner; +// _isTuner = true; + } + else + { +// _tunerForInput[name] = -1; + } +*/ } + } + + } + } +#endif + m_name=m_model; // Take care about changing the name to be different from the model itself... + + detectPixelFormats(); +#ifdef V4L2_CAP_VIDEO_CAPTURE + enumerateControls(); +#endif +// TODO: Now we must execute the proper initialization according to the type of the driver. + kDebug() << "checkDevice() exited successfuly."; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + + +/*! + \fn VideoDevice::showDeviceCapabilities() + */ +int VideoDevice::showDeviceCapabilities() +{ + kDebug() << "showDeviceCapabilities() called."; + if(isOpen()) + { +/* kDebug() << "libkopete (avdevice): Driver: " << (const char*)V4L2_capabilities.driver << " " + << ((V4L2_capabilities.version>>16) & 0xFF) << "." + << ((V4L2_capabilities.version>> 8) & 0xFF) << "." + << ((V4L2_capabilities.version ) & 0xFF) << endl; + kDebug() << "libkopete (avdevice): Device: " << name; + kDebug() << "libkopete (avdevice): Capabilities:"; + if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_CAPTURE) + kDebug() << "libkopete (avdevice): Video capture"; + if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_OUTPUT) + kDebug() << "libkopete (avdevice): Video output"; + if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_OVERLAY) + kDebug() << "libkopete (avdevice): Video overlay"; + if(V4L2_capabilities.capabilities & V4L2_CAP_VBI_CAPTURE) + kDebug() << "libkopete (avdevice): VBI capture"; + if(V4L2_capabilities.capabilities & V4L2_CAP_VBI_OUTPUT) + kDebug() << "libkopete (avdevice): VBI output"; + if(V4L2_capabilities.capabilities & V4L2_CAP_RDS_CAPTURE) + kDebug() << "libkopete (avdevice): RDS capture"; + if(V4L2_capabilities.capabilities & V4L2_CAP_TUNER) + kDebug() << "libkopete (avdevice): Tuner IO"; + if(V4L2_capabilities.capabilities & V4L2_CAP_AUDIO) + kDebug() << "libkopete (avdevice): Audio IO"; +;*/ + kDebug() << "Device model: " << m_model; + kDebug() << "Device name : " << m_name; + kDebug() << "Capabilities:"; + if(canCapture()) + { + kDebug() << " Video capture"; + } + if(canRead()) + { + kDebug() << " Read"; + } + if(canAsyncIO()) + { + kDebug() << " Asynchronous input/output"; + } + if(canStream()) + { + kDebug() << " Streaming"; + } + if(canChromakey()) + { + kDebug() << " Video chromakey"; + } + if(canScale()) + { + kDebug() << " Video scales"; + } + if(canOverlay()) + { + kDebug() << " Video overlay"; + } +// kDebug() << "libkopete (avdevice): Audios : " << V4L_capabilities.audios; + kDebug() << " Max res: " << maxWidth() << " x " << maxHeight(); + kDebug() << " Min res: " << minWidth() << " x " << minHeight(); + kDebug() << " Inputs : " << inputs(); + for (int loop=0; loop < inputs(); loop++) + kDebug() << "Input " << loop << ": " << m_input[loop].name << " (tuner: " << m_input[loop].hastuner << ")"; + kDebug() << "showDeviceCapabilities() exited successfuly."; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +/*! + \fn VideoDevicePool::initDevice() + */ +int VideoDevice::initDevice() +{ + /// @todo implement me + kDebug() << "initDevice() started"; + if(-1 == descriptor) + { + kDebug() << "initDevice() Device is not open"; + return EXIT_FAILURE; + } + m_io_method = IO_METHOD_NONE; + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + if(V4L2_capabilities.capabilities & V4L2_CAP_READWRITE) + { + m_videoread=true; + m_io_method = IO_METHOD_READ; + kDebug() << " Read/Write interface"; + } + if(V4L2_capabilities.capabilities & V4L2_CAP_ASYNCIO) + { + m_videoasyncio=true; + kDebug() << " Async IO interface"; + } + if(V4L2_capabilities.capabilities & V4L2_CAP_STREAMING) + { + m_videostream=true; + m_io_method = IO_METHOD_MMAP; +// m_io_method = IO_METHOD_USERPTR; + kDebug() << " Streaming interface"; + } + if(m_io_method==IO_METHOD_NONE) + { + kDebug() << "initDevice() Found no suitable input/output method for " << full_filename; + return EXIT_FAILURE; + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + m_videoread=true; + m_io_method=IO_METHOD_READ; + if(-1 != xioctl(VIDIOCGFBUF,&V4L_videobuffer)) + { +// m_videostream=true; +// m_io_method = IO_METHOD_MMAP; + kDebug() << " Streaming interface"; + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + + break; + } + +// Select video input, video standard and tune here. +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (VIDIOC_CROPCAP, &cropcap)) + { // Errors ignored. + } + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c = cropcap.defrect; // reset to default + if (-1 == xioctl (VIDIOC_S_CROP, &crop)) + { + switch (errno) + { + case EINVAL: break; // Cropping not supported. + default: break; // Errors ignored. + } + } +#endif +#endif + + showDeviceCapabilities(); + kDebug() << "initDevice() exited successfuly"; + return EXIT_SUCCESS; +} + +int VideoDevice::inputs() +{ + return m_input.size(); +} + + +int VideoDevice::width() +{ + return currentwidth; +} + +int VideoDevice::minWidth() +{ + return minwidth; +} + +int VideoDevice::maxWidth() +{ + return maxwidth; +} + +int VideoDevice::height() +{ + return currentheight; +} + +int VideoDevice::minHeight() +{ + return minheight; +} + +int VideoDevice::maxHeight() +{ + return maxheight; +} + +int VideoDevice::setSize( int newwidth, int newheight) +{ +kDebug() << "setSize(" << newwidth << ", " << newheight << ") called."; + if(isOpen()) + { +// It should not be there. It must remain in a completely distict place, cause this method should not change the pixelformat. +// It shouldn't try to find a suitable pixel format this way. It should use values discovered by - detectPixelFormats() - to choose a valid one. + kDebug() << "Trying YUY422P"; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUV422P)) + { + kDebug() << "Device doesn't seem to support YUV422P format. Trying YUYV."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUYV)) + { + kDebug() << "Device doesn't seem to support YUYV format. Trying UYVY."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_UYVY)) + { + kDebug() << "Device doesn't seem to support UYVY format. Trying YUV420P."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUV420P)) + { + kDebug() << "Device doesn't seem to support YUV420P format. Trying RGB24."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_RGB24)) + { + kDebug() << "Device doesn't seem to support RGB24 format. Trying BGR24."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_BGR24)) + { + kDebug() << "Device doesn't seem to support RGB24 format. Trying RGB32."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_RGB32)) + { + kDebug() << "Device doesn't seem to support RGB32 format. Trying BGR32."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_BGR32)) + { + kDebug() << "Device doesn't seem to support BGR32 format. Trying SBGGR8."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_SBGGR8)) + { + kDebug() << "Device doesn't seem to support SBGGR8 format. Trying SN9C10X."; + if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_SN9C10X)) + { + kDebug() << "Device doesn't seem to support BGR32 format. Fallback to it is not yet implemented."; + } + } + } + } + } + } + } + } + } + } + + if(newwidth > maxwidth ) newwidth = maxwidth; + if(newheight > maxheight) newheight = maxheight; + if(newwidth < minwidth ) newwidth = minwidth; + if(newheight < minheight) newheight = minheight; + + currentwidth = newwidth; + currentheight = newheight; + +//kDebug() << "width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << width() << "x" << height(); +// Change resolution for the video device + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: +// CLEAR (fmt); + if (-1 == xioctl (VIDIOC_G_FMT, &fmt)) + { + kDebug() << "VIDIOC_G_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; + } + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = width(); + fmt.fmt.pix.height = height(); + fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (-1 == xioctl (VIDIOC_S_FMT, &fmt)) + { + kDebug() << "VIDIOC_S_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; + // Note VIDIOC_S_FMT may change width and height. + } + else + { +// Buggy driver paranoia. +kDebug() << "VIDIOC_S_FMT worked (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; + unsigned int min = fmt.fmt.pix.width * 2; + if (fmt.fmt.pix.bytesperline < min) + { + fmt.fmt.pix.bytesperline = min; + } + min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; + if (fmt.fmt.pix.sizeimage < min) + { + fmt.fmt.pix.sizeimage = min; + } + m_buffer_size=fmt.fmt.pix.sizeimage ; + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + { + struct video_window V4L_videowindow; + + if (xioctl (VIDIOCGWIN, &V4L_videowindow)== -1) + { + perror ("ioctl VIDIOCGWIN"); +// return (NULL); + } + V4L_videowindow.width = width(); + V4L_videowindow.height = height(); + V4L_videowindow.clipcount=0; + if (xioctl (VIDIOCSWIN, &V4L_videowindow)== -1) + { + perror ("ioctl VIDIOCSWIN"); +// return (NULL); + } +kDebug() << "------------- width: " << V4L_videowindow.width << " Height: " << V4L_videowindow.height << " Clipcount: " << V4L_videowindow.clipcount << " -----------------"; + +// kDebug() << "libkopete (avdevice): V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth; + +/* if(-1 == xioctl(VIDIOCGFBUF,&V4L_videobuffer)) + kDebug() << "libkopete (avdevice): VIDIOCGFBUF failed (" << errno << "): Device cannot stream";*/ + + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + m_buffer_size = width() * height() * pixelFormatDepth(m_pixelformat) / 8; +kDebug() << "------------------------- ------- -- m_buffer_size: " << m_buffer_size << " !!! -- ------- -----------------------------------------"; + + m_currentbuffer.pixelformat=m_pixelformat; + m_currentbuffer.data.resize(m_buffer_size); + + switch (m_io_method) + { + case IO_METHOD_NONE: break; + case IO_METHOD_READ: initRead (); break; + case IO_METHOD_MMAP: initMmap (); break; + case IO_METHOD_USERPTR: initUserptr (); break; + } + +kDebug() << "setSize(" << newwidth << ", " << newheight << ") exited successfuly."; + return EXIT_SUCCESS; + } +kDebug() << "setSize(" << newwidth << ", " << newheight << ") Device is not open."; + return EXIT_FAILURE; +} + + + + + + + + + + + + + +pixel_format VideoDevice::setPixelFormat(pixel_format newformat) +{ + pixel_format ret = PIXELFORMAT_NONE; +//kDebug() << "called."; +// Change the pixel format for the video device + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: +// CLEAR (fmt); + if (-1 == xioctl (VIDIOC_G_FMT, &fmt)) + { +// return errnoReturn ("VIDIOC_S_FMT"); +// kDebug() << "VIDIOC_G_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; + } + else + m_pixelformat = pixelFormatForPalette(fmt.fmt.pix.pixelformat); + + fmt.fmt.pix.pixelformat = pixelFormatCode(newformat); + if (-1 == xioctl (VIDIOC_S_FMT, &fmt)) + { +// kDebug() << "VIDIOC_S_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height; + } + else + { + if (fmt.fmt.pix.pixelformat == (unsigned int) pixelFormatCode(newformat)) // Thih "if" (not what is contained within) is a fix for a bug in sn9c102 driver. + { + m_pixelformat = newformat; + ret = m_pixelformat; + } + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + { + struct video_picture V4L_picture; + if(-1 == xioctl(VIDIOCGPICT, &V4L_picture)) + { + kDebug() << "VIDIOCGPICT failed (" << errno << ")."; + } +// kDebug() << "V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth; + V4L_picture.palette = pixelFormatCode(newformat); + V4L_picture.depth = pixelFormatDepth(newformat); + if(-1 == xioctl(VIDIOCSPICT,&V4L_picture)) + { +// kDebug() << "Device seems to not support " << pixelFormatName(newformat) << " format. Fallback to it is not yet implemented."; + } + + if(-1 == xioctl(VIDIOCGPICT, &V4L_picture)) + { + kDebug() << "VIDIOCGPICT failed (" << errno << ")."; + } + +// kDebug() << "V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth; + m_pixelformat=pixelFormatForPalette(V4L_picture.palette); + if (m_pixelformat == newformat) + ret = newformat; + + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + return ret; +} + + + + + + +/*! + \fn Kopete::AV::VideoDevice::currentInput() + */ +int VideoDevice::currentInput() +{ + /// @todo implement me + if(isOpen()) + { + return m_current_input; + } + return 0; +} + +/*! + \fn Kopete::AV::VideoDevice::selectInput(int input) + */ +int VideoDevice::selectInput(int newinput) +{ + /// @todo implement me + if(m_current_input >= inputs()) + return EXIT_FAILURE; + + if(isOpen()) + { + switch (m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + if (-1 == ioctl (descriptor, VIDIOC_S_INPUT, &newinput)) + { + perror ("VIDIOC_S_INPUT"); + return EXIT_FAILURE; + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + struct video_channel V4L_input; + V4L_input.channel=newinput; + V4L_input.norm=4; // Hey, it's plain wrong! It should be input's signal standard! + if (-1 == ioctl (descriptor, VIDIOCSCHAN, &V4L_input)) + { + perror ("ioctl (VIDIOCSCHAN)"); + return EXIT_FAILURE; + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + kDebug() << "Selected input " << newinput << " (" << m_input[newinput].name << ")"; + m_current_input = newinput; + setInputParameters(); + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +/*! + \fn Kopete::AV::VideoDevice::setInputParameters() + */ +int VideoDevice::setInputParameters() +{ + /// @todo implement me + if( (isOpen()) && (m_current_input < inputs() ) ) + { + setBrightness( getBrightness() ); + setContrast( getContrast() ); + setSaturation( getSaturation() ); + setWhiteness( getWhiteness() ); + setHue( getHue() ); + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +/*! + \fn VideoDevice::startCapturing() + */ +int VideoDevice::startCapturing() +{ + + kDebug() << "called."; + if(isOpen()) + { + switch (m_io_method) + { + case IO_METHOD_NONE: // Device cannot capture frames + return EXIT_FAILURE; + break; + case IO_METHOD_READ: // Nothing to do + break; + case IO_METHOD_MMAP: +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + { + unsigned int loop; + for (loop = 0; loop < m_streambuffers; ++loop) + { + struct v4l2_buffer buf; + CLEAR (buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = loop; + if (-1 == xioctl (VIDIOC_QBUF, &buf)) + return errnoReturn ("VIDIOC_QBUF"); + } + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (VIDIOC_STREAMON, &type)) + return errnoReturn ("VIDIOC_STREAMON"); + } +#endif +#endif + break; + case IO_METHOD_USERPTR: +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + { + unsigned int loop; + for (loop = 0; loop < m_streambuffers; ++loop) + { + struct v4l2_buffer buf; + CLEAR (buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_USERPTR; + buf.m.userptr = (unsigned long) m_rawbuffers[loop].start; + buf.length = m_rawbuffers[loop].length; + if (-1 == xioctl (VIDIOC_QBUF, &buf)) + return errnoReturn ("VIDIOC_QBUF"); + } + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (VIDIOC_STREAMON, &type)) + return errnoReturn ("VIDIOC_STREAMON"); + } +#endif +#endif + break; + } + + kDebug() << "exited successfuly."; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +/*! + \fn VideoDevice::getFrame() + */ +int VideoDevice::getFrame() +{ + /// @todo implement me + ssize_t bytesread; + +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + struct v4l2_buffer v4l2buffer; +#endif +#endif +// kDebug() << "getFrame() called."; + if(isOpen()) + { + switch (m_io_method) + { + case IO_METHOD_NONE: // Device cannot capture frames + return EXIT_FAILURE; + break; + case IO_METHOD_READ: +// kDebug() << "Using IO_METHOD_READ.File descriptor: " << descriptor << " Buffer address: " << &m_currentbuffer.data[0] << " Size: " << m_currentbuffer.data.size(); + if (m_currentbuffer.data.isEmpty()) + return EXIT_FAILURE; + +#ifdef HAVE_LIBV4L2 + bytesread = v4l2_read (descriptor, &m_currentbuffer.data[0], m_currentbuffer.data.size()); +#else + bytesread = read (descriptor, &m_currentbuffer.data[0], m_currentbuffer.data.size()); +#endif + if (-1 == bytesread) // must verify this point with ov511 driver. + { + kDebug() << "IO_METHOD_READ failed."; + switch (errno) + { + case EAGAIN: + return EXIT_FAILURE; + case EIO: /* Could ignore EIO, see spec. fall through */ + default: + return errnoReturn ("read"); + } + } + if((int)m_currentbuffer.data.size() < bytesread) + { + kDebug() << "IO_METHOD_READ returned less bytes (" << bytesread << ") than it was asked for (" << m_currentbuffer.data.size() <<")."; + } + break; + case IO_METHOD_MMAP: +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + CLEAR (v4l2buffer); + v4l2buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2buffer.memory = V4L2_MEMORY_MMAP; + if (-1 == xioctl (VIDIOC_DQBUF, &v4l2buffer)) + { + kDebug() << full_filename << " MMAPed getFrame failed."; + switch (errno) + { + case EAGAIN: + { + kDebug() << full_filename << " MMAPed getFrame failed: EAGAIN. Pointer: "; + return EXIT_FAILURE; + } + case EIO: /* Could ignore EIO, see spec. fall through */ + default: + return errnoReturn ("VIDIOC_DQBUF"); + } + } +/* if (v4l2buffer.index < m_streambuffers) + return EXIT_FAILURE;*/ //it was an assert() +// kDebug() << "m_rawbuffers[" << v4l2buffer.index << "].start: " << (void *)m_rawbuffers[v4l2buffer.index].start << " Size: " << m_currentbuffer.data.size(); + if (m_currentbuffer.data.isEmpty() || +// v4l2buffer.index < 0 || // is always false: v4l2buffer.index is unsigned + (uint) m_rawbuffers.size() <= v4l2buffer.index) + return EXIT_FAILURE; + + memcpy(&m_currentbuffer.data[0], m_rawbuffers[v4l2buffer.index].start, m_currentbuffer.data.size()); + if (-1 == xioctl (VIDIOC_QBUF, &v4l2buffer)) + return errnoReturn ("VIDIOC_QBUF"); +#endif +#endif + break; + case IO_METHOD_USERPTR: +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + { + unsigned int i; + CLEAR (v4l2buffer); + v4l2buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2buffer.memory = V4L2_MEMORY_USERPTR; + if (-1 == xioctl (VIDIOC_DQBUF, &v4l2buffer)) + { + switch (errno) + { + case EAGAIN: + return EXIT_FAILURE; + case EIO: /* Could ignore EIO, see spec. fall through */ + default: + return errnoReturn ("VIDIOC_DQBUF"); + } + } + if ((unsigned int) m_rawbuffers.size() < m_streambuffers) + return EXIT_FAILURE; + + for (i = 0; i < m_streambuffers; ++i) + if (v4l2buffer.m.userptr == (unsigned long) m_rawbuffers[i].start && v4l2buffer.length == m_rawbuffers[i].length) + break; + if (i < m_streambuffers) + return EXIT_FAILURE; + if (-1 == xioctl (VIDIOC_QBUF, &v4l2buffer)) + return errnoReturn ("VIDIOC_QBUF"); + } +#endif +#endif + break; + } +// kDebug() << "exited successfuly."; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +/*! + \fn VideoDevice::getFrame(imagebuffer *imgbuffer) + */ +int VideoDevice::getFrame(imagebuffer *imgbuffer) +{ + if(imgbuffer) + { + getFrame(); + imgbuffer->height = m_currentbuffer.height; + imgbuffer->width = m_currentbuffer.width; + imgbuffer->pixelformat = m_currentbuffer.pixelformat; + imgbuffer->data = m_currentbuffer.data; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +/*! + \fn Kopete::AV::VideoDevice::getImage(const QImage *qimage) + */ +int VideoDevice::getImage(QImage *qimage) +{ + /// @todo implement me + + // do NOT delete qimage here, as it is received as a parameter + if (qimage->width() != width() || qimage->height() != height()) + *qimage = QImage(width(), height(), QImage::Format_RGB32); + + if (!m_currentbuffer.data.size()) + { + //there is no data so if we continue something will try access it (as in bug 161536) and crash kopete + //perhaps we should look at having the interface reflect when the camera isn't available? as it thinks + //it is for some reason, though the data size seems to be an ok check + return EXIT_FAILURE; + } + + uchar *bits=qimage->bits(); +// kDebug() << "Capturing in " << pixelFormatName(m_currentbuffer.pixelformat); + switch(m_currentbuffer.pixelformat) + { + case PIXELFORMAT_NONE : break; + +// Packed RGB formats + case PIXELFORMAT_RGB332 : + { + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = (m_currentbuffer.data[step]>>5<<5)+(m_currentbuffer.data[step]>>5<<2)+(m_currentbuffer.data[step]>>6); + bits[loop+1] = (m_currentbuffer.data[step]>>2<<5)+(m_currentbuffer.data[step]<<3>>5<<2)+(m_currentbuffer.data[step]<<3>>6); + bits[loop+2] = (m_currentbuffer.data[step]<<6)+(m_currentbuffer.data[step]<<6>>2)+(m_currentbuffer.data[step]<<6>>4)+(m_currentbuffer.data[step]<<6>>6); + bits[loop+3] = 255; + step++; + } + } + break; + case PIXELFORMAT_RGB444 : break; + case PIXELFORMAT_RGB555 : break; + case PIXELFORMAT_RGB565 : + { + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = (m_currentbuffer.data[step]<<3)+(m_currentbuffer.data[step]<<3>>5); + bits[loop+1] = ((m_currentbuffer.data[step+1])<<5)|m_currentbuffer.data[step]>>5; + bits[loop+2] = ((m_currentbuffer.data[step+1])&248)+((m_currentbuffer.data[step+1])>>5); + bits[loop+3] = 255; + step+=2; + } + } + break; + case PIXELFORMAT_RGB555X: break; + case PIXELFORMAT_RGB565X: break; + case PIXELFORMAT_BGR24 : + { + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = m_currentbuffer.data[step+2]; + bits[loop+1] = m_currentbuffer.data[step+1]; + bits[loop+2] = m_currentbuffer.data[step]; + bits[loop+3] = 255; + step+=3; + } + } + break; + case PIXELFORMAT_RGB24 : + { + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = m_currentbuffer.data[step]; + bits[loop+1] = m_currentbuffer.data[step+1]; + bits[loop+2] = m_currentbuffer.data[step+2]; + bits[loop+3] = 255; + step+=3; + } + } + break; + case PIXELFORMAT_BGR32 : + { + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = m_currentbuffer.data[step+2]; + bits[loop+1] = m_currentbuffer.data[step+1]; + bits[loop+2] = m_currentbuffer.data[step]; + bits[loop+3] = m_currentbuffer.data[step+3]; + step+=4; + } + } + break; + case PIXELFORMAT_RGB32 : memcpy(bits,&m_currentbuffer.data[0], m_currentbuffer.data.size()); + break; + +// Bayer RGB format + case PIXELFORMAT_SBGGR8 : + { + unsigned char *d = (unsigned char *) malloc (width() * height() * 3); + bayer2rgb24(d, &m_currentbuffer.data.first(), width(), height()); + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = d[step+2]; + bits[loop+1] = d[step+1]; + bits[loop+2] = d[step]; + bits[loop+3] = 255; + step+=3; + } + free(d); + } + break; + +// YUV formats + case PIXELFORMAT_GREY : + { + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = m_currentbuffer.data[step]; + bits[loop+1] = m_currentbuffer.data[step]; + bits[loop+2] = m_currentbuffer.data[step]; + bits[loop+3] = 255; + step++; + } + } + break; + case PIXELFORMAT_YUYV: + case PIXELFORMAT_UYVY: + case PIXELFORMAT_YUV420P: + case PIXELFORMAT_YUV422P: + { + uchar *yptr, *cbptr, *crptr; + bool halfheight=false; + bool packed=false; +// Adjust algorythm to specific YUV data arrangements. + if (m_currentbuffer.pixelformat == PIXELFORMAT_YUV420P) + halfheight=true; + if (m_currentbuffer.pixelformat == PIXELFORMAT_YUYV) + { + yptr = &m_currentbuffer.data[0]; + cbptr = yptr + 1; + crptr = yptr + 3; + packed=true; + } + else if (m_currentbuffer.pixelformat == PIXELFORMAT_UYVY) + { + cbptr = &m_currentbuffer.data[0]; + yptr = cbptr + 1; + crptr = cbptr + 2; + packed=true; + } + else + { + yptr = &m_currentbuffer.data[0]; + cbptr = yptr + (width()*height()); + crptr = cbptr + (width()*height()/(halfheight ? 4:2)); + } + + for(int y=0; y<height(); y++) + { +// Decode scanline + for(int x=0; x<width(); x++) + { + int c,d,e; + + if (packed) + { + c = (yptr[x<<1])-16; + d = (cbptr[x>>1<<2])-128; + e = (crptr[x>>1<<2])-128; + } + else + { + c = (yptr[x])-16; + d = (cbptr[x>>1])-128; + e = (crptr[x>>1])-128; + } + + int r = (298 * c + 409 * e + 128)>>8; + int g = (298 * c - 100 * d - 208 * e + 128)>>8; + int b = (298 * c + 516 * d + 128)>>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; + + uint *p = (uint*)qimage->scanLine(y)+x; + *p = qRgba(r,g,b,255); + + } +// Jump to next line + if (packed) + { + yptr+=width()*2; + cbptr+=width()*2; + crptr+=width()*2; + } + else + { + yptr+=width(); + if (!halfheight || y&1) + { + cbptr+=width()/2; + crptr+=width()/2; + } + } + } + } + break; + +// Compressed formats + case PIXELFORMAT_JPEG : break; + case PIXELFORMAT_MPEG : break; + +// Reserved formats + case PIXELFORMAT_DV : break; + case PIXELFORMAT_ET61X251:break; + case PIXELFORMAT_HI240 : break; + case PIXELFORMAT_HM12 : break; + case PIXELFORMAT_MJPEG : break; + case PIXELFORMAT_PWC1 : break; + case PIXELFORMAT_PWC2 : break; + case PIXELFORMAT_SN9C10X: + { + unsigned char *s = new unsigned char [width() * height()]; + unsigned char *d = new unsigned char [width() * height() * 3]; + sonix_decompress_init(); + sonix_decompress(width(), height(), &m_currentbuffer.data.first(), s); + bayer2rgb24(d, s, width(), height()); + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = d[step+2]; + bits[loop+1] = d[step+1]; + bits[loop+2] = d[step]; + bits[loop+3] = 255; + step+=3; + } + delete[] s; + delete[] d; + } + case PIXELFORMAT_WNVA : break; + case PIXELFORMAT_YYUV : break; + } + +// Proccesses image for automatic Brightness/Contrast/Color correction + if (getAutoBrightnessContrast()||getAutoColorCorrection()) + { + unsigned long long R=0, G=0, B=0, A=0, global=0; + int Rmax=0, Gmax=0, Bmax=0, Amax=0, globalmax=0; + int Rmin=255, Gmin=255, Bmin=255, Amin=255, globalmin=255; + int Rrange=255, Grange=255, Brange=255; + +// Finds minimum and maximum intensity for each color component + for(unsigned int loop=0;loop < (unsigned int) qimage->numBytes();loop+=4) + { + R+=bits[loop]; + G+=bits[loop+1]; + B+=bits[loop+2]; +// A+=bits[loop+3]; + if (bits[loop] < Rmin) Rmin = bits[loop]; + if (bits[loop+1] < Gmin) Gmin = bits[loop+1]; + if (bits[loop+2] < Bmin) Bmin = bits[loop+2]; +// if (bits[loop+3] < Amin) Amin = bits[loop+3]; + if (bits[loop] > Rmax) Rmax = bits[loop]; + if (bits[loop+1] > Gmax) Gmax = bits[loop+1]; + if (bits[loop+2] > Bmax) Bmax = bits[loop+2]; +// if (bits[loop+3] > Amax) Amax = bits[loop+3]; + } + global = R + G + B; +// Finds overall minimum and maximum intensity + if (Rmin > Gmin) globalmin = Gmin; else globalmin = Rmin; if (Bmin < globalmin) globalmin = Bmin; + if (Rmax > Gmax) globalmax = Rmax; else globalmax = Gmax; if (Bmax > globalmax) globalmax = Bmax; +// If no color correction should be performed, simply level all the intensities so they're just the same. +// In fact color correction should use the R, G and B variables to detect color deviation and "bump up" the saturation, +// but it's computationally more expensive and the current way returns better results to the user. + if(!getAutoColorCorrection()) + { + Rmin = globalmin ; Rmax = globalmax; + Gmin = globalmin ; Gmax = globalmax; + Bmin = globalmin ; Bmax = globalmax; +// Amin = globalmin ; Amax = globalmax; + } +// Calculates ranges and prevent a division by zero later on. + Rrange = Rmax - Rmin; if (Rrange == 0) Rrange = 255; + Grange = Gmax - Gmin; if (Grange == 0) Grange = 255; + Brange = Bmax - Bmin; if (Brange == 0) Brange = 255; +// Arange = Amax - Amin; if (Arange == 0) Arange = 255; + + kDebug() << " R: " << R << " G: " << G << " B: " << B << " A: " << A << " global: " << global << + " Rmin: " << Rmin << " Gmin: " << Gmin << " Bmin: " << Bmin << " Amin: " << Amin << " globalmin: " << globalmin << + " Rmax: " << Rmax << " Gmax: " << Gmax << " Bmax: " << Bmax << " Amax: " << Amax << " globalmax: " << globalmax ; + + for(unsigned int loop=0;loop < (unsigned int) qimage->numBytes();loop+=4) + { + bits[loop] = (bits[loop] - Rmin) * 255 / (Rrange); + bits[loop+1] = (bits[loop+1] - Gmin) * 255 / (Grange); + bits[loop+2] = (bits[loop+2] - Bmin) * 255 / (Brange); +// bits[loop+3] = (bits[loop+3] - Amin) * 255 / (Arange); + } + } + return EXIT_SUCCESS; +} + +/*! + \fn VideoDevice::stopCapturing() + */ +int VideoDevice::stopCapturing() +{ + /// @todo implement me + kDebug() << "called."; + if(isOpen()) + { + switch (m_io_method) + { + case IO_METHOD_NONE: // Device cannot capture frames + return EXIT_FAILURE; + break; + case IO_METHOD_READ: // Nothing to do + break; + case IO_METHOD_MMAP: + case IO_METHOD_USERPTR: +#ifdef V4L2_CAP_VIDEO_CAPTURE + { + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl (VIDIOC_STREAMOFF, &type)) + return errnoReturn ("VIDIOC_STREAMOFF"); + + if (m_io_method == IO_METHOD_MMAP) + { + unsigned int loop; + for (loop = 0; loop < m_streambuffers; ++loop) + { +#ifdef HAVE_LIBV4L2 + if (v4l2_munmap(m_rawbuffers[loop].start,m_rawbuffers[loop].length) != 0) +#else + if (munmap(m_rawbuffers[loop].start,m_rawbuffers[loop].length) != 0) +#endif + { + kDebug() << "unable to munmap."; + } + } + } + } +#endif + break; + } + kDebug() << "exited successfuly."; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + + +/*! + \fn VideoDevice::close() + */ +int VideoDevice::close() +{ + /// @todo implement me + kDebug() << " called."; + if(isOpen()) + { + kDebug() << " Device is open. Trying to properly shutdown the device."; + stopCapturing(); +#ifdef HAVE_LIBV4L2 + int ret = ::v4l2_close(descriptor); +#else + int ret = ::close(descriptor); +#endif + kDebug() << "::close() returns " << ret; + } + descriptor = -1; + return EXIT_SUCCESS; +} + +float VideoDevice::getBrightness() +{ + if (m_current_input < m_input.size() ) + return m_input[m_current_input].getBrightness(); + else + return 0; +} + +float VideoDevice::setBrightness(float brightness) +{ + kDebug() << "(" << brightness << ") called."; + m_input[m_current_input].setBrightness(brightness); // Just to check bounds + + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + { + struct v4l2_queryctrl queryctrl; + struct v4l2_control control; + + CLEAR (queryctrl); + queryctrl.id = V4L2_CID_BRIGHTNESS; + + if (-1 == xioctl (VIDIOC_QUERYCTRL, &queryctrl)) + { + if (errno != EINVAL) + { + kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ")."; + } else + { + kDebug() << "Device doesn't support the Brightness control."; + } + } else + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + { + kDebug() << "Brightness control is disabled."; + } else + { + CLEAR (control); + control.id = V4L2_CID_BRIGHTNESS; + control.value = (__s32)((queryctrl.maximum - queryctrl.minimum)*getBrightness()); + control.value += queryctrl.minimum; + + if (-1 == xioctl (VIDIOC_S_CTRL, &control)) + { + kDebug() << "VIDIOC_S_CTRL failed (" << errno << ")."; + } + } + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + { + struct video_picture V4L_picture; + if(-1 == xioctl(VIDIOCGPICT, &V4L_picture)) + { + kDebug() << "VIDIOCGPICT failed (" << errno << ")."; + } + V4L_picture.brightness = uint(65535 * getBrightness()); + if(-1 == xioctl(VIDIOCSPICT,&V4L_picture)) + { + kDebug() << "Device seems to not support adjusting image brightness. Fallback to it is not yet implemented."; + } + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + return getBrightness(); +} + +float VideoDevice::getContrast() +{ + if (m_current_input < m_input.size() ) + return m_input[m_current_input].getContrast(); + else + return 0; +} + +float VideoDevice::setContrast(float contrast) +{ + kDebug() << "(" << contrast << ") called."; + m_input[m_current_input].setContrast(contrast); // Just to check bounds + + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + { + struct v4l2_queryctrl queryctrl; + struct v4l2_control control; + + CLEAR (queryctrl); + queryctrl.id = V4L2_CID_CONTRAST; + + if (-1 == xioctl (VIDIOC_QUERYCTRL, &queryctrl)) + { + if (errno != EINVAL) + { + kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ")."; + } else + { + kDebug() << "Device doesn't support the Contrast control."; + } + } else + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + { + kDebug() << "Contrast control is disabled."; + } else + { + CLEAR (control); + control.id = V4L2_CID_CONTRAST; + control.value = (__s32)((queryctrl.maximum - queryctrl.minimum)*getContrast()); + control.value += queryctrl.minimum; + + if (-1 == xioctl (VIDIOC_S_CTRL, &control)) + { + kDebug() << "VIDIOC_S_CTRL failed (" << errno << ")."; + } + } + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + { + struct video_picture V4L_picture; + if(-1 == xioctl(VIDIOCGPICT, &V4L_picture)) + { + kDebug() << "VIDIOCGPICT failed (" << errno << ")."; + } + V4L_picture.contrast = uint(65535*getContrast()); + if(-1 == xioctl(VIDIOCSPICT,&V4L_picture)) + { + kDebug() << "Device seems to not support adjusting image contrast. Fallback to it is not yet implemented."; + } + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + return getContrast(); +} + +float VideoDevice::getSaturation() +{ + if (m_current_input < m_input.size() ) + return m_input[m_current_input].getSaturation(); + else + return 0; +} + +float VideoDevice::setSaturation(float saturation) +{ + kDebug() << "(" << saturation << ") called."; + m_input[m_current_input].setSaturation(saturation); // Just to check bounds + + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + { + struct v4l2_queryctrl queryctrl; + struct v4l2_control control; + + CLEAR (queryctrl); + queryctrl.id = V4L2_CID_SATURATION; + + if (-1 == xioctl (VIDIOC_QUERYCTRL, &queryctrl)) + { + if (errno != EINVAL) + { + kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ")."; + } else + { + kDebug() << "Device doesn't support the Saturation control."; + } + } else + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + { + kDebug() << "Saturation control is disabled."; + } else + { + CLEAR (control); + control.id = V4L2_CID_SATURATION; + control.value = (__s32)((queryctrl.maximum - queryctrl.minimum)*getSaturation()); + control.value += queryctrl.minimum; + + if (-1 == xioctl (VIDIOC_S_CTRL, &control)) + { + kDebug() << "VIDIOC_S_CTRL failed (" << errno << ")."; + } + } + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + { + struct video_picture V4L_picture; + if(-1 == xioctl(VIDIOCGPICT, &V4L_picture)) + { + kDebug() << "VIDIOCGPICT failed (" << errno << ")."; + } + V4L_picture.colour = uint(65535*getSaturation()); + if(-1 == xioctl(VIDIOCSPICT,&V4L_picture)) + { + kDebug() << "Device seems to not support adjusting image saturation. Fallback to it is not yet implemented."; + } + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + return getSaturation(); +} + +float VideoDevice::getWhiteness() +{ + if (m_current_input < m_input.size() ) + return m_input[m_current_input].getWhiteness(); + else + return 0; +} + +float VideoDevice::setWhiteness(float whiteness) +{ + kDebug() << "(" << whiteness << ") called."; + m_input[m_current_input].setWhiteness(whiteness); // Just to check bounds + + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + { + struct v4l2_queryctrl queryctrl; + struct v4l2_control control; + + CLEAR (queryctrl); + queryctrl.id = V4L2_CID_WHITENESS; + + if (-1 == xioctl (VIDIOC_QUERYCTRL, &queryctrl)) + { + if (errno != EINVAL) + { + kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ")."; + } else + { + kDebug() << "Device doesn't support the Whiteness control."; + } + } else + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + { + kDebug() << "Whiteness control is disabled."; + } else + { + CLEAR (control); + control.id = V4L2_CID_WHITENESS; + control.value = (__s32)((queryctrl.maximum - queryctrl.minimum)*getWhiteness()); + control.value += queryctrl.minimum; + + if (-1 == xioctl (VIDIOC_S_CTRL, &control)) + { + kDebug() << "VIDIOC_S_CTRL failed (" << errno << ")."; + } + } + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + { + struct video_picture V4L_picture; + if(-1 == xioctl(VIDIOCGPICT, &V4L_picture)) + { + kDebug() << "VIDIOCGPICT failed (" << errno << ")."; + } + V4L_picture.whiteness = uint(65535*getWhiteness()); + if(-1 == xioctl(VIDIOCSPICT,&V4L_picture)) + { + kDebug() << "Device seems to not support adjusting white level. Fallback to it is not yet implemented."; + } + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + return getWhiteness(); +} + +float VideoDevice::getHue() +{ + if (m_current_input < m_input.size() ) + return m_input[m_current_input].getHue(); + else + return 0; +} + +float VideoDevice::setHue(float hue) +{ + kDebug() << "(" << hue << ") called."; + m_input[m_current_input].setHue(hue); // Just to check bounds + + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + { + struct v4l2_queryctrl queryctrl; + struct v4l2_control control; + + CLEAR (queryctrl); + queryctrl.id = V4L2_CID_HUE; + + if (-1 == xioctl (VIDIOC_QUERYCTRL, &queryctrl)) + { + if (errno != EINVAL) + { + kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ")."; + } else + { + kDebug() << "Device doesn't support the Hue control."; + } + } else + if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) + { + kDebug() << "Hue control is disabled."; + } else + { + CLEAR (control); + control.id = V4L2_CID_HUE; + control.value = (__s32)((queryctrl.maximum - queryctrl.minimum)*getHue()); + control.value += queryctrl.minimum; + + if (-1 == xioctl (VIDIOC_S_CTRL, &control)) + { + kDebug() << "VIDIOC_S_CTRL failed (" << errno << ")."; + } + } + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + { + struct video_picture V4L_picture; + if(-1 == xioctl(VIDIOCGPICT, &V4L_picture)) + { + kDebug() << "VIDIOCGPICT failed (" << errno << ")."; + } + V4L_picture.hue = uint(65535*getHue()); + if(-1 == xioctl(VIDIOCSPICT,&V4L_picture)) + { + kDebug() << "Device seems to not support adjusting image hue. Fallback to it is not yet implemented."; + } + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + return getHue(); +} + + +bool VideoDevice::getAutoBrightnessContrast() +{ + if (m_current_input < m_input.size() ) + return m_input[m_current_input].getAutoBrightnessContrast(); + else + return false; +} + +bool VideoDevice::setAutoBrightnessContrast(bool brightnesscontrast) +{ + kDebug() << "VideoDevice::setAutoBrightnessContrast(" << brightnesscontrast << ") called."; + if (m_current_input < m_input.size() ) + { + m_input[m_current_input].setAutoBrightnessContrast(brightnesscontrast); + return m_input[m_current_input].getAutoBrightnessContrast(); + } + else + return false; + +} + +bool VideoDevice::getAutoColorCorrection() +{ + if (m_current_input < m_input.size() ) + return m_input[m_current_input].getAutoColorCorrection(); + else + return false; +} + +bool VideoDevice::setAutoColorCorrection(bool colorcorrection) +{ + kDebug() << "VideoDevice::setAutoColorCorrection(" << colorcorrection << ") called."; + if (m_current_input < m_input.size() ) + { + m_input[m_current_input].setAutoColorCorrection(colorcorrection); + return m_input[m_current_input].getAutoColorCorrection(); + } + else + return false; +} + +bool VideoDevice::getImageAsMirror() +{ + if (m_current_input < m_input.size() ) + return m_input[m_current_input].getImageAsMirror(); + else + return false; +} + +bool VideoDevice::setImageAsMirror(bool imageasmirror) +{ + kDebug() << "VideoDevice::setImageAsMirror(" << imageasmirror << ") called."; + if (m_current_input < m_input.size() ) + { + m_input[m_current_input].setImageAsMirror(imageasmirror); + return m_input[m_current_input].getImageAsMirror(); + } + else + return false; +} + +pixel_format VideoDevice::pixelFormatForPalette( int palette ) +{ + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + switch(palette) + { + case 0 : return PIXELFORMAT_NONE; break; + +// Packed RGB formats + case V4L2_PIX_FMT_RGB332 : return PIXELFORMAT_RGB332; break; +#if defined( V4L2_PIX_FMT_RGB444 ) + case V4L2_PIX_FMT_RGB444 : return PIXELFORMAT_RGB444; break; +#endif + case V4L2_PIX_FMT_RGB555 : return PIXELFORMAT_RGB555; break; + case V4L2_PIX_FMT_RGB565 : return PIXELFORMAT_RGB565; break; + case V4L2_PIX_FMT_RGB555X : return PIXELFORMAT_RGB555X; break; + case V4L2_PIX_FMT_RGB565X : return PIXELFORMAT_RGB565X; break; + case V4L2_PIX_FMT_BGR24 : return PIXELFORMAT_BGR24; break; + case V4L2_PIX_FMT_RGB24 : return PIXELFORMAT_RGB24; break; + case V4L2_PIX_FMT_BGR32 : return PIXELFORMAT_BGR32; break; + case V4L2_PIX_FMT_RGB32 : return PIXELFORMAT_RGB32; break; + +// Bayer RGB format + case V4L2_PIX_FMT_SBGGR8 : return PIXELFORMAT_SBGGR8; break; + +// YUV formats + case V4L2_PIX_FMT_GREY : return PIXELFORMAT_GREY; break; + case V4L2_PIX_FMT_YUYV : return PIXELFORMAT_YUYV; break; + case V4L2_PIX_FMT_UYVY : return PIXELFORMAT_UYVY; break; + case V4L2_PIX_FMT_YUV420 : return PIXELFORMAT_YUV420P; break; + case V4L2_PIX_FMT_YUV422P : return PIXELFORMAT_YUV422P; break; + +// Compressed formats + case V4L2_PIX_FMT_JPEG : return PIXELFORMAT_JPEG; break; + case V4L2_PIX_FMT_MPEG : return PIXELFORMAT_MPEG; break; + +// Reserved formats + case V4L2_PIX_FMT_DV : return PIXELFORMAT_DV; break; + case V4L2_PIX_FMT_ET61X251 : return PIXELFORMAT_ET61X251; break; + case V4L2_PIX_FMT_HI240 : return PIXELFORMAT_HI240; break; +#if defined( V4L2_PIX_FMT_HM12 ) + case V4L2_PIX_FMT_HM12 : return PIXELFORMAT_HM12; break; +#endif + case V4L2_PIX_FMT_MJPEG : return PIXELFORMAT_MJPEG; break; + case V4L2_PIX_FMT_PWC1 : return PIXELFORMAT_PWC1; break; + case V4L2_PIX_FMT_PWC2 : return PIXELFORMAT_PWC2; break; + case V4L2_PIX_FMT_SN9C10X : return PIXELFORMAT_SN9C10X; break; + case V4L2_PIX_FMT_WNVA : return PIXELFORMAT_WNVA; break; + case V4L2_PIX_FMT_YYUV : return PIXELFORMAT_YYUV; break; + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + switch(palette) + { + case 0 : return PIXELFORMAT_NONE; break; + case VIDEO_PALETTE_GREY : return PIXELFORMAT_GREY; break; + case VIDEO_PALETTE_HI240 : return PIXELFORMAT_RGB332; break; + case VIDEO_PALETTE_RGB555 : return PIXELFORMAT_RGB555; break; + case VIDEO_PALETTE_RGB565 : return PIXELFORMAT_RGB565; break; + case VIDEO_PALETTE_RGB24 : return PIXELFORMAT_RGB24; break; + case VIDEO_PALETTE_RGB32 : return PIXELFORMAT_RGB32; break; + case VIDEO_PALETTE_YUYV : return PIXELFORMAT_YUYV; break; + case VIDEO_PALETTE_UYVY : return PIXELFORMAT_UYVY; break; + case VIDEO_PALETTE_YUV420 : + case VIDEO_PALETTE_YUV420P : return PIXELFORMAT_YUV420P; break; + case VIDEO_PALETTE_YUV422P : return PIXELFORMAT_YUV422P; break; + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + return PIXELFORMAT_NONE; break; + } + return PIXELFORMAT_NONE; +} + +int VideoDevice::pixelFormatCode(pixel_format pixelformat) +{ + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + switch(pixelformat) + { + case PIXELFORMAT_NONE : return 0; break; + +// Packed RGB formats + case PIXELFORMAT_RGB332 : return V4L2_PIX_FMT_RGB332; break; +#if defined( V4L2_PIX_FMT_RGB444 ) + case PIXELFORMAT_RGB444 : return V4L2_PIX_FMT_RGB444; break; +#endif + case PIXELFORMAT_RGB555 : return V4L2_PIX_FMT_RGB555; break; + case PIXELFORMAT_RGB565 : return V4L2_PIX_FMT_RGB565; break; + case PIXELFORMAT_RGB555X: return V4L2_PIX_FMT_RGB555X; break; + case PIXELFORMAT_RGB565X: return V4L2_PIX_FMT_RGB565X; break; + case PIXELFORMAT_BGR24 : return V4L2_PIX_FMT_BGR24; break; + case PIXELFORMAT_RGB24 : return V4L2_PIX_FMT_RGB24; break; + case PIXELFORMAT_BGR32 : return V4L2_PIX_FMT_BGR32; break; + case PIXELFORMAT_RGB32 : return V4L2_PIX_FMT_RGB32; break; + +// Bayer RGB format + case PIXELFORMAT_SBGGR8 : return V4L2_PIX_FMT_SBGGR8; break; + +// YUV formats + case PIXELFORMAT_GREY : return V4L2_PIX_FMT_GREY; break; + case PIXELFORMAT_YUYV : return V4L2_PIX_FMT_YUYV; break; + case PIXELFORMAT_UYVY : return V4L2_PIX_FMT_UYVY; break; + case PIXELFORMAT_YUV420P: return V4L2_PIX_FMT_YUV420; break; + case PIXELFORMAT_YUV422P: return V4L2_PIX_FMT_YUV422P; break; + +// Compressed formats + case PIXELFORMAT_JPEG : return V4L2_PIX_FMT_JPEG; break; + case PIXELFORMAT_MPEG : return V4L2_PIX_FMT_MPEG; break; + +// Reserved formats + case PIXELFORMAT_DV : return V4L2_PIX_FMT_DV; break; + case PIXELFORMAT_ET61X251:return V4L2_PIX_FMT_ET61X251;break; + case PIXELFORMAT_HI240 : return V4L2_PIX_FMT_HI240; break; +#if defined( V4L2_PIX_FMT_HM12 ) + case PIXELFORMAT_HM12 : return V4L2_PIX_FMT_HM12; break; +#endif + case PIXELFORMAT_MJPEG : return V4L2_PIX_FMT_MJPEG; break; + case PIXELFORMAT_PWC1 : return V4L2_PIX_FMT_PWC1; break; + case PIXELFORMAT_PWC2 : return V4L2_PIX_FMT_PWC2; break; + case PIXELFORMAT_SN9C10X: return V4L2_PIX_FMT_SN9C10X; break; + case PIXELFORMAT_WNVA : return V4L2_PIX_FMT_WNVA; break; + case PIXELFORMAT_YYUV : return V4L2_PIX_FMT_YYUV; break; + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + switch(pixelformat) + { + case PIXELFORMAT_NONE : return 0; break; + +// Packed RGB formats + case PIXELFORMAT_RGB332 : return VIDEO_PALETTE_HI240; break; + case PIXELFORMAT_RGB444 : return 0; break; + case PIXELFORMAT_RGB555 : return VIDEO_PALETTE_RGB555; break; + case PIXELFORMAT_RGB565 : return VIDEO_PALETTE_RGB565; break; + case PIXELFORMAT_RGB555X: return 0; break; + case PIXELFORMAT_RGB565X: return 0; break; + case PIXELFORMAT_BGR24 : return 0; break; + case PIXELFORMAT_RGB24 : return VIDEO_PALETTE_RGB24; break; + case PIXELFORMAT_BGR32 : return 0; break; + case PIXELFORMAT_RGB32 : return VIDEO_PALETTE_RGB32; break; + +// Bayer RGB format + case PIXELFORMAT_SBGGR8 : return 0; break; + +// YUV formats + case PIXELFORMAT_GREY : return VIDEO_PALETTE_GREY; break; + case PIXELFORMAT_YUYV : return VIDEO_PALETTE_YUYV; break; + case PIXELFORMAT_UYVY : return VIDEO_PALETTE_UYVY; break; + case PIXELFORMAT_YUV420P: return VIDEO_PALETTE_YUV420; break; + case PIXELFORMAT_YUV422P: return VIDEO_PALETTE_YUV422P; break; + +// Compressed formats + case PIXELFORMAT_JPEG : return 0; break; + case PIXELFORMAT_MPEG : return 0; break; + +// Reserved formats + case PIXELFORMAT_DV : return 0; break; + case PIXELFORMAT_ET61X251:return 0; break; + case PIXELFORMAT_HI240 : return VIDEO_PALETTE_HI240; break; + case PIXELFORMAT_HM12 : return 0; break; + case PIXELFORMAT_MJPEG : return 0; break; + case PIXELFORMAT_PWC1 : return 0; break; + case PIXELFORMAT_PWC2 : return 0; break; + case PIXELFORMAT_SN9C10X: return 0; break; + case PIXELFORMAT_WNVA : return 0; break; + case PIXELFORMAT_YYUV : return 0; break; + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + return PIXELFORMAT_NONE; break; + } + return PIXELFORMAT_NONE; +} + +int VideoDevice::pixelFormatDepth(pixel_format pixelformat) +{ + switch(pixelformat) + { + case PIXELFORMAT_NONE : return 0; break; + +// Packed RGB formats + case PIXELFORMAT_RGB332 : return 8; break; + case PIXELFORMAT_RGB444 : return 16; break; + case PIXELFORMAT_RGB555 : return 16; break; + case PIXELFORMAT_RGB565 : return 16; break; + case PIXELFORMAT_RGB555X: return 16; break; + case PIXELFORMAT_RGB565X: return 16; break; + case PIXELFORMAT_BGR24 : return 24; break; + case PIXELFORMAT_RGB24 : return 24; break; + case PIXELFORMAT_BGR32 : return 32; break; + case PIXELFORMAT_RGB32 : return 32; break; + +// Bayer RGB format + case PIXELFORMAT_SBGGR8 : return 0; break; + +// YUV formats + case PIXELFORMAT_GREY : return 8; break; + case PIXELFORMAT_YUYV : return 16; break; + case PIXELFORMAT_UYVY : return 16; break; + case PIXELFORMAT_YUV420P: return 16; break; + case PIXELFORMAT_YUV422P: return 16; break; + +// Compressed formats + case PIXELFORMAT_JPEG : return 0; break; + case PIXELFORMAT_MPEG : return 0; break; + +// Reserved formats + case PIXELFORMAT_DV : return 0; break; + case PIXELFORMAT_ET61X251:return 0; break; + case PIXELFORMAT_HI240 : return 8; break; + case PIXELFORMAT_HM12 : return 0; break; + case PIXELFORMAT_MJPEG : return 0; break; + case PIXELFORMAT_PWC1 : return 0; break; + case PIXELFORMAT_PWC2 : return 0; break; + case PIXELFORMAT_SN9C10X: return 0; break; + case PIXELFORMAT_WNVA : return 0; break; + case PIXELFORMAT_YYUV : return 0; break; + } + return 0; +} + +QString VideoDevice::pixelFormatName(pixel_format pixelformat) +{ + QString returnvalue; + returnvalue = "None"; + switch(pixelformat) + { + case PIXELFORMAT_NONE : returnvalue = "None"; break; + +// Packed RGB formats + case PIXELFORMAT_RGB332 : returnvalue = "8-bit RGB332"; break; + case PIXELFORMAT_RGB444 : returnvalue = "8-bit RGB444"; break; + case PIXELFORMAT_RGB555 : returnvalue = "16-bit RGB555"; break; + case PIXELFORMAT_RGB565 : returnvalue = "16-bit RGB565"; break; + case PIXELFORMAT_RGB555X: returnvalue = "16-bit RGB555X"; break; + case PIXELFORMAT_RGB565X: returnvalue = "16-bit RGB565X"; break; + case PIXELFORMAT_BGR24 : returnvalue = "24-bit BGR24"; break; + case PIXELFORMAT_RGB24 : returnvalue = "24-bit RGB24"; break; + case PIXELFORMAT_BGR32 : returnvalue = "32-bit BGR32"; break; + case PIXELFORMAT_RGB32 : returnvalue = "32-bit RGB32"; break; + +// Bayer RGB format + case PIXELFORMAT_SBGGR8 : returnvalue = "Bayer RGB format"; break; + +// YUV formats + case PIXELFORMAT_GREY : returnvalue = "8-bit Grayscale"; break; + case PIXELFORMAT_YUYV : returnvalue = "Packed YUV 4:2:2"; break; + case PIXELFORMAT_UYVY : returnvalue = "Packed YVU 4:2:2"; break; + case PIXELFORMAT_YUV420P: returnvalue = "Planar YUV 4:2:0"; break; + case PIXELFORMAT_YUV422P: returnvalue = "Planar YUV 4:2:2"; break; + + +// Compressed formats + case PIXELFORMAT_JPEG : returnvalue = "JPEG image"; break; + case PIXELFORMAT_MPEG : returnvalue = "MPEG stream"; break; + +// Reserved formats + case PIXELFORMAT_DV : returnvalue = "DV (unknown)"; break; + case PIXELFORMAT_ET61X251:returnvalue = "ET61X251"; break; + case PIXELFORMAT_HI240 : returnvalue = "8-bit HI240 (RGB332)"; break; + case PIXELFORMAT_HM12 : returnvalue = "Packed YUV 4:2:2"; break; + case PIXELFORMAT_MJPEG : returnvalue = "8-bit Grayscale"; break; + case PIXELFORMAT_PWC1 : returnvalue = "PWC1"; break; + case PIXELFORMAT_PWC2 : returnvalue = "PWC2"; break; + case PIXELFORMAT_SN9C10X: returnvalue = "SN9C102"; break; + case PIXELFORMAT_WNVA : returnvalue = "Winnov Videum"; break; + case PIXELFORMAT_YYUV : returnvalue = "YYUV (unknown)"; break; + } + return returnvalue; +} + +QString VideoDevice::pixelFormatName(int pixelformat) +{ + QString returnvalue; + returnvalue = "None"; + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + switch(pixelformat) + { + case 0 : returnvalue = pixelFormatName(PIXELFORMAT_NONE); break; + +// Packed RGB formats + case V4L2_PIX_FMT_RGB332 : returnvalue = pixelFormatName(PIXELFORMAT_RGB332); break; +#if defined( V4L2_PIX_FMT_RGB444 ) + case V4L2_PIX_FMT_RGB444 : returnvalue = pixelFormatName(PIXELFORMAT_RGB444); break; +#endif + case V4L2_PIX_FMT_RGB555 : returnvalue = pixelFormatName(PIXELFORMAT_RGB555); break; + case V4L2_PIX_FMT_RGB565 : returnvalue = pixelFormatName(PIXELFORMAT_RGB565); break; + case V4L2_PIX_FMT_RGB555X : returnvalue = pixelFormatName(PIXELFORMAT_RGB555X); break; + case V4L2_PIX_FMT_RGB565X : returnvalue = pixelFormatName(PIXELFORMAT_RGB565X); break; + case V4L2_PIX_FMT_BGR24 : returnvalue = pixelFormatName(PIXELFORMAT_BGR24); break; + case V4L2_PIX_FMT_RGB24 : returnvalue = pixelFormatName(PIXELFORMAT_RGB24); break; + case V4L2_PIX_FMT_BGR32 : returnvalue = pixelFormatName(PIXELFORMAT_BGR32); break; + case V4L2_PIX_FMT_RGB32 : returnvalue = pixelFormatName(PIXELFORMAT_RGB32); break; + +// Bayer RGB format + case V4L2_PIX_FMT_SBGGR8 : returnvalue = pixelFormatName(PIXELFORMAT_SBGGR8); break; + +// YUV formats + case V4L2_PIX_FMT_GREY : returnvalue = pixelFormatName(PIXELFORMAT_GREY); break; + case V4L2_PIX_FMT_YUYV : returnvalue = pixelFormatName(PIXELFORMAT_YUYV); break; + case V4L2_PIX_FMT_UYVY : returnvalue = pixelFormatName(PIXELFORMAT_UYVY); break; + case V4L2_PIX_FMT_YUV420 : returnvalue = pixelFormatName(PIXELFORMAT_YUV420P); break; + case V4L2_PIX_FMT_YUV422P : returnvalue = pixelFormatName(PIXELFORMAT_YUV422P); break; + +// Compressed formats + case V4L2_PIX_FMT_JPEG : returnvalue = pixelFormatName(PIXELFORMAT_JPEG); break; + case V4L2_PIX_FMT_MPEG : returnvalue = pixelFormatName(PIXELFORMAT_MPEG); break; + +// Reserved formats + case V4L2_PIX_FMT_DV : returnvalue = pixelFormatName(PIXELFORMAT_DV); break; + case V4L2_PIX_FMT_ET61X251 : returnvalue = pixelFormatName(PIXELFORMAT_ET61X251); break; + case V4L2_PIX_FMT_HI240 : returnvalue = pixelFormatName(PIXELFORMAT_HI240); break; +#if defined( V4L2_PIX_FMT_HM12 ) + case V4L2_PIX_FMT_HM12 : returnvalue = pixelFormatName(PIXELFORMAT_HM12); break; +#endif + case V4L2_PIX_FMT_MJPEG : returnvalue = pixelFormatName(PIXELFORMAT_MJPEG); break; + case V4L2_PIX_FMT_PWC1 : returnvalue = pixelFormatName(PIXELFORMAT_PWC1); break; + case V4L2_PIX_FMT_PWC2 : returnvalue = pixelFormatName(PIXELFORMAT_PWC2); break; + case V4L2_PIX_FMT_SN9C10X : returnvalue = pixelFormatName(PIXELFORMAT_SN9C10X); break; + case V4L2_PIX_FMT_WNVA : returnvalue = pixelFormatName(PIXELFORMAT_WNVA); break; + case V4L2_PIX_FMT_YYUV : returnvalue = pixelFormatName(PIXELFORMAT_YYUV); break; + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + switch(pixelformat) + { + case VIDEO_PALETTE_GREY : returnvalue = pixelFormatName(PIXELFORMAT_GREY); break; + case VIDEO_PALETTE_HI240 : returnvalue = pixelFormatName(PIXELFORMAT_RGB332); break; + case VIDEO_PALETTE_RGB555 : returnvalue = pixelFormatName(PIXELFORMAT_RGB555); break; + case VIDEO_PALETTE_RGB565 : returnvalue = pixelFormatName(PIXELFORMAT_RGB565); break; + case VIDEO_PALETTE_RGB24 : returnvalue = pixelFormatName(PIXELFORMAT_RGB24); break; + case VIDEO_PALETTE_RGB32 : returnvalue = pixelFormatName(PIXELFORMAT_RGB32); break; + case VIDEO_PALETTE_YUYV : returnvalue = pixelFormatName(PIXELFORMAT_YUYV); break; + case VIDEO_PALETTE_UYVY : returnvalue = pixelFormatName(PIXELFORMAT_UYVY); break; + case VIDEO_PALETTE_YUV420 : + case VIDEO_PALETTE_YUV420P : returnvalue = pixelFormatName(PIXELFORMAT_YUV420P); break; + case VIDEO_PALETTE_YUV422P : returnvalue = pixelFormatName(PIXELFORMAT_YUV422P); break; + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + return returnvalue; +} + +int VideoDevice::detectPixelFormats() +{ + int err = 0; + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + fmtdesc.index = 0; + fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + while ( err == 0 ) + { + if (-1 == xioctl (VIDIOC_ENUM_FMT, &fmtdesc)) +// if (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0 ) + { + perror("VIDIOC_ENUM_FMT"); + err = errno; + } + else + { + kDebug () << fmtdesc.pixelformat << " " << pixelFormatName(fmtdesc.pixelformat); // Need a cleanup. PixelFormatForPalette is a really bad name + fmtdesc.index++; + } + } +// break; +#endif + case VIDEODEV_DRIVER_V4L: +// TODO: THis thing can be used to detec what pixel formats are supported in a API-independent way, but V4L2 has VIDIOC_ENUM_PIXFMT. +// The correct thing to do is to isolate these calls and do a proper implementation for V4L and another for V4L2 when this thing will be migrated to a plugin architecture. + +// Packed RGB formats + kDebug() << "Supported pixel formats:"; + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_RGB332)) { kDebug() << pixelFormatName(PIXELFORMAT_RGB332); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_RGB444)) { kDebug() << pixelFormatName(PIXELFORMAT_RGB444); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_RGB555)) { kDebug() << pixelFormatName(PIXELFORMAT_RGB555); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_RGB565)) { kDebug() << pixelFormatName(PIXELFORMAT_RGB565); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_RGB555X)) { kDebug() << pixelFormatName(PIXELFORMAT_RGB555X); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_RGB565X)) { kDebug() << pixelFormatName(PIXELFORMAT_RGB565X); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_BGR24)) { kDebug() << pixelFormatName(PIXELFORMAT_BGR24); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_RGB24)) { kDebug() << pixelFormatName(PIXELFORMAT_RGB24); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_BGR32)) { kDebug() << pixelFormatName(PIXELFORMAT_BGR32); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_RGB32)) { kDebug() << pixelFormatName(PIXELFORMAT_RGB32); } + +// Bayer RGB format + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_SBGGR8)) { kDebug() << pixelFormatName(PIXELFORMAT_SBGGR8); } + +// YUV formats + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_GREY)) { kDebug() << pixelFormatName(PIXELFORMAT_GREY); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_YUYV)) { kDebug() << pixelFormatName(PIXELFORMAT_YUYV); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_UYVY)) { kDebug() << pixelFormatName(PIXELFORMAT_UYVY); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_YUV420P)) { kDebug() << pixelFormatName(PIXELFORMAT_YUV420P); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_YUV422P)) { kDebug() << pixelFormatName(PIXELFORMAT_YUV422P); } + +// Compressed formats + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_JPEG)) { kDebug() << pixelFormatName(PIXELFORMAT_JPEG); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_MPEG)) { kDebug() << pixelFormatName(PIXELFORMAT_MPEG); } + +// Reserved formats + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_DV)) { kDebug() << pixelFormatName(PIXELFORMAT_DV); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_ET61X251)) { kDebug() << pixelFormatName(PIXELFORMAT_ET61X251); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_HI240)) { kDebug() << pixelFormatName(PIXELFORMAT_HI240); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_HM12)) { kDebug() << pixelFormatName(PIXELFORMAT_HM12); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_MJPEG)) { kDebug() << pixelFormatName(PIXELFORMAT_MJPEG); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_PWC1)) { kDebug() << pixelFormatName(PIXELFORMAT_PWC1); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_PWC2)) { kDebug() << pixelFormatName(PIXELFORMAT_PWC2); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_SN9C10X)) { kDebug() << pixelFormatName(PIXELFORMAT_SN9C10X); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_WNVA)) { kDebug() << pixelFormatName(PIXELFORMAT_WNVA); } + if(PIXELFORMAT_NONE != setPixelFormat(PIXELFORMAT_YYUV)) { kDebug() << pixelFormatName(PIXELFORMAT_YYUV); } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + return PIXELFORMAT_NONE; break; + } + return PIXELFORMAT_NONE; +} + +__u64 VideoDevice::signalStandardCode(signal_standard standard) +{ + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + switch(standard) + { + case STANDARD_PAL_B : return V4L2_STD_PAL_B; break; + case STANDARD_PAL_B1 : return V4L2_STD_PAL_B1; break; + case STANDARD_PAL_G : return V4L2_STD_PAL_G; break; + case STANDARD_PAL_H : return V4L2_STD_PAL_H; break; + case STANDARD_PAL_I : return V4L2_STD_PAL_I; break; + case STANDARD_PAL_D : return V4L2_STD_PAL_D; break; + case STANDARD_PAL_D1 : return V4L2_STD_PAL_D1; break; + case STANDARD_PAL_K : return V4L2_STD_PAL_K; break; + + case STANDARD_PAL_M : return V4L2_STD_PAL_M; break; + case STANDARD_PAL_N : return V4L2_STD_PAL_N; break; + case STANDARD_PAL_Nc : return V4L2_STD_PAL_Nc; break; + case STANDARD_PAL_60 : return V4L2_STD_PAL_60; break; + + case STANDARD_NTSC_M : return V4L2_STD_NTSC_M; break; + case STANDARD_NTSC_M_JP : return V4L2_STD_NTSC_M_JP; break; + case STANDARD_NTSC_443 : return V4L2_STD_NTSC_443; break; + case STANDARD_NTSC_M_KR : return V4L2_STD_NTSC_M_KR; break; + + case STANDARD_SECAM_B : return V4L2_STD_SECAM_B; break; + case STANDARD_SECAM_D : return V4L2_STD_SECAM_D; break; + case STANDARD_SECAM_G : return V4L2_STD_SECAM_G; break; + case STANDARD_SECAM_H : return V4L2_STD_SECAM_H; break; + case STANDARD_SECAM_K : return V4L2_STD_SECAM_K; break; + case STANDARD_SECAM_K1 : return V4L2_STD_SECAM_K1; break; + case STANDARD_SECAM_L : return V4L2_STD_SECAM_L; break; + case STANDARD_SECAM_LC : return V4L2_STD_SECAM_LC; break; + + case STANDARD_ATSC_8_VSB: return V4L2_STD_ATSC_8_VSB; break; + case STANDARD_ATSC_16_VSB:return V4L2_STD_ATSC_16_VSB; break; + + case STANDARD_PAL_BG : return V4L2_STD_PAL_BG; break; + case STANDARD_PAL_DK : return V4L2_STD_PAL_DK; break; + case STANDARD_PAL : return V4L2_STD_PAL; break; + case STANDARD_NTSC : return V4L2_STD_NTSC; break; + case STANDARD_SECAM_DK : return V4L2_STD_SECAM_DK; break; + case STANDARD_SECAM : return V4L2_STD_SECAM; break; + + case STANDARD_MN : return V4L2_STD_MN; break; + case STANDARD_B : return V4L2_STD_B; break; + case STANDARD_GH : return V4L2_STD_GH; break; + case STANDARD_DK : return V4L2_STD_DK; break; + + case STANDARD_525_60 : return V4L2_STD_525_60; break; + case STANDARD_625_50 : return V4L2_STD_625_50; break; + case STANDARD_ATSC : return V4L2_STD_ATSC; break; + + case STANDARD_UNKNOWN : return V4L2_STD_UNKNOWN; break; + case STANDARD_ALL : return V4L2_STD_ALL; break; + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + switch(standard) + { + case STANDARD_PAL_B : return VIDEO_MODE_PAL; break; + case STANDARD_PAL_B1 : return VIDEO_MODE_PAL; break; + case STANDARD_PAL_G : return VIDEO_MODE_PAL; break; + case STANDARD_PAL_H : return VIDEO_MODE_PAL; break; + case STANDARD_PAL_I : return VIDEO_MODE_PAL; break; + case STANDARD_PAL_D : return VIDEO_MODE_PAL; break; + case STANDARD_PAL_D1 : return VIDEO_MODE_PAL; break; + case STANDARD_PAL_K : return VIDEO_MODE_PAL; break; + + case STANDARD_PAL_M : return 5; break; // Undocumented value found to be compatible with V4L bttv driver + case STANDARD_PAL_N : return 6; break; // Undocumented value found to be compatible with V4L bttv driver + case STANDARD_PAL_Nc : return 4; break; // Undocumented value found to be compatible with V4L bttv driver + case STANDARD_PAL_60 : return VIDEO_MODE_PAL; break; + + case STANDARD_NTSC_M : return VIDEO_MODE_NTSC; break; + case STANDARD_NTSC_M_JP : return 7; break; // Undocumented value found to be compatible with V4L bttv driver + case STANDARD_NTSC_443 : return VIDEO_MODE_NTSC; break; + case STANDARD_NTSC_M_KR : return VIDEO_MODE_NTSC; break; + + case STANDARD_SECAM_B : return VIDEO_MODE_SECAM; break; + case STANDARD_SECAM_D : return VIDEO_MODE_SECAM; break; + case STANDARD_SECAM_G : return VIDEO_MODE_SECAM; break; + case STANDARD_SECAM_H : return VIDEO_MODE_SECAM; break; + case STANDARD_SECAM_K : return VIDEO_MODE_SECAM; break; + case STANDARD_SECAM_K1 : return VIDEO_MODE_SECAM; break; + case STANDARD_SECAM_L : return VIDEO_MODE_SECAM; break; + case STANDARD_SECAM_LC : return VIDEO_MODE_SECAM; break; + + case STANDARD_ATSC_8_VSB: return VIDEO_MODE_AUTO; break; + case STANDARD_ATSC_16_VSB:return VIDEO_MODE_AUTO; break; + + case STANDARD_PAL_BG : return VIDEO_MODE_PAL; break; + case STANDARD_PAL_DK : return VIDEO_MODE_PAL; break; + case STANDARD_PAL : return VIDEO_MODE_PAL; break; + case STANDARD_NTSC : return VIDEO_MODE_NTSC; break; + case STANDARD_SECAM_DK : return VIDEO_MODE_SECAM; break; + case STANDARD_SECAM : return VIDEO_MODE_SECAM; break; + + case STANDARD_MN : return VIDEO_MODE_AUTO; break; + case STANDARD_B : return VIDEO_MODE_AUTO; break; + case STANDARD_GH : return VIDEO_MODE_AUTO; break; + case STANDARD_DK : return VIDEO_MODE_AUTO; break; + + case STANDARD_525_60 : return VIDEO_MODE_PAL; break; + case STANDARD_625_50 : return VIDEO_MODE_SECAM; break; + case STANDARD_ATSC : return VIDEO_MODE_AUTO; break; + + case STANDARD_UNKNOWN : return VIDEO_MODE_AUTO; break; + case STANDARD_ALL : return VIDEO_MODE_AUTO; break; + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + return STANDARD_UNKNOWN; break; + } + return STANDARD_UNKNOWN; +} + +QString VideoDevice::signalStandardName(signal_standard standard) +{ + QString returnvalue; + returnvalue = "None"; + switch(standard) + { + case STANDARD_PAL_B : returnvalue = "PAL-B"; break; + case STANDARD_PAL_B1 : returnvalue = "PAL-B1"; break; + case STANDARD_PAL_G : returnvalue = "PAL-G"; break; + case STANDARD_PAL_H : returnvalue = "PAL-H"; break; + case STANDARD_PAL_I : returnvalue = "PAL-I"; break; + case STANDARD_PAL_D : returnvalue = "PAL-D"; break; + case STANDARD_PAL_D1 : returnvalue = "PAL-D1"; break; + case STANDARD_PAL_K : returnvalue = "PAL-K"; break; + + case STANDARD_PAL_M : returnvalue = "PAL-M"; break; + case STANDARD_PAL_N : returnvalue = "PAL-N"; break; + case STANDARD_PAL_Nc : returnvalue = "PAL-Nc"; break; + case STANDARD_PAL_60 : returnvalue = "PAL-60"; break; + + case STANDARD_NTSC_M : returnvalue = "NTSC-M"; break; + case STANDARD_NTSC_M_JP : returnvalue = "NTSC-M(JP)"; break; + case STANDARD_NTSC_443 : returnvalue = "NTSC-443"; break; + case STANDARD_NTSC_M_KR : returnvalue = "NTSC-M(KR)"; break; + + case STANDARD_SECAM_B : returnvalue = "SECAM-B"; break; + case STANDARD_SECAM_D : returnvalue = "SECAM-D"; break; + case STANDARD_SECAM_G : returnvalue = "SECAM-G"; break; + case STANDARD_SECAM_H : returnvalue = "SECAM-H"; break; + case STANDARD_SECAM_K : returnvalue = "SECAM-K"; break; + case STANDARD_SECAM_K1 : returnvalue = "SECAM-K1"; break; + case STANDARD_SECAM_L : returnvalue = "SECAM-L"; break; + case STANDARD_SECAM_LC : returnvalue = "SECAM-LC"; break; + + case STANDARD_ATSC_8_VSB: returnvalue = "ATSC-8-VSB"; break; + case STANDARD_ATSC_16_VSB:returnvalue = "ATSC-16-VSB"; break; + + case STANDARD_PAL_BG : returnvalue = "PAL-BG"; break; + case STANDARD_PAL_DK : returnvalue = "PAL-DK"; break; + case STANDARD_PAL : returnvalue = "PAL"; break; + case STANDARD_NTSC : returnvalue = "NTSC"; break; + case STANDARD_SECAM_DK : returnvalue = "SECAM-DK"; break; + case STANDARD_SECAM : returnvalue = "SECAM"; break; + + case STANDARD_MN : returnvalue = "DK"; break; + case STANDARD_B : returnvalue = "B"; break; + case STANDARD_GH : returnvalue = "GH"; break; + case STANDARD_DK : returnvalue = "DK"; break; + + case STANDARD_525_60 : returnvalue = "525 lines 60Hz";break; + case STANDARD_625_50 : returnvalue = "625 lines 50Hz";break; + case STANDARD_ATSC : returnvalue = "ATSC"; break; + + case STANDARD_UNKNOWN : returnvalue = "Unknown"; break; + case STANDARD_ALL : returnvalue = "All"; break; + } + return returnvalue; +} + +QString VideoDevice::signalStandardName(int standard) +{ + QString returnvalue; + returnvalue = "None"; + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + switch(standard) + { + case V4L2_STD_PAL_B : returnvalue = signalStandardName(STANDARD_PAL_B); break; + case V4L2_STD_PAL_B1 : returnvalue = signalStandardName(STANDARD_PAL_B1); break; + case V4L2_STD_PAL_G : returnvalue = signalStandardName(STANDARD_PAL_G); break; + case V4L2_STD_PAL_H : returnvalue = signalStandardName(STANDARD_PAL_H); break; + case V4L2_STD_PAL_I : returnvalue = signalStandardName(STANDARD_PAL_I); break; + case V4L2_STD_PAL_D : returnvalue = signalStandardName(STANDARD_PAL_D); break; + case V4L2_STD_PAL_D1 : returnvalue = signalStandardName(STANDARD_PAL_D1); break; + case V4L2_STD_PAL_K : returnvalue = signalStandardName(STANDARD_PAL_K); break; + case V4L2_STD_PAL_M : returnvalue = signalStandardName(STANDARD_PAL_M); break; + case V4L2_STD_PAL_N : returnvalue = signalStandardName(STANDARD_PAL_N); break; + case V4L2_STD_PAL_Nc : returnvalue = signalStandardName(STANDARD_PAL_Nc); break; + case V4L2_STD_PAL_60 : returnvalue = signalStandardName(STANDARD_PAL_60); break; + case V4L2_STD_NTSC_M : returnvalue = signalStandardName(STANDARD_NTSC_M); break; + case V4L2_STD_NTSC_M_JP : returnvalue = signalStandardName(STANDARD_NTSC_M_JP); break; + case V4L2_STD_NTSC_443 : returnvalue = signalStandardName(STANDARD_NTSC_443); break; // Commented out because my videodev2.h header seems to not include this standard in struct __u64 v4l2_std_id + case V4L2_STD_NTSC_M_KR : returnvalue = signalStandardName(STANDARD_NTSC_M_KR); break; // Commented out because my videodev2.h header seems to not include this standard in struct __u64 v4l2_std_id + case V4L2_STD_SECAM_B : returnvalue = signalStandardName(STANDARD_SECAM_B); break; + case V4L2_STD_SECAM_D : returnvalue = signalStandardName(STANDARD_SECAM_D); break; + case V4L2_STD_SECAM_G : returnvalue = signalStandardName(STANDARD_SECAM_G); break; + case V4L2_STD_SECAM_H : returnvalue = signalStandardName(STANDARD_SECAM_H); break; + case V4L2_STD_SECAM_K : returnvalue = signalStandardName(STANDARD_SECAM_K); break; + case V4L2_STD_SECAM_K1 : returnvalue = signalStandardName(STANDARD_SECAM_K1); break; + case V4L2_STD_SECAM_L : returnvalue = signalStandardName(STANDARD_SECAM_L); break; + case V4L2_STD_SECAM_LC : returnvalue = signalStandardName(STANDARD_SECAM_LC); break; + + case V4L2_STD_ATSC_8_VSB: returnvalue = signalStandardName(STANDARD_ATSC_8_VSB);break; + case V4L2_STD_ATSC_16_VSB:returnvalue = signalStandardName(STANDARD_ATSC_16_VSB);break; + + case V4L2_STD_PAL_BG : returnvalue = signalStandardName(STANDARD_PAL_BG); break; + case V4L2_STD_PAL_DK : returnvalue = signalStandardName(STANDARD_PAL_DK); break; + case V4L2_STD_PAL : returnvalue = signalStandardName(STANDARD_PAL); break; + case V4L2_STD_NTSC : returnvalue = signalStandardName(STANDARD_NTSC); break; + case V4L2_STD_SECAM_DK : returnvalue = signalStandardName(STANDARD_SECAM_DK); break; + case V4L2_STD_SECAM : returnvalue = signalStandardName(STANDARD_SECAM); break; + + case V4L2_STD_MN : returnvalue = signalStandardName(STANDARD_MN); break; + case V4L2_STD_B : returnvalue = signalStandardName(STANDARD_B); break; + case V4L2_STD_GH : returnvalue = signalStandardName(STANDARD_GH); break; + case V4L2_STD_DK : returnvalue = signalStandardName(STANDARD_DK); break; + + case V4L2_STD_525_60 : returnvalue = signalStandardName(STANDARD_525_60); break; + case V4L2_STD_625_50 : returnvalue = signalStandardName(STANDARD_625_50); break; + case V4L2_STD_ATSC : returnvalue = signalStandardName(STANDARD_ATSC); break; + + case V4L2_STD_UNKNOWN : returnvalue = signalStandardName(STANDARD_UNKNOWN); break; + case V4L2_STD_ALL : returnvalue = signalStandardName(STANDARD_ALL); break; + } + break; +#endif + case VIDEODEV_DRIVER_V4L: + switch(standard) + { + case VIDEO_MODE_PAL : returnvalue = signalStandardName(STANDARD_PAL); break; + case VIDEO_MODE_NTSC : returnvalue = signalStandardName(STANDARD_NTSC); break; + case VIDEO_MODE_SECAM : returnvalue = signalStandardName(STANDARD_SECAM); break; + case VIDEO_MODE_AUTO : returnvalue = signalStandardName(STANDARD_ALL); break; // It must be disabled until I find a correct way to handle those non-standard bttv modes +// case VIDEO_MODE_PAL_Nc : returnvalue = signalStandardName(STANDARD_PAL_Nc); break; // Undocumented value found to be compatible with V4L bttv driver + case VIDEO_MODE_PAL_M : returnvalue = signalStandardName(STANDARD_PAL_M); break; // Undocumented value found to be compatible with V4L bttv driver + case VIDEO_MODE_PAL_N : returnvalue = signalStandardName(STANDARD_PAL_N); break; // Undocumented value found to be compatible with V4L bttv driver + case VIDEO_MODE_NTSC_JP : returnvalue = signalStandardName(STANDARD_NTSC_M_JP); break; // Undocumented value found to be compatible with V4L bttv driver + } + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + return returnvalue; +} + +/*! + \fn VideoDevice::detectSignalStandards() +// this must be done once for each _input_. + */ +int VideoDevice::detectSignalStandards() +{ + kDebug() << "called."; + if(isOpen()) + { + switch(m_driver) + { +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + case VIDEODEV_DRIVER_V4L2: + + + struct v4l2_input input; + struct v4l2_standard standard; + + memset (&input, 0, sizeof (input)); + + if (-1 == xioctl (VIDIOC_G_INPUT, &input.index)) { + perror ("VIDIOC_G_INPUT"); + return EXIT_FAILURE; + } + + if (-1 == xioctl (VIDIOC_ENUMINPUT, &input)) { + perror ("VIDIOC_ENUM_INPUT"); + return EXIT_FAILURE; + } + +// printf ("Current input %s supports:\n", input.name); + + memset (&standard, 0, sizeof (standard)); + standard.index = 0; + + while (0 == xioctl (VIDIOC_ENUMSTD, &standard)) { + if (standard.id & input.std) + { +// kDebug() << standard.name; + kDebug() << signalStandardName(standard.id) << " (" << standard.id << ")" << V4L2_STD_NTSC; + } + + standard.index++; + } + +/* EINVAL indicates the end of the enumeration, which cannot be + empty unless this device falls under the USB exception. */ + + if (errno != EINVAL || standard.index == 0) { + perror ("VIDIOC_ENUMSTD"); + return EXIT_FAILURE; + } + + + break; +#endif + case VIDEODEV_DRIVER_V4L: + break; +#endif + case VIDEODEV_DRIVER_NONE: + default: + break; + } + //FIXME: return a real value + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +/*! + \fn VideoDevice::initRead() + */ +int VideoDevice::initRead() +{ + /// @todo implement me + + kDebug() << "called."; + if(isOpen()) + { + m_rawbuffers.resize(1); + if (m_rawbuffers.size()==0) + { + fprintf (stderr, "Out of memory\n"); + return EXIT_FAILURE; + } + kDebug() << "m_buffer_size: " << m_buffer_size; + +// m_rawbuffers[0].pixelformat=m_pixelformat; + m_rawbuffers[0].length = m_buffer_size; + m_rawbuffers[0].start = (uchar *)malloc (m_buffer_size); + + if (!m_rawbuffers[0].start) + { + fprintf (stderr, "Out of memory\n"); + return EXIT_FAILURE; + } + kDebug() << "exited successfuly."; + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + + +/*! + \fn VideoDevice::initMmap() + */ +int VideoDevice::initMmap() +{ + /// @todo implement me +#define BUFFERS 2 + if(isOpen()) + { + kDebug() << full_filename << " Trying to MMAP"; +#ifdef V4L2_CAP_VIDEO_CAPTURE + struct v4l2_requestbuffers req; + + CLEAR (req); + + req.count = BUFFERS; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + + if (-1 == xioctl (VIDIOC_REQBUFS, &req)) + { + if (EINVAL == errno) + { + kDebug() << full_filename << " does not support memory mapping"; + return EXIT_FAILURE; + } + else + { + return errnoReturn ("VIDIOC_REQBUFS"); + } + } + + if (req.count < BUFFERS) + { + kDebug() << "Insufficient buffer memory on " << full_filename; + return EXIT_FAILURE; + } + + m_rawbuffers.resize(req.count); + + if (m_rawbuffers.size()==0) + { + kDebug() << "Out of memory"; + return EXIT_FAILURE; + } + + for (m_streambuffers = 0; m_streambuffers < req.count; ++m_streambuffers) + { + struct v4l2_buffer v4l2buffer; + + CLEAR (v4l2buffer); + + v4l2buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2buffer.memory = V4L2_MEMORY_MMAP; + v4l2buffer.index = m_streambuffers; + + if (-1 == xioctl (VIDIOC_QUERYBUF, &v4l2buffer)) + return errnoReturn ("VIDIOC_QUERYBUF"); + + m_rawbuffers[m_streambuffers].length = v4l2buffer.length; +#ifdef HAVE_LIBV4L2 + m_rawbuffers[m_streambuffers].start = (uchar *) v4l2_mmap (NULL /* start anywhere */, v4l2buffer.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, descriptor, v4l2buffer.m.offset); +#else + m_rawbuffers[m_streambuffers].start = (uchar *) mmap (NULL /* start anywhere */, v4l2buffer.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, descriptor, v4l2buffer.m.offset); +#endif + + if (MAP_FAILED == m_rawbuffers[m_streambuffers].start) + return errnoReturn ("mmap"); + } +#endif + m_currentbuffer.data.resize(m_rawbuffers[0].length); // Makes the imagesize.data buffer size equal to the rawbuffer size + kDebug() << full_filename << " m_currentbuffer.data.size(): " << m_currentbuffer.data.size(); + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + + +/*! + \fn VideoDevice::initUserptr() + */ +int VideoDevice::initUserptr() +{ + /// @todo implement me + if(isOpen()) + { +#ifdef V4L2_CAP_VIDEO_CAPTURE + struct v4l2_requestbuffers req; + + CLEAR (req); + + req.count = 2; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_USERPTR; + + if (-1 == xioctl (VIDIOC_REQBUFS, &req)) + { + if (EINVAL == errno) + { + kDebug() << full_filename << " does not support memory mapping"; + return EXIT_FAILURE; + } + else + { + return errnoReturn ("VIDIOC_REQBUFS"); + } + } + + m_rawbuffers.resize(4); + + if (m_rawbuffers.size()==0) + { + fprintf (stderr, "Out of memory\n"); + return EXIT_FAILURE; + } + + for (m_streambuffers = 0; m_streambuffers < 4; ++m_streambuffers) + { + m_rawbuffers[m_streambuffers].length = m_buffer_size; + m_rawbuffers[m_streambuffers].start = (uchar *) malloc (m_buffer_size); + + if (!m_rawbuffers[m_streambuffers].start) + { + kDebug() << "Out of memory"; + return EXIT_FAILURE; + } + } +#endif + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +bool VideoDevice::canCapture() +{ + return m_videocapture; +} + +bool VideoDevice::canChromakey() +{ + return m_videochromakey; +} + +bool VideoDevice::canScale() +{ + return m_videoscale; +} + +bool VideoDevice::canOverlay() +{ + return m_videooverlay; +} + +bool VideoDevice::canRead() +{ + return m_videoread; +} + +bool VideoDevice::canAsyncIO() +{ + return m_videoasyncio; +} + +bool VideoDevice::canStream() +{ + return m_videostream; +} + +void VideoDevice::setUdi( const QString & udi ) +{ + m_udi = udi; +} + +QString VideoDevice::udi() const +{ + return m_udi; +} + +} + +} diff --git a/src/kvilib/ext/avdevice/videodevice.h b/src/kvilib/ext/avdevice/videodevice.h new file mode 100644 index 000000000..20dcbc90f --- /dev/null +++ b/src/kvilib/ext/avdevice/videodevice.h @@ -0,0 +1,374 @@ +//============================================================================= +// +// File : videodevice.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videodevice.h - Kopete Video Device Low-level Support + + Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro <taupter@gmail.com> + + Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#define ENABLE_AV + +#ifndef KOPETE_AVVIDEODEVICELISTITEM_H +#define KOPETE_AVVIDEODEVICELISTITEM_H + +//#include <config-kopete.h> + +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> + +#if defined(__linux__) && defined(ENABLE_AV) + +#include <asm/types.h> +#undef __STRICT_ANSI__ +#ifndef __u64 //required by videodev.h +#define __u64 unsigned long long +#endif // __u64 +#ifndef __s64 //required by videodev.h +#define __s64 signed long long +#endif // __s64 + + +#ifndef pgoff_t +#define pgoff_t unsigned long +#endif + +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/videodev.h> +#define VIDEO_MODE_PAL_Nc 3 +#define VIDEO_MODE_PAL_M 4 +#define VIDEO_MODE_PAL_N 5 +#define VIDEO_MODE_NTSC_JP 6 +#define __STRICT_ANSI__ + +#ifdef HAVE_LIBV4L2 +#include <libv4l2.h> +#endif // HAVE_V4L2 + +#endif // __linux__ + +#include <qstring.h> +#include <qfile.h> +#include <qimage.h> +#include <q3valuevector.h> +#include <kcombobox.h> + +#include "videoinput.h" + +namespace Kopete { + +namespace AV { + +/** +@author Kopete Developers +*/ +typedef enum +{ + VIDEODEV_DRIVER_NONE +#if defined( __linux__) && defined(ENABLE_AV) + , + VIDEODEV_DRIVER_V4L +#ifdef V4L2_CAP_VIDEO_CAPTURE + , + VIDEODEV_DRIVER_V4L2 +#endif +#endif +} videodev_driver; + +typedef enum +{ +// Packed RGB formats + PIXELFORMAT_NONE = 0, + PIXELFORMAT_GREY = (1 << 0), + PIXELFORMAT_RGB332 = (1 << 1), + PIXELFORMAT_RGB444 = (1 << 2), + PIXELFORMAT_RGB555 = (1 << 3), + PIXELFORMAT_RGB565 = (1 << 4), + PIXELFORMAT_RGB555X = (1 << 5), + PIXELFORMAT_RGB565X = (1 << 6), + PIXELFORMAT_BGR24 = (1 << 7), + PIXELFORMAT_RGB24 = (1 << 8), + PIXELFORMAT_BGR32 = (1 << 9), + PIXELFORMAT_RGB32 = (1 << 10), + +// Bayer RGB format + PIXELFORMAT_SBGGR8 = (1 << 11), + +// YUV formats + PIXELFORMAT_YUYV = (1 << 12), + PIXELFORMAT_UYVY = (1 << 13), + PIXELFORMAT_YUV420P = (1 << 14), + PIXELFORMAT_YUV422P = (1 << 15), + +// Compressed formats + PIXELFORMAT_JPEG = (1 << 16), + PIXELFORMAT_MPEG = (1 << 17), + +// Reserved formats + PIXELFORMAT_DV = (1 << 18), + PIXELFORMAT_ET61X251 = (1 << 19), + PIXELFORMAT_HI240 = (1 << 20), + PIXELFORMAT_HM12 = (1 << 21), + PIXELFORMAT_MJPEG = (1 << 22), + PIXELFORMAT_PWC1 = (1 << 23), + PIXELFORMAT_PWC2 = (1 << 24), + PIXELFORMAT_SN9C10X = (1 << 25), + PIXELFORMAT_WNVA = (1 << 26), + PIXELFORMAT_YYUV = (1 << 27) + +// PIXELFORMAT_ALL = 0x00003FFF +} pixel_format; + +typedef enum +{ +// One bit for each + STANDARD_PAL_B = (1 << 0), + STANDARD_PAL_B1 = (1 << 1), + STANDARD_PAL_G = (1 << 2), + STANDARD_PAL_H = (1 << 3), + STANDARD_PAL_I = (1 << 4), + STANDARD_PAL_D = (1 << 5), + STANDARD_PAL_D1 = (1 << 6), + STANDARD_PAL_K = (1 << 7), + + STANDARD_PAL_M = (1 << 8), + STANDARD_PAL_N = (1 << 9), + STANDARD_PAL_Nc = (1 << 10), + STANDARD_PAL_60 = (1 << 11), +// STANDARD_PAL_60 is a hybrid standard with 525 lines, 60 Hz refresh rate, and PAL color modulation with a 4.43 MHz color subcarrier. Some PAL video recorders can play back NTSC tapes in this mode for display on a 50/60 Hz agnostic PAL TV. + + STANDARD_NTSC_M = (1 << 12), + STANDARD_NTSC_M_JP = (1 << 13), + STANDARD_NTSC_443 = (1 << 14), +// STANDARD_NTSC_443 is a hybrid standard with 525 lines, 60 Hz refresh rate, and NTSC color modulation with a 4.43 MHz color subcarrier. + STANDARD_NTSC_M_KR = (1 << 15), + + STANDARD_SECAM_B = (1 << 16), + STANDARD_SECAM_D = (1 << 17), + STANDARD_SECAM_G = (1 << 18), + STANDARD_SECAM_H = (1 << 19), + STANDARD_SECAM_K = (1 << 20), + STANDARD_SECAM_K1 = (1 << 21), + STANDARD_SECAM_L = (1 << 22), + STANDARD_SECAM_LC = (1 << 23), + +// ATSC/HDTV + STANDARD_ATSC_8_VSB = (1 << 24), + STANDARD_ATSC_16_VSB = (1 << 25), + +// Some common needed stuff + STANDARD_PAL_BG = ( STANDARD_PAL_B | STANDARD_PAL_B1 | STANDARD_PAL_G ), + STANDARD_PAL_DK = ( STANDARD_PAL_D | STANDARD_PAL_D1 | STANDARD_PAL_K ), + STANDARD_PAL = ( STANDARD_PAL_BG | STANDARD_PAL_DK | STANDARD_PAL_H | STANDARD_PAL_I ), + STANDARD_NTSC = ( STANDARD_NTSC_M | STANDARD_NTSC_M_JP| STANDARD_NTSC_M_KR ), + STANDARD_SECAM_DK = ( STANDARD_SECAM_D | STANDARD_SECAM_K | STANDARD_SECAM_K1 ), + STANDARD_SECAM = ( STANDARD_SECAM_B | STANDARD_SECAM_G | STANDARD_SECAM_H | STANDARD_SECAM_DK | STANDARD_SECAM_L | STANDARD_SECAM_LC ), + +// some merged standards */ + STANDARD_MN = ( STANDARD_PAL_M | STANDARD_PAL_N | STANDARD_PAL_Nc | STANDARD_NTSC ), + STANDARD_B = ( STANDARD_PAL_B | STANDARD_PAL_B1 | STANDARD_SECAM_B ), + STANDARD_GH = ( STANDARD_PAL_G | STANDARD_PAL_H | STANDARD_SECAM_G | STANDARD_SECAM_H ), + STANDARD_DK = ( STANDARD_PAL_DK | STANDARD_SECAM_DK ), + + STANDARD_525_60 = ( STANDARD_PAL_M | STANDARD_PAL_60 | STANDARD_NTSC | STANDARD_NTSC_443), + STANDARD_625_50 = ( STANDARD_PAL | STANDARD_PAL_N | STANDARD_PAL_Nc | STANDARD_SECAM), + STANDARD_ATSC = ( STANDARD_ATSC_8_VSB | STANDARD_ATSC_16_VSB ), + + STANDARD_UNKNOWN = 0, + STANDARD_ALL = ( STANDARD_525_60 | STANDARD_625_50) +} signal_standard; + + +typedef enum +{ + IO_METHOD_NONE, + IO_METHOD_READ, + IO_METHOD_MMAP, + IO_METHOD_USERPTR +} io_method; + +struct imagebuffer +{ + int height; + int width; + pixel_format pixelformat; + QVector <uchar> data; // maybe it should be a rawbuffer instead of it? It could make us avoid a memory copy +}; +struct rawbuffer // raw buffer +{ + uchar * start; + size_t length; +}; + + +class VideoDevice{ +public: + VideoDevice(); + virtual ~VideoDevice(); + int setFileName(QString filename); + virtual int open(); + virtual bool isOpen(); + virtual int checkDevice(); + int showDeviceCapabilities(); + virtual int initDevice(); + int inputs(); + int width(); + int minWidth(); + int maxWidth(); + int height(); + int minHeight(); + int maxHeight(); + virtual int setSize( int newwidth, int newheight); + + virtual pixel_format setPixelFormat(pixel_format newformat); + int pixelFormatCode(pixel_format pixelformat); + pixel_format pixelFormatForPalette( int palette ); + int pixelFormatDepth(pixel_format pixelformat); + QString pixelFormatName(pixel_format pixelformat); + QString pixelFormatName(int pixelformat); + int detectPixelFormats(); + + __u64 signalStandardCode(signal_standard standard); + QString signalStandardName(signal_standard standard); + QString signalStandardName(int standard); + int detectSignalStandards(); + + int currentInput(); + int selectInput(int input); + int setInputParameters(); + virtual int startCapturing(); + virtual int getFrame(); + virtual int getFrame(imagebuffer *imgbuffer); + virtual int getImage(QImage *qimage); + virtual int stopCapturing(); + virtual int close(); + + float getBrightness(); + float setBrightness(float brightness); + float getContrast(); + float setContrast(float contrast); + float getSaturation(); + float setSaturation(float saturation); + float getWhiteness(); + float setWhiteness(float whiteness); + float getHue(); + float setHue(float Hue); + + bool getAutoBrightnessContrast(); + bool setAutoBrightnessContrast(bool brightnesscontrast); + bool getAutoColorCorrection(); + bool setAutoColorCorrection(bool colorcorrection); + bool getImageAsMirror(); + bool setImageAsMirror(bool imageasmirror); + + bool canCapture(); + bool canChromakey(); + bool canScale(); + bool canOverlay(); + bool canRead(); + bool canAsyncIO(); + bool canStream(); + + void setUdi( const QString & ); + QString udi() const; + QString m_model; + QString m_name; + size_t m_modelindex; // Defines what's the number of a device when more than 1 device of a given model is present; + QString full_filename; + videodev_driver m_driver; + int descriptor; + +//protected: +#if defined(__linux__) && defined(ENABLE_AV) +#ifdef V4L2_CAP_VIDEO_CAPTURE + struct v4l2_capability V4L2_capabilities; + struct v4l2_cropcap cropcap; + struct v4l2_crop crop; + struct v4l2_format fmt; + struct v4l2_fmtdesc fmtdesc; // Not sure if it must be here or inside detectPixelFormats(). Should inve +// struct v4l2_input m_input; + struct v4l2_queryctrl queryctrl; + struct v4l2_querymenu querymenu; + void enumerateControls (void); + void enumerateMenu (void); +#endif + struct video_capability V4L_capabilities; + struct video_buffer V4L_videobuffer; +#endif + QVector<Kopete::AV::VideoInput> m_input; +// QFile file; +protected: + int currentwidth, minwidth, maxwidth, currentheight, minheight, maxheight; + + QVector<rawbuffer> m_rawbuffers; + unsigned int m_streambuffers; + imagebuffer m_currentbuffer; + int m_buffer_size; + + int m_current_input; + pixel_format m_pixelformat; + + io_method m_io_method; + bool m_videocapture; + bool m_videochromakey; + bool m_videoscale; + bool m_videooverlay; + bool m_videoread; + bool m_videoasyncio; + bool m_videostream; + + int xioctl(int request, void *arg); + int errnoReturn(const char* s); + int initRead(); + int initMmap(); + int initUserptr(); + + QString m_udi; +}; + +} + +} + +#endif diff --git a/src/kvilib/ext/avdevice/videodevicemodelpool.cpp b/src/kvilib/ext/avdevice/videodevicemodelpool.cpp new file mode 100644 index 000000000..3333beaae --- /dev/null +++ b/src/kvilib/ext/avdevice/videodevicemodelpool.cpp @@ -0,0 +1,94 @@ +//============================================================================= +// +// File : videodevicepool.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videodevicepool.cpp - Kopete Multiple Video Device handler Class + + Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro <taupter@gmail.com> + + Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#include "videodevicemodelpool.h" + +namespace Kopete { + +namespace AV { + +VideoDeviceModelPool::VideoDeviceModelPool() +{ +} + + +VideoDeviceModelPool::~VideoDeviceModelPool() +{ +} + +void VideoDeviceModelPool::clear() +{ + m_devicemodel.clear(); +} + +size_t VideoDeviceModelPool::size() +{ + return m_devicemodel.size(); +} + +size_t VideoDeviceModelPool::addModel( QString newmodel ) +{ + VideoDeviceModel newdevicemodel; + newdevicemodel.model=newmodel; + newdevicemodel.count=0; + + if(m_devicemodel.size()) + { + for ( int loop = 0 ; loop < m_devicemodel.size(); loop++) + if (newmodel == m_devicemodel[loop].model) + { + kDebug() << "Model " << newmodel << " already exists."; + m_devicemodel[loop].count++; + return m_devicemodel[loop].count; + } + } + m_devicemodel.push_back(newdevicemodel); + m_devicemodel[m_devicemodel.size()-1].model = newmodel; + m_devicemodel[m_devicemodel.size()-1].count = 0; + return 0; +} + + +} + +} diff --git a/src/kvilib/ext/avdevice/videodevicemodelpool.h b/src/kvilib/ext/avdevice/videodevicemodelpool.h new file mode 100644 index 000000000..56ede1a16 --- /dev/null +++ b/src/kvilib/ext/avdevice/videodevicemodelpool.h @@ -0,0 +1,79 @@ +//============================================================================= +// +// File : videodevicepool.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videodevicepool.h - Kopete Multiple Video Device handler Class + + Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro <taupter@gmail.com> + + Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#ifndef KOPETE_AVVIDEODEVICEMODELPOOL_H +#define KOPETE_AVVIDEODEVICEMODELPOOL_H + +#include <qstring.h> +#include <qvector.h> +#include <kdebug.h> +#include "kopete_export.h" + +namespace Kopete { + +namespace AV { + +/** + @author Kopete Developers <kopete-devel@kde.org> +*/ +class VideoDeviceModelPool{ + + struct VideoDeviceModel + { + QString model; + size_t count; + }; + QVector<VideoDeviceModel> m_devicemodel; +public: + VideoDeviceModelPool(); + ~VideoDeviceModelPool(); + void clear(); + size_t size(); + size_t addModel(QString newmodel); +}; + +} + +} + +#endif diff --git a/src/kvilib/ext/avdevice/videodevicepool.cpp b/src/kvilib/ext/avdevice/videodevicepool.cpp new file mode 100644 index 000000000..83271723c --- /dev/null +++ b/src/kvilib/ext/avdevice/videodevicepool.cpp @@ -0,0 +1,940 @@ +//============================================================================= +// +// File : videodevicepool.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videodevicepool.cpp - Kopete Video Device Low-level Support + + Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro <taupter@gmail.com> + + Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#define ENABLE_AV + +#include <assert.h> +#include <cstdlib> +#include <cerrno> +#include <cstring> + +#include <klocale.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kconfiggroup.h> +#include <qdir.h> + +#include "videodevice.h" +#include "videodevicepool.h" + +#ifdef COMPILE_KDE_SUPPORT + #include <solid/device.h> + #include <solid/devicenotifier.h> + #include <solid/deviceinterface.h> + #include <solid/video.h> +#endif + +#define CLEAR(x) memset (&(x), 0, sizeof (x)) + +namespace Kopete { + +namespace AV { + +VideoDevicePool *VideoDevicePool::s_self = NULL; +__u64 VideoDevicePool::m_clients = 0; + +VideoDevicePool* VideoDevicePool::self() +{ +// kDebug() << "libkopete (avdevice): self() called"; + if (s_self == NULL) + { + s_self = new VideoDevicePool; + if (s_self) + m_clients = 0; + } +// kDebug() << "libkopete (avdevice): self() exited successfuly"; + return s_self; +} + +VideoDevicePool::VideoDevicePool() +: m_current_device(0) +{ +#ifdef COMPILE_KDE_SUPPORT + connect( Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(const QString&)), SLOT(deviceAdded(const QString &)) ); + connect( Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(const QString&)), SLOT(deviceRemoved(const QString &)) ); +#endif +} + + +VideoDevicePool::~VideoDevicePool() +{ +} + + + + +/*! + \fn VideoDevicePool::open() + */ +int VideoDevicePool::open() +{ + /// @todo implement me +qDebug("VideoDevicePool::open()"); + m_ready.lock(); + if(!m_videodevice.size()) + { + kDebug() << "open(): No devices found. Must scan for available devices." << m_current_device; + scanDevices(); + } + if(!m_videodevice.size()) + { + kDebug() << "open(): No devices found. bailing out." << m_current_device; + m_ready.unlock(); + return EXIT_FAILURE; + } + if(m_current_device >= m_videodevice.size()) + { + kDebug() << "open(): Device out of scope (" << m_current_device << "). Defaulting to the first one."; + m_current_device = 0; + } + int isopen = m_videodevice[currentDevice()].open(); + if ( isopen == EXIT_SUCCESS) + { + loadConfig(); // Temporary hack. The open() seems to clean the input parameters. Need to find a way to fix it. + + } + m_clients++; + kDebug() << "Number of clients: " << m_clients; + m_ready.unlock(); + return isopen; +} + +/*! + \fn VideoDevicePool::open(int device) + */ +int VideoDevicePool::open(int device) +{ + /// @todo implement me + kDebug() << "open(" << device << ") called."; + if(device >= m_videodevice.size()) + { + kDebug() << "open(" << device <<"): Device does not exist."; + return EXIT_FAILURE; + } + close(); + kDebug() << "open(" << device << ") Setting m_current_Device to " << device; + m_current_device = device; + kDebug() << "open(" << device << ") Calling open()."; + saveConfig(); + + return open(); +} + +bool VideoDevicePool::isOpen() +{ + return m_videodevice[currentDevice()].isOpen(); +} + +/*! + \fn VideoDevicePool::showDeviceCapabilities(int device) + */ +int VideoDevicePool::showDeviceCapabilities(unsigned int device) +{ + return m_videodevice[device].showDeviceCapabilities(); +} + +int VideoDevicePool::width() +{ + return m_videodevice[currentDevice()].width(); +} + +int VideoDevicePool::minWidth() +{ + return m_videodevice[currentDevice()].minWidth(); +} + +int VideoDevicePool::maxWidth() +{ + return m_videodevice[currentDevice()].maxWidth(); +} + +int VideoDevicePool::height() +{ + return m_videodevice[currentDevice()].height(); +} + +int VideoDevicePool::minHeight() +{ + return m_videodevice[currentDevice()].minHeight(); +} + +int VideoDevicePool::maxHeight() +{ + return m_videodevice[currentDevice()].maxHeight(); +} + +int VideoDevicePool::setSize( int newwidth, int newheight) +{ + if(m_videodevice.size()) + return m_videodevice[currentDevice()].setSize(newwidth, newheight); + else + { + kDebug() << "VideoDevicePool::setSize() fallback for no device."; + m_buffer.width=newwidth; + m_buffer.height=newheight; + m_buffer.pixelformat= PIXELFORMAT_RGB24; + m_buffer.data.resize(m_buffer.width*m_buffer.height*3); + kDebug() << "VideoDevicePool::setSize() buffer size: "<< m_buffer.data.size(); + } + return EXIT_SUCCESS; +} + +/*! + \fn VideoDevicePool::close() + */ +int VideoDevicePool::close() +{ + /// @todo implement me + if(m_clients) + m_clients--; + if((currentDevice() < m_videodevice.size())&&(!m_clients)) + return m_videodevice[currentDevice()].close(); + if(m_clients) + kDebug() << "VideoDevicePool::close() The video device is still in use."; + if(currentDevice() >= m_videodevice.size()) + kDebug() << "VideoDevicePool::close() Current device out of range."; + return EXIT_FAILURE; +} + +/*! + \fn VideoDevicePool::startCapturing() + */ +int VideoDevicePool::startCapturing() +{ + kDebug() << "startCapturing() called."; + if(m_videodevice.size()) + return m_videodevice[currentDevice()].startCapturing(); + return EXIT_FAILURE; +} + + +/*! + \fn VideoDevicePool::stopCapturing() + */ +int VideoDevicePool::stopCapturing() +{ + if(m_videodevice.size()) + return m_videodevice[currentDevice()].stopCapturing(); + return EXIT_FAILURE; +} + +// Implementation of the methods that get / set input's adjustment parameters +/*! + \fn VideoDevicePool::getBrightness() + */ +float VideoDevicePool::getBrightness() +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].getBrightness(); + else + return 0; +} + +/*! + \fn VideoDevicePool::setBrightness(float brightness) + */ +float VideoDevicePool::setBrightness(float brightness) +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].setBrightness(brightness); + else + return 0; +} + +/*! + \fn VideoDevicePool::getContrast() + */ +float VideoDevicePool::getContrast() +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].getContrast(); + else + return 0; +} + +/*! + \fn VideoDevicePool::setContrast(float contrast) + */ +float VideoDevicePool::setContrast(float contrast) +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].setContrast(contrast); + else + return 0; +} + +/*! + \fn VideoDevicePool::getSaturation() + */ +float VideoDevicePool::getSaturation() +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].getSaturation(); + else + return 0; +} + +/*! + \fn VideoDevicePool::setSaturation(float saturation) + */ +float VideoDevicePool::setSaturation(float saturation) +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].setSaturation(saturation); + else + return 0; +} + +/*! + \fn VideoDevicePool::getWhiteness() + */ +float VideoDevicePool::getWhiteness() +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].getWhiteness(); + else + return 0; +} + +/*! + \fn VideoDevicePool::setWhiteness(float whiteness) + */ +float VideoDevicePool::setWhiteness(float whiteness) +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].setWhiteness(whiteness); + else + return 0; +} + +/*! + \fn VideoDevicePool::getHue() + */ +float VideoDevicePool::getHue() +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].getHue(); + else + return 0; +} + +/*! + \fn VideoDevicePool::setHue(float hue) + */ +float VideoDevicePool::setHue(float hue) +{ + if (currentDevice() < m_videodevice.size() ) + return m_videodevice[currentDevice()].setHue(hue); + else + return 0; +} + +/*! + \fn VideoDevicePool::getAutoBrightnessContrast() + */ +bool VideoDevicePool::getAutoBrightnessContrast() +{ + if(m_videodevice.size()) + return m_videodevice[currentDevice()].getAutoBrightnessContrast(); + return false; +} + +/*! + \fn VideoDevicePool::setAutoBrightnessContrast(bool brightnesscontrast) + */ +bool VideoDevicePool::setAutoBrightnessContrast(bool brightnesscontrast) +{ + kDebug() << "VideoDevicePool::setAutoBrightnessContrast(" << brightnesscontrast << ") called."; + if(m_videodevice.size()) + return m_videodevice[currentDevice()].setAutoBrightnessContrast(brightnesscontrast); + return false; +} + +/*! + \fn VideoDevicePool::getAutoColorCorrection() + */ +bool VideoDevicePool::getAutoColorCorrection() +{ + if(m_videodevice.size()) + return m_videodevice[currentDevice()].getAutoColorCorrection(); + return false; +} + +/*! + \fn VideoDevicePool::setAutoColorCorrection(bool colorcorrection) + */ +bool VideoDevicePool::setAutoColorCorrection(bool colorcorrection) +{ + kDebug() << "VideoDevicePool::setAutoColorCorrection(" << colorcorrection << ") called."; + if(m_videodevice.size()) + return m_videodevice[currentDevice()].setAutoColorCorrection(colorcorrection); + return false; +} + +/*! + \fn VideoDevicePool::getIMageAsMirror() + */ +bool VideoDevicePool::getImageAsMirror() +{ + if(m_videodevice.size()) + return m_videodevice[currentDevice()].getImageAsMirror(); + return false; +} + +/*! + \fn VideoDevicePool::setImageAsMirror(bool imageasmirror) + */ +bool VideoDevicePool::setImageAsMirror(bool imageasmirror) +{ + kDebug() << "VideoDevicePool::setImageAsMirror(" << imageasmirror << ") called."; + if(m_videodevice.size()) + return m_videodevice[currentDevice()].setImageAsMirror(imageasmirror); + return false; +} + +/*! + \fn VideoDevicePool::getFrame() + */ +int VideoDevicePool::getFrame() +{ +// kDebug() << "VideoDevicePool::getFrame() called."; + if(m_videodevice.size()) + return m_videodevice[currentDevice()].getFrame(); + else + { + kDebug() << "VideoDevicePool::getFrame() fallback for no device."; + for(int loop=0; loop < m_buffer.data.size(); loop+=3) + { + m_buffer.data[loop] = 255; + m_buffer.data[loop+1] = 0; + m_buffer.data[loop+2] = 0; + } + } + kDebug() << "VideoDevicePool::getFrame() exited successfuly."; + + return EXIT_SUCCESS; +} + +/*! + \fn VideoDevicePool::getQImage(QImage *qimage) + */ +int VideoDevicePool::getImage(QImage *qimage) +{ +// kDebug() << "VideoDevicePool::getImage() called."; + if(m_videodevice.size()) + return m_videodevice[currentDevice()].getImage(qimage); + else + { + kDebug() << "VideoDevicePool::getImage() fallback for no device."; + + // do NOT delete qimage here, as it is received as a parameter + if (qimage->width() != width() || qimage->height() != height()) + *qimage = QImage(width(), height(), QImage::Format_RGB32); + + uchar *bits=qimage->bits(); + switch(m_buffer.pixelformat) + { + case PIXELFORMAT_NONE : break; + case PIXELFORMAT_GREY : break; + case PIXELFORMAT_RGB332 : break; + case PIXELFORMAT_RGB555 : break; + case PIXELFORMAT_RGB555X: break; + case PIXELFORMAT_RGB565 : break; + case PIXELFORMAT_RGB565X: break; + case PIXELFORMAT_RGB24 : + { + kDebug() << "VideoDevicePool::getImage() fallback for no device - RGB24."; + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = m_buffer.data[step]; + bits[loop+1] = m_buffer.data[step+1]; + bits[loop+2] = m_buffer.data[step+2]; + bits[loop+3] = 255; + step+=3; + } + } + break; + case PIXELFORMAT_BGR24 : break; + { + int step=0; + for(int loop=0;loop < qimage->numBytes();loop+=4) + { + bits[loop] = m_buffer.data[step+2]; + bits[loop+1] = m_buffer.data[step+1]; + bits[loop+2] = m_buffer.data[step]; + bits[loop+3] = 255; + step+=3; + } + } + break; + case PIXELFORMAT_RGB32 : memcpy(bits,&m_buffer.data[0], m_buffer.data.size()); + break; + case PIXELFORMAT_BGR32 : break; + case PIXELFORMAT_YUYV : break; + case PIXELFORMAT_UYVY : break; + case PIXELFORMAT_YUV420P: break; + case PIXELFORMAT_YUV422P: break; + default: break; + } + } + kDebug() << "VideoDevicePool::getImage() exited successfuly."; + return EXIT_SUCCESS; +} + +/*! + \fn Kopete::AV::VideoDevicePool::selectInput(int input) + */ +int VideoDevicePool::selectInput(int newinput) +{ + kDebug() << "VideoDevicePool::selectInput(" << newinput << ") called."; + if(m_videodevice.size()) + return m_videodevice[currentDevice()].selectInput(newinput); + else + return 0; +} + +/*! + \fn Kopete::AV::VideoDevicePool::setInputParameters() + */ +int VideoDevicePool::setInputParameters() +{ + if(m_videodevice.size()) + return m_videodevice[currentDevice()].setInputParameters(); + else + return EXIT_FAILURE; +} + +/*! + \fn Kopete::AV::VideoDevicePool::fillDeviceQComboBox(QComboBox *combobox) + */ +int VideoDevicePool::fillDeviceQComboBox(QComboBox *combobox) +{ + /// @todo implement me + kDebug() << "Called."; +// check if QComboBox is a valid pointer. + if (combobox != NULL) + { + combobox->clear(); + kDebug() << "Combobox cleaned."; + if(m_videodevice.size()) + { + for (int loop=0; loop < m_videodevice.size(); loop++) + { + combobox->addItem(m_videodevice[loop].m_name); + kDebug() << "Added device " << loop << ": " << m_videodevice[loop].m_name; + } + combobox->setCurrentIndex(currentDevice()); + return EXIT_SUCCESS; + } + } + return EXIT_FAILURE; +} + +/*! + \fn Kopete::AV::VideoDevicePool::fillInputQComboBox(QComboBox *combobox) + */ +int VideoDevicePool::fillInputQComboBox(QComboBox *combobox) +{ + /// @todo implement me + kDebug() << "Called."; + if (combobox != NULL) + { + combobox->clear(); + if ( !m_videodevice.isEmpty() && (currentDevice()>=0) && currentDevice() < m_videodevice.size() ) + { + if(m_videodevice[currentDevice()].inputs()>0) + { + for (int loop=0; loop < m_videodevice[currentDevice()].inputs(); loop++) + { + combobox->addItem(m_videodevice[currentDevice()].m_input[loop].name); + kDebug() << "Added input " << loop << ": " << m_videodevice[currentDevice()].m_input[loop].name << " (tuner: " << m_videodevice[currentDevice()].m_input[loop].hastuner << ")"; + } + combobox->setCurrentIndex(currentInput()); + return EXIT_SUCCESS; + } + } + } + return EXIT_FAILURE; +} + +/*! + \fn Kopete::AV::VideoDevicePool::fillStandardQComboBox(QComboBox *combobox) + */ +int VideoDevicePool::fillStandardQComboBox(QComboBox *combobox) +{ + /// @todo implement me + kDebug() << "Called."; + if (combobox != NULL) + { + combobox->clear(); + if ( !m_videodevice.isEmpty() && currentDevice() < m_videodevice.size() ) + { + if(m_videodevice[currentDevice()].inputs()>0) + { + for (unsigned int loop=0; loop < 25; loop++) + { + if ( (m_videodevice[currentDevice()].m_input[currentInput()].m_standards) & (1 << loop) ) + combobox->addItem(m_videodevice[currentDevice()].signalStandardName( 1 << loop)); +/* + case STANDARD_PAL_B1 : return V4L2_STD_PAL_B1; break; + case STANDARD_PAL_G : return V4L2_STD_PAL_G; break; + case STANDARD_PAL_H : return V4L2_STD_PAL_H; break; + case STANDARD_PAL_I : return V4L2_STD_PAL_I; break; + case STANDARD_PAL_D : return V4L2_STD_PAL_D; break; + case STANDARD_PAL_D1 : return V4L2_STD_PAL_D1; break; + case STANDARD_PAL_K : return V4L2_STD_PAL_K; break; + case STANDARD_PAL_M : return V4L2_STD_PAL_M; break; + case STANDARD_PAL_N : return V4L2_STD_PAL_N; break; + case STANDARD_PAL_Nc : return V4L2_STD_PAL_Nc; break; + case STANDARD_PAL_60 : return V4L2_STD_PAL_60; break; + case STANDARD_NTSC_M : return V4L2_STD_NTSC_M; break; + case STANDARD_NTSC_M_JP : return V4L2_STD_NTSC_M_JP; break; + case STANDARD_NTSC_443 : return V4L2_STD_NTSC; break; // Using workaround value because my videodev2.h header seems to not include this standard in struct __u64 v4l2_std_id + case STANDARD_SECAM_B : return V4L2_STD_SECAM_B; break; + case STANDARD_SECAM_D : return V4L2_STD_SECAM_D; break; + case STANDARD_SECAM_G : return V4L2_STD_SECAM_G; break; + case STANDARD_SECAM_H : return V4L2_STD_SECAM_H; break; + case STANDARD_SECAM_K : return V4L2_STD_SECAM_K; break; + case STANDARD_SECAM_K1 : return V4L2_STD_SECAM_K1; break; + case STANDARD_SECAM_L : return V4L2_STD_SECAM_L; break; + case STANDARD_SECAM_LC : return V4L2_STD_SECAM; break; // Using workaround value because my videodev2.h header seems to not include this standard in struct __u64 v4l2_std_id + case STANDARD_ATSC_8_VSB : return V4L2_STD_ATSC_8_VSB; break; // ATSC/HDTV Standard officially not supported by V4L2 but exists in videodev2.h + case STANDARD_ATSC_16_VSB : return V4L2_STD_ATSC_16_VSB; break; // ATSC/HDTV Standard officially not supported by V4L2 but exists in videodev2.h + case STANDARD_PAL_BG : return V4L2_STD_PAL_BG; break; + case STANDARD_PAL_DK : return V4L2_STD_PAL_DK; break; + case STANDARD_PAL : return V4L2_STD_PAL; break; + case STANDARD_NTSC : return V4L2_STD_NTSC; break; + case STANDARD_SECAM_DK : return V4L2_STD_SECAM_DK; break; + case STANDARD_SECAM : return V4L2_STD_SECAM; break; + case STANDARD_525_60 : return V4L2_STD_525_60; break; + case STANDARD_625_50 : return V4L2_STD_625_50; break; + case STANDARD_ALL : return V4L2_STD_ALL; break; + + combobox->insertItem(m_videodevice[currentDevice()].m_input[loop].name); + kDebug() << "StandardQComboBox: Added input " << loop << ": " << m_videodevice[currentDevice()].m_input[loop].name << " (tuner: " << m_videodevice[currentDevice()].m_input[loop].hastuner << ")";*/ + } + combobox->setCurrentIndex(currentInput()); + return EXIT_SUCCESS; + } + } + } + return EXIT_FAILURE; +} + +/*! + \fn Kopete::AV::VideoDevicePool::scanDevices() + */ +int VideoDevicePool::scanDevices() +{ + /// @todo implement me + + kDebug() << "called"; +#ifdef COMPILE_KDE_SUPPORT + foreach (Solid::Device device, + Solid::Device::listFromType(Solid::DeviceInterface::Video, QString())) { + registerDevice( device ); + } + +#endif + kDebug() << "exited successfuly"; + return EXIT_SUCCESS; +} + +#ifdef COMPILE_KDE_SUPPORT + +void VideoDevicePool::registerDevice( Solid::Device & device ) +{ + kDebug() << "New video device at " << device.udi(); + const Solid::Device * vendorDevice = &device; + while ( vendorDevice->isValid() && vendorDevice->vendor().isEmpty() ) + { + vendorDevice = new Solid::Device( vendorDevice->parentUdi() ); + } + if ( vendorDevice->isValid() ) + { + kDebug() << "vendor: " << vendorDevice->vendor() << ", product: " << vendorDevice->product(); + } + Solid::Video * solidVideoDevice = device.as<Solid::Video>(); + if ( solidVideoDevice ) { + QStringList protocols = solidVideoDevice->supportedProtocols(); + if ( protocols.contains( "video4linux" ) ) + { + QStringList drivers = solidVideoDevice->supportedDrivers( "video4linux" ); + if ( drivers.contains( "video4linux" ) ) + { + kDebug() << "V4L device path is" << solidVideoDevice->driverHandle( "video4linux" ).toString(); + VideoDevice videodevice; + videodevice.setUdi( device.udi() ); + videodevice.setFileName(solidVideoDevice->driverHandle( "video4linux" ).toString()); + kDebug() << "Found device " << videodevice.full_filename; + videodevice.open(); + if(videodevice.isOpen()) + { + kDebug() << "File " << videodevice.full_filename << " was opened successfuly"; + videodevice.close(); + videodevice.m_modelindex=m_modelvector.addModel (videodevice.m_model); // Adds device to the device list and sets model number + m_videodevice.push_back(videodevice); + } + } + } + } +} +#endif + +/*! + \fn Kopete::AV::VideoDevicePool::hasDevices() + */ +bool VideoDevicePool::hasDevices() +{ + /// @todo implement me + if(m_videodevice.size()) + return true; + return false; +} + +/*! + \fn Kopete::AV::VideoDevicePool::size() + */ +size_t VideoDevicePool::size() +{ + /// @todo implement me + return m_videodevice.size(); +} + +/*! + \fn Kopete::AV::VideoDevicePool::currentDevice() + */ +int VideoDevicePool::currentDevice() +{ + /// @todo implement me + return m_current_device; +} + +/*! + \fn Kopete::AV::VideoDevicePool::currentInput() + */ +int VideoDevicePool::currentInput() +{ + /// @todo implement me + return m_videodevice[currentDevice()].currentInput(); +} + +/*! + \fn Kopete::AV::VideoDevicePool::currentInput() + */ +unsigned int VideoDevicePool::inputs() +{ + /// @todo implement me + return m_videodevice[currentDevice()].inputs(); +} + +/*! + \fn Kopete::AV::VideoDevicePool::loadConfig() + */ +void VideoDevicePool::loadConfig() +{ + /// @todo implement me + kDebug() << "called"; + if((hasDevices())&&(m_clients==0)) + { + KConfigGroup config(KGlobal::config(), "Video Device Settings"); + QString currentdevice = config.readEntry("Current Device", QString()); + kDebug() << "Current device: " << currentdevice; + +// m_current_device = 0; // Must check this thing because of the fact that multiple loadConfig in other methodas can do bad things. Watch out! + + VideoDeviceVector::iterator vditerator; + for( vditerator = m_videodevice.begin(); vditerator != m_videodevice.end(); ++vditerator ) + { + const QString modelindex = QString::fromLocal8Bit ( "Model %1 Device %2") .arg ((*vditerator).m_name ) .arg ((*vditerator).m_modelindex); + if(modelindex == currentdevice) + { + m_current_device = std::distance (m_videodevice.begin(), vditerator); +// kDebug() << "This place will be used to set " << modelindex << " as the current device ( " << std::distance(m_videodevice.begin(), vditerator ) << " )."; + } + const QString name = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Name") .arg ((*vditerator).m_name ) .arg ((*vditerator).m_modelindex)), (*vditerator).m_model); + const int currentinput = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Current input") .arg ((*vditerator).m_name ) .arg ((*vditerator).m_modelindex)), 0); + kDebug() << "Device name: " << name; + kDebug() << "Device current input: " << currentinput; + (*vditerator).selectInput(currentinput); + + for (int input = 0 ; input < (*vditerator).m_input.size(); input++) + { + const float brightness = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Brightness").arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input)) , 0.5 ); + const float contrast = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Contrast") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input)) , 0.5 ); + const float saturation = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Saturation").arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input)) , 0.5 ); + const float whiteness = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Whiteness") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input)) , 0.5 ); + const float hue = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Hue") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input)) , 0.5 ); + const bool autobrightnesscontrast = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 AutoBrightnessContrast") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input)) , false ); + const bool autocolorcorrection = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 AutoColorCorrection") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input)) , false ); + const bool imageasmirror = config.readEntry((QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 mageAsMirror") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input)) , false ); + (*vditerator).setBrightness(brightness); + (*vditerator).setContrast(contrast); + (*vditerator).setSaturation(saturation); + (*vditerator).setHue(hue); + (*vditerator).setAutoBrightnessContrast(autobrightnesscontrast); + (*vditerator).setAutoColorCorrection(autocolorcorrection); + (*vditerator).setImageAsMirror(imageasmirror); + kDebug() << "Brightness:" << brightness; + kDebug() << "Contrast :" << contrast; + kDebug() << "Saturation:" << saturation; + kDebug() << "Whiteness :" << whiteness; + kDebug() << "Hue :" << hue; + kDebug() << "AutoBrightnessContrast:" << autobrightnesscontrast; + kDebug() << "AutoColorCorrection :" << autocolorcorrection; + kDebug() << "ImageAsMirror :" << imageasmirror; + } + } + } +} + +/*! + \fn Kopete::AV::VideoDevicePool::saveConfig() + */ +void VideoDevicePool::saveConfig() +{ + /// @todo implement me + kDebug() << "called"; + if(hasDevices()) + { + KConfigGroup config(KGlobal::config(), "Video Device Settings"); + +/* if(m_modelvector.size()) + { + VideoDeviceModelPool::m_devicemodel::iterator vmiterator; + for( vmiterator = m_modelvector.begin(); vmiterator != m_modelvector.end(); ++vmiterator ) + { + kDebug() << "Device Model: " << (*vmiterator).name; + kDebug() << "Device Count: " << (*vmiterator).count; + } + } +*/ +// Stores what is the current video device in use + const QString currentdevice = QString::fromLocal8Bit ( "Model %1 Device %2" ) .arg(m_videodevice[m_current_device].m_model) .arg(m_videodevice[m_current_device].m_modelindex); + config.writeEntry( "Current Device", currentdevice); + + VideoDeviceVector::iterator vditerator; + for( vditerator = m_videodevice.begin(); vditerator != m_videodevice.end(); ++vditerator ) + { + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Name:" << (*vditerator).m_name; + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Current input:" << (*vditerator).currentInput(); + +// Stores current input for the given video device + const QString name = QString::fromLocal8Bit ( "Model %1 Device %2 Name") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex); + const QString currentinput = QString::fromLocal8Bit ( "Model %1 Device %2 Current input") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex); + config.writeEntry( name, (*vditerator).m_name); + config.writeEntry( currentinput, (*vditerator).currentInput()); + + for (int input = 0 ; input < (*vditerator).m_input.size(); input++) + { + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Input:" << input << ":Brightness: " << (*vditerator).m_input[input].getBrightness(); + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Input:" << input << ":Contrast : " << (*vditerator).m_input[input].getContrast(); + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Input:" << input << ":Saturation: " << (*vditerator).m_input[input].getSaturation(); + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Input:" << input << ":Whiteness : " << (*vditerator).m_input[input].getWhiteness(); + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Input:" << input << ":Hue : " << (*vditerator).m_input[input].getHue(); + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Input:" << input << ":Automatic brightness / contrast: " << (*vditerator).m_input[input].getAutoBrightnessContrast(); + kDebug() << "Model:" << (*vditerator).m_model << ":Index:" << (*vditerator).m_modelindex << ":Input:" << input << ":Automatic color correction : " << (*vditerator).m_input[input].getAutoColorCorrection(); + +// Stores configuration about each channel + const QString brightness = QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Brightness") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input); + const QString contrast = QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Contrast") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input); + const QString saturation = QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Saturation") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input); + const QString whiteness = QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Whiteness") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input); + const QString hue = QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 Hue") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input); + const QString autobrightnesscontrast = QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 AutoBrightnessContrast") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input); + const QString autocolorcorrection = QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 AutoColorCorrection") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input); + const QString imageasmirror = QString::fromLocal8Bit ( "Model %1 Device %2 Input %3 ImageAsMirror") .arg ((*vditerator).m_model ) .arg ((*vditerator).m_modelindex) .arg (input); + config.writeEntry( brightness, (double)(*vditerator).m_input[input].getBrightness()); + config.writeEntry( contrast, (double)(*vditerator).m_input[input].getContrast()); + config.writeEntry( saturation, (double)(*vditerator).m_input[input].getSaturation()); + config.writeEntry( whiteness, (double)(*vditerator).m_input[input].getWhiteness()); + config.writeEntry( hue, (double)(*vditerator).m_input[input].getHue()); + config.writeEntry( autobrightnesscontrast, (*vditerator).m_input[input].getAutoBrightnessContrast()); + config.writeEntry( autocolorcorrection, (*vditerator).m_input[input].getAutoColorCorrection()); + config.writeEntry( imageasmirror, (*vditerator).m_input[input].getImageAsMirror()); + } + } + config.sync(); + kDebug(); + } +} + +#ifdef COMPILE_KDE_SUPPORT + +void VideoDevicePool::deviceAdded( const QString & udi ) +{ + kDebug() << "("<< udi << ") called"; + Solid::Device dev( udi ); + if ( dev.is<Solid::Video>() ) + { + registerDevice( dev ); + emit deviceRegistered( udi ); + } +} + +void VideoDevicePool::deviceRemoved( const QString & udi ) +{ + kDebug() << "("<< udi << ") called"; + int i = 0; + foreach ( VideoDevice vd, m_videodevice ) + { + if ( vd.udi() == udi ) + { + kDebug() << "Video device '" << udi << "' has been removed!"; + emit deviceUnregistered( udi ); + // not sure if this is safe but at this point the device node is gone already anyway + m_videodevice.remove( i ); + } + else + { + i++; + } + } +} + +#endif + +} // namespace AV + +} // namespace Kopete diff --git a/src/kvilib/ext/avdevice/videodevicepool.h b/src/kvilib/ext/avdevice/videodevicepool.h new file mode 100644 index 000000000..2adc663b5 --- /dev/null +++ b/src/kvilib/ext/avdevice/videodevicepool.h @@ -0,0 +1,175 @@ +//============================================================================= +// +// File : videodevicepool.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videodevicepool.h - Kopete Multiple Video Device handler Class + + Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro <taupter@gmail.com> + + Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#ifndef VIDEODEVICEPOOL_H +#define VIDEODEVICEPOOL_H + +#include <iostream> + +#include "kvi_settings.h" + +#include "videoinput.h" +#include "videodevicemodelpool.h" +#include <qstring.h> +#include <qimage.h> +#include <q3valuevector.h> +#include <qmutex.h> +#include <QComboBox> +#include "videodevice.h" +#include "kopete_export.h" +#include <kconfig.h> +#include <kglobal.h> + +#ifdef COMPILE_KDE_SUPPORT + #include <solid/device.h> +#endif + +// Uncomment this line and comment out the include and using lines to +// revert to standard vector if you hit issues. It should all be fine though. +// typedef QVector<Kopete::AV::VideoDevice> VideoDeviceVector; +#include "videodevicevector.h" +using Kopete::AV::VideoDeviceVector; + +namespace Kopete { + +namespace AV { + +/** +This class allows kopete to check for the existence, open, configure, test, set parameters, grab frames from and close a given video capture card using the Video4Linux API. + +@author Cláudio da Silveira Pinheiro +*/ + +class KOPETE_EXPORT VideoDevicePool : public QObject +{ +Q_OBJECT +public: + static VideoDevicePool* self(); + int open(); + int open(int device); + bool isOpen(); + int getFrame(); + int width(); + int minWidth(); + int maxWidth(); + int height(); + int minHeight(); + int maxHeight(); + int setSize( int newwidth, int newheight); + int close(); + int startCapturing(); + int stopCapturing(); + int readFrame(); + int getImage(QImage *qimage); + int selectInput(int newinput); + int setInputParameters(); + int scanDevices(); +#ifdef COMPILE_KDE_SUPPORT + void registerDevice( Solid::Device & dev ); +#endif + bool hasDevices(); + size_t size(); + ~VideoDevicePool(); + VideoDeviceVector m_videodevice; // Vector to be filled with found devices + VideoDeviceModelPool m_modelvector; // Vector to be filled with unique device models + int fillDeviceQComboBox(QComboBox *combobox); + int fillInputQComboBox(QComboBox *combobox); + int fillStandardQComboBox(QComboBox *combobox); + int currentDevice(); + int currentInput(); + unsigned int inputs(); + + float getBrightness(); + float setBrightness(float brightness); + float getContrast(); + float setContrast(float contrast); + float getSaturation(); + float setSaturation(float saturation); + float getWhiteness(); + float setWhiteness(float whiteness); + float getHue(); + float setHue(float hue); + + bool getAutoBrightnessContrast(); + bool setAutoBrightnessContrast(bool brightnesscontrast); + bool getAutoColorCorrection(); + bool setAutoColorCorrection(bool colorcorrection); + bool getImageAsMirror(); + bool setImageAsMirror(bool imageasmirror); + + void loadConfig(); // Load configuration parameters; + void saveConfig(); // Save configuretion parameters; +signals: + /** + * Provisional signatures, probably more useful to indicate which device was registered + */ + void deviceRegistered( const QString & udi ); + void deviceUnregistered( const QString & udi ); +#ifdef COMPILE_KDE_SUPPORT +protected slots: + /** + * Slot called when a new device is added to the system + */ + void deviceAdded( const QString & udi ); + void deviceRemoved( const QString & udi ); +#endif +protected: + int xioctl(int request, void *arg); + int errnoReturn(const char* s); + int showDeviceCapabilities(unsigned int device); + void guessDriver(); + int m_current_device; + struct imagebuffer m_buffer; // only used when no devices were found + + QMutex m_ready; +private: + VideoDevicePool(); + static VideoDevicePool* s_self; + static __u64 m_clients; // Number of instances +}; + +} + +} + +#endif // VIDEODEVICEPOOL_H diff --git a/src/kvilib/ext/avdevice/videodevicevector.cpp b/src/kvilib/ext/avdevice/videodevicevector.cpp new file mode 100644 index 000000000..4edc96c39 --- /dev/null +++ b/src/kvilib/ext/avdevice/videodevicevector.cpp @@ -0,0 +1,88 @@ +//============================================================================= +// +// File : videodevicevector.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videodevicevector.cpp - Kopete Video Device List Abstration + + Copyright (c) 2009 by Alan Jones <skyphyr@gmail.com> + + Kopete (c) 2002-2009 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library 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 3 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, see <http://www.gnu.org/licenses/>. * + ************************************************************************* +*/ + +#include "videodevicevector.h" + +namespace Kopete { + +namespace AV { + +VideoDevice& VideoDeviceVector::operator[] (int i) + { + if (i>=size()) + { + //we're outside the range so let's return a default camera not available VideoDevice + return fallback; + } + + //if we've made it here then we're within range + return QVector<VideoDevice>::operator[](i); + } + +const VideoDevice& VideoDeviceVector::operator[] (int i) const + { + return at(i); + } + +const VideoDevice& VideoDeviceVector::at(int i) const + { + if (i>=size()) + { + //we're outside the range so let's return a default camera not available VideoDevice + return fallback; + } + + //if we've made it here then we're within range + return QVector<VideoDevice>::operator[](i); + } + +} + +} diff --git a/src/kvilib/ext/avdevice/videodevicevector.h b/src/kvilib/ext/avdevice/videodevicevector.h new file mode 100644 index 000000000..e8bd330ac --- /dev/null +++ b/src/kvilib/ext/avdevice/videodevicevector.h @@ -0,0 +1,89 @@ +//============================================================================= +// +// File : videodevicevector.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videodevicevector.h - Kopete Video Device List Abstration + + Copyright (c) 2009 by Alan Jones <skyphyr@gmail.com> + + Kopete (c) 2002-2009 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library 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 3 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, see <http://www.gnu.org/licenses/>. * + ************************************************************************* +*/ + +#ifndef KOPETE_AVVIDEODEVICEVECTOR_H +#define KOPETE_AVVIDEODEVICEVECTOR_H + +#include "videodevice.h" +#include "dummyvideodevice.h" + +namespace Kopete { + +namespace AV { + +/** +@author Kopete Developers +*/ + +class VideoDeviceVector : public QVector<VideoDevice> +{ + +public: + VideoDeviceVector() {} + ~VideoDeviceVector() {} + + VideoDevice& operator[] (int i); + + const VideoDevice& operator[] (int i) const; + + const VideoDevice& at(int i) const; + +private: + + DummyVideoDevice fallback; +}; + +} + +} + + + +#endif diff --git a/src/kvilib/ext/avdevice/videoinput.cpp b/src/kvilib/ext/avdevice/videoinput.cpp new file mode 100644 index 000000000..2f95c8d58 --- /dev/null +++ b/src/kvilib/ext/avdevice/videoinput.cpp @@ -0,0 +1,198 @@ +//============================================================================= +// +// File : videoinput.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videoinput.cpp - Kopete Video Input Class + + Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro <taupter@gmail.com> + + Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#include "videoinput.h" + +namespace Kopete { + +namespace AV { + +VideoInput::VideoInput() +{ + kDebug() << "Executing Video Input's constructor!!!"; + m_brightness = 0.5; + m_contrast = 0.5; + m_saturation = 0.5; + m_hue = 0.5; + m_autobrightnesscontrast = false; + m_autocolorcorrection = false; +} + + +VideoInput::~VideoInput() +{ +} + +float VideoInput::getBrightness() +{ +// kDebug() << " called."; + return m_brightness; +} + +float VideoInput::setBrightness(float brightness) +{ +// kDebug() << " called."; + if ( brightness > 1 ) + brightness = 1; + else + if ( brightness < 0 ) + brightness = 0; + m_brightness = brightness; + return getBrightness(); +} + +float VideoInput::getContrast() +{ +// kDebug() << " called."; + return m_contrast; +} + +float VideoInput::setContrast(float contrast) +{ +// kDebug() << " called."; + if ( contrast > 1 ) + contrast = 1; + else + if ( contrast < 0 ) + contrast = 0; + m_contrast = contrast; + return getContrast(); +} + +float VideoInput::getSaturation() +{ +// kDebug() << " called."; + return m_saturation; +} + +float VideoInput::setSaturation(float saturation) +{ +// kDebug() << " called."; + if ( saturation > 1 ) + saturation = 1; + else + if ( saturation < 0 ) + saturation = 0; + m_saturation = saturation; + return getSaturation(); +} + +float VideoInput::getWhiteness() +{ +// kDebug() << " called."; + return m_whiteness; +} + +float VideoInput::setWhiteness(float whiteness) +{ +// kDebug() << " called."; + if ( whiteness > 1 ) + whiteness = 1; + else + if ( whiteness < 0 ) + whiteness = 0; + m_whiteness = whiteness; + return getWhiteness(); +} + +float VideoInput::getHue() +{ +// kDebug() << " called."; + return m_hue; +} + +float VideoInput::setHue(float hue) +{ +// kDebug() << " called."; + if ( hue > 1 ) + hue = 1; + else + if ( hue < 0 ) + hue = 0; + m_hue = hue; + return getHue(); +} + + +bool VideoInput::getAutoBrightnessContrast() +{ +// kDebug() << " called."; + return m_autobrightnesscontrast; +} + +bool VideoInput::setAutoBrightnessContrast(bool brightnesscontrast) +{ +// kDebug() << " called."; + m_autobrightnesscontrast = brightnesscontrast; + return getAutoBrightnessContrast(); +} + +bool VideoInput::getAutoColorCorrection() +{ +// kDebug() << " called."; + return m_autocolorcorrection; +} + +bool VideoInput::setAutoColorCorrection(bool colorcorrection) +{ +// kDebug() << " called."; + m_autocolorcorrection = colorcorrection; + return getAutoColorCorrection(); +} + +bool VideoInput::getImageAsMirror() +{ +// kDebug() << " called."; + return m_imageasmirror; +} + +bool VideoInput::setImageAsMirror(bool imageasmirror) +{ +// kDebug() << " called."; + m_imageasmirror = imageasmirror; + return getImageAsMirror(); +} + +} + +} diff --git a/src/kvilib/ext/avdevice/videoinput.h b/src/kvilib/ext/avdevice/videoinput.h new file mode 100644 index 000000000..fcb4970dd --- /dev/null +++ b/src/kvilib/ext/avdevice/videoinput.h @@ -0,0 +1,111 @@ +//============================================================================= +// +// File : videoinput.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// This file has been taken from the "Kopete, The KDE Instant Messenger" +// sourcecode. Original copyright of the file follows: +//============================================================================= + +/* + videoinput.h - Kopete Video Input Class + + Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro <taupter@gmail.com> + + Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#define ENABLE_AV + +#ifndef KOPETE_AVVIDEOINPUT_H +#define KOPETE_AVVIDEOINPUT_H + +#ifdef __linux__ +#include <asm/types.h> +#undef __STRICT_ANSI__ +#endif // __linux__ +#ifndef __u64 //required by videodev.h +#define __u64 unsigned long long +#endif // __u64*/ + +#include <qstring.h> +#include <kdebug.h> +#include "kopete_export.h" + +namespace Kopete { + +namespace AV { + +/** +@author Kopete Developers +*/ +class KOPETE_EXPORT VideoInput{ +public: + VideoInput(); + ~VideoInput(); + QString name; + int hastuner; + __u64 m_standards; + float getBrightness(); + float setBrightness(float brightness); + float getContrast(); + float setContrast(float contrast); + float getSaturation(); + float setSaturation(float saturation); + float getWhiteness(); + float setWhiteness(float whiteness); + float getHue(); + float setHue(float Hue); + bool getAutoBrightnessContrast(); + bool setAutoBrightnessContrast(bool brightnesscontrast); + bool getAutoColorCorrection(); + bool setAutoColorCorrection(bool colorcorrection); + bool getImageAsMirror(); + bool setImageAsMirror(bool imageasmirror); + +protected: +// this block must be changed to use a vector of controls instead of fixed ones + float m_brightness; + float m_contrast; + float m_saturation; + float m_whiteness; + float m_hue; + + bool m_autobrightnesscontrast; + bool m_autocolorcorrection; + bool m_imageasmirror; + + +}; + +} + +} + +#endif diff --git a/src/kvirc/kernel/kvi_options.cpp b/src/kvirc/kernel/kvi_options.cpp index 25778480a..06ad5dcbc 100644 --- a/src/kvirc/kernel/kvi_options.cpp +++ b/src/kvirc/kernel/kvi_options.cpp @@ -315,7 +315,10 @@ KviBoolOption g_boolOptionsTable[KVI_NUM_BOOL_OPTIONS]= BOOL_OPTION("PasteLastLogOnQueryJoin",false,KviOption_sectFlagLogging), BOOL_OPTION("UseSpecifiedSmartColorForOwnNick",false,KviOption_sectFlagIrcView | KviOption_resetUpdateGui | KviOption_groupTheme), BOOL_OPTION("UseFullWordHighlighting",false,KviOption_sectFlagIrcView), - BOOL_OPTION("ZshLikeNickCompletion",false,KviOption_sectFlagInput) + BOOL_OPTION("ZshLikeNickCompletion",false,KviOption_sectFlagInput), + BOOL_OPTION("AutoAcceptDccVideo", false, KviOption_sectFlagDcc), + BOOL_OPTION("CreateMinimizedDccVideo", false, KviOption_sectFlagDcc), + BOOL_OPTION("CreateMinimizedDccVideoWhenAutoAccepted",true,KviOption_sectFlagDcc) }; #define STRING_OPTION(_txt,_val,_flags) KviStringOption(KVI_STRING_OPTIONS_PREFIX _txt,_val,_flags) diff --git a/src/kvirc/kernel/kvi_options.h b/src/kvirc/kernel/kvi_options.h index 2a803e183..7330ea0c9 100644 --- a/src/kvirc/kernel/kvi_options.h +++ b/src/kvirc/kernel/kvi_options.h @@ -323,8 +323,11 @@ DECLARE_OPTION_STRUCT(KviStringListOption,QStringList) #define KviOption_boolUseSpecifiedSmartColorForOwnNick 229 /* interface::ircview */ #define KviOption_boolUseFullWordHighlighting 230 /* highlight */ #define KviOption_boolZshLikeNickCompletion 231 +#define KviOption_boolAutoAcceptDccVideo 232 /* dcc::video */ +#define KviOption_boolCreateMinimizedDccVideo 233 /* dcc::video */ +#define KviOption_boolCreateMinimizedDccVideoWhenAutoAccepted 234 /* dcc::video */ -#define KVI_NUM_BOOL_OPTIONS 232 +#define KVI_NUM_BOOL_OPTIONS 235 #define KVI_STRING_OPTIONS_PREFIX "string" diff --git a/src/modules/dcc/CMakeLists.txt b/src/modules/dcc/CMakeLists.txt index 71da80ff6..c380cb998 100644 --- a/src/modules/dcc/CMakeLists.txt +++ b/src/modules/dcc/CMakeLists.txt @@ -6,6 +6,7 @@ SET(kvidcc_MOC_HDRS dialogs.h marshal.h send.h + video.h voice.h window.h ) @@ -26,6 +27,7 @@ SET(kvidcc_SRCS send.cpp thread.cpp utils.cpp + video.cpp voice.cpp window.cpp ) diff --git a/src/modules/dcc/broker.cpp b/src/modules/dcc/broker.cpp index 4d0453aa8..d0c64b145 100644 --- a/src/modules/dcc/broker.cpp +++ b/src/modules/dcc/broker.cpp @@ -27,6 +27,7 @@ #include "chat.h" #include "send.h" #include "voice.h" +#include "video.h" #ifdef COMPILE_DCC_CANVAS #include "canvas.h" @@ -398,6 +399,75 @@ void KviDccBroker::passiveVoiceExecute(KviDccDescriptor * dcc) /////////////////////////////////////////////////////////////////////////////// +// ACTIVE VIDEO +/////////////////////////////////////////////////////////////////////////////// + +void KviDccBroker::activeVideoManage(KviDccDescriptor * dcc) +{ + if(!dcc->bAutoAccept) + { + // need confirmation + QString tmp = __tr2qs_ctx( + "<b>%1 [%2@%3]</b> requests a<br>" \ + "<b>Direct Client Connection</b> in <b>VIDEO</b> mode.<br>" \ + "The connection target will be host <b>%4</b> on port <b>%5</b><br>" \ + ,"dcc" \ + ).arg(dcc->szNick).arg(dcc->szUser).arg(dcc->szHost).arg(dcc->szIp).arg(dcc->szPort); + + KviDccAcceptBox * box = new KviDccAcceptBox(this,dcc,tmp,__tr2qs_ctx("DCC VIDEO request","dcc")); + m_pBoxList->append(box); + connect(box,SIGNAL(accepted(KviDccBox *,KviDccDescriptor *)), + this,SLOT(activeVideoExecute(KviDccBox *,KviDccDescriptor *))); + connect(box,SIGNAL(rejected(KviDccBox *,KviDccDescriptor *)), + this,SLOT(cancelDcc(KviDccBox *,KviDccDescriptor *))); + box->show(); + } else { + // auto accept + activeVideoExecute(0,dcc); + } +} + +void KviDccBroker::activeVideoExecute(KviDccBox *box,KviDccDescriptor * dcc) +{ + if(box)box->forgetDescriptor(); + + if(!g_pApp->windowExists(dcc->console())) + { + // rebind to the first available console.... + dcc->setConsole(g_pApp->activeConsole()); + } + + KviStr tmp(KviStr::Format,"dcc: video %s@%s:%s",dcc->szNick.toUtf8().data(),dcc->szIp.toUtf8().data(),dcc->szPort.toUtf8().data()); + KviDccVideo * v = new KviDccVideo(dcc->console()->frame(),dcc,tmp.ptr()); + + bool bMinimized = dcc->bOverrideMinimize ? dcc->bShowMinimized : \ + (KVI_OPTION_BOOL(KviOption_boolCreateMinimizedDccVideo) || \ + (dcc->bAutoAccept && KVI_OPTION_BOOL(KviOption_boolCreateMinimizedDccVideoWhenAutoAccepted))); + + dcc->console()->frame()->addWindow(v,!bMinimized); + if(bMinimized)v->minimize(); + + m_pDccWindowList->append(v); +} + + +/////////////////////////////////////////////////////////////////////////////// +// PASSIVE VOICE +/////////////////////////////////////////////////////////////////////////////// + +void KviDccBroker::passiveVideoExecute(KviDccDescriptor * dcc) +{ + KviStr tmp(KviStr::Format,"dcc: video %s@%s:%s",dcc->szNick.toUtf8().data(),dcc->szIp.toUtf8().data(),dcc->szPort.toUtf8().data()); + KviDccVideo * v = new KviDccVideo(dcc->console()->frame(),dcc,tmp.ptr()); + //#warning "Create minimized dcc video ?... or maybe it's too much ? :)" + bool bMinimized = dcc->bOverrideMinimize ? dcc->bShowMinimized : KVI_OPTION_BOOL(KviOption_boolCreateMinimizedDccChat); + dcc->console()->frame()->addWindow(v,!bMinimized); + if(bMinimized)v->minimize(); + m_pDccWindowList->append(v); +} + + +/////////////////////////////////////////////////////////////////////////////// // ACTIVE CANVAS /////////////////////////////////////////////////////////////////////////////// diff --git a/src/modules/dcc/broker.h b/src/modules/dcc/broker.h index 5be531571..338ebb853 100644 --- a/src/modules/dcc/broker.h +++ b/src/modules/dcc/broker.h @@ -86,6 +86,9 @@ public: void activeVoiceManage(KviDccDescriptor * dcc); void passiveVoiceExecute(KviDccDescriptor * dcc); + void activeVideoManage(KviDccDescriptor * dcc); + void passiveVideoExecute(KviDccDescriptor * dcc); + void recvFileManage(KviDccDescriptor * dcc); void sendFileManage(KviDccDescriptor * dcc); @@ -101,6 +104,7 @@ public slots: void activeCanvasExecute(KviDccBox * box,KviDccDescriptor * dcc); void activeVoiceExecute(KviDccBox * box,KviDccDescriptor * dcc); + void activeVideoExecute(KviDccBox * box,KviDccDescriptor * dcc); void sendFileExecute(KviDccBox * box,KviDccDescriptor * dcc); void recvFileExecute(KviDccBox * box,KviDccDescriptor * dcc); diff --git a/src/modules/dcc/codec.cpp b/src/modules/dcc/codec.cpp index d08a1c87f..1ea1172c9 100644 --- a/src/modules/dcc/codec.cpp +++ b/src/modules/dcc/codec.cpp @@ -88,3 +88,70 @@ int KviDccVoiceNullCodec::decodedFrameSize() { return 1024; } + +//-------------------------- + +KviDccVideoCodec::KviDccVideoCodec() +{ +} + +KviDccVideoCodec::~KviDccVideoCodec() +{ +} + +void KviDccVideoCodec::encode(KviDataBuffer *,KviDataBuffer *) +{ +} + +void KviDccVideoCodec::decode(KviDataBuffer *,KviDataBuffer *) +{ +} + +int KviDccVideoCodec::encodedFrameSize() +{ + return 0; +} + +int KviDccVideoCodec::decodedFrameSize() +{ + return 0; +} + +const char * KviDccVideoCodec::name() +{ + return m_szName.ptr(); +} + +KviDccVideoNullCodec::KviDccVideoNullCodec() +: KviDccVideoCodec() +{ + m_szName = "null (no compression)"; +} + +KviDccVideoNullCodec::~KviDccVideoNullCodec() +{ +} + +void KviDccVideoNullCodec::encode(KviDataBuffer * signal,KviDataBuffer * stream) +{ + if(signal->size() < 1)return; + stream->append(signal->data(),signal->size()); + signal->resize(0); +} + +void KviDccVideoNullCodec::decode(KviDataBuffer * stream,KviDataBuffer * signal) +{ + if(stream->size() < 1)return; + signal->append(stream->data(),stream->size()); + stream->resize(0); +} + +int KviDccVideoNullCodec::encodedFrameSize() +{ + return 1024; +} + +int KviDccVideoNullCodec::decodedFrameSize() +{ + return 1024; +} diff --git a/src/modules/dcc/codec.h b/src/modules/dcc/codec.h index 5cd8ee85b..7f0ed4f58 100644 --- a/src/modules/dcc/codec.h +++ b/src/modules/dcc/codec.h @@ -54,4 +54,30 @@ public: virtual int decodedFrameSize(); }; +class KviDccVideoCodec +{ +public: + KviDccVideoCodec(); + virtual ~KviDccVideoCodec(); +protected: + KviStr m_szName; +public: + const char * name(); + virtual void encode(KviDataBuffer * signal,KviDataBuffer * stream); + virtual void decode(KviDataBuffer * stream,KviDataBuffer * signal); + virtual int encodedFrameSize(); + virtual int decodedFrameSize(); +}; + +class KviDccVideoNullCodec : public KviDccVideoCodec +{ +public: + KviDccVideoNullCodec(); + virtual ~KviDccVideoNullCodec(); +public: + virtual void encode(KviDataBuffer * signal,KviDataBuffer * stream); + virtual void decode(KviDataBuffer * stream,KviDataBuffer * signal); + virtual int encodedFrameSize(); + virtual int decodedFrameSize(); +}; #endif //_CODEC_H_ diff --git a/src/modules/dcc/libkvidcc.cpp b/src/modules/dcc/libkvidcc.cpp index 620a6f3e6..3231a68df 100644 --- a/src/modules/dcc/libkvidcc.cpp +++ b/src/modules/dcc/libkvidcc.cpp @@ -25,6 +25,7 @@ #include "gsmcodec.h" #include "broker.h" #include "voice.h" +#include "video.h" #include "utils.h" #include "send.h" #include "window.h" @@ -1181,6 +1182,69 @@ static bool dcc_kvs_cmd_voice(KviKvsModuleCommandCall * c) } +static bool dcc_kvs_cmd_video(KviKvsModuleCommandCall * c) +{ + QString szTarget; + KVSM_PARAMETERS_BEGIN(c) + KVSM_PARAMETER("target",KVS_PT_NONEMPTYSTRING,0,szTarget) + KVSM_PARAMETERS_END(c) + +#ifdef COMPILE_DISABLE_DCC_VIDEO + c->warning(__tr2qs_ctx("DCC VIDEO support not enabled at compilation time","dcc")); + return true; +#endif + + KviDccDescriptor * d = new KviDccDescriptor(c->window()->console()); + + d->szNick = szTarget; // we always specify the nickname + d->szUser = __tr2qs_ctx("unknown","dcc"); // username is always unknown + d->szHost = d->szUser; // host is always unknown + + if(!dcc_kvs_parse_default_parameters(d,c))return false; + + d->szCodec = "null"; + + if(KviKvsVariant * pCodec = c->switches()->find('g',"codec")) + { + QString szCodec; + pCodec->asString(szCodec); + + if(!kvi_dcc_video_is_valid_codec(szCodec.toUtf8().data())) + { + c->warning(__tr2qs_ctx("Invalid codec specified, defaulting to 'null'","dcc")); + d->szCodec = "null"; + } + } + + dcc_module_set_dcc_type(d,"VIDEO"); + if(c->switches()->find('c',"connect")) + { + if(!(c->switches()->find('i',"ip") && c->switches()->find('p',"port"))) + { + delete d; + c->error(__tr2qs_ctx("-c requires -i and -p","dcc")); + return false; + } + d->szIp = d->szListenIp; + d->szPort = d->szListenPort; + d->szListenIp = ""; // useless + d->szListenPort = ""; // useless + d->bActive = true; + + d->triggerCreationEvent(); + g_pDccBroker->activeVideoExecute(0,d); + } else { + d->szIp = __tr2qs_ctx("unknown","dcc"); + d->szPort = d->szIp; + d->bActive = false; + d->bSendRequest = !(c->switches()->find('n',"no-ctcp")); + + d->triggerCreationEvent(); + g_pDccBroker->passiveVideoExecute(d); + } + + return true; +} /* @@ -2698,6 +2762,7 @@ static bool dcc_module_init(KviModule * m) KVSM_REGISTER_SIMPLE_COMMAND(m,"send",dcc_kvs_cmd_send); KVSM_REGISTER_SIMPLE_COMMAND(m,"chat",dcc_kvs_cmd_chat); + KVSM_REGISTER_SIMPLE_COMMAND(m,"video",dcc_kvs_cmd_video); KVSM_REGISTER_SIMPLE_COMMAND(m,"voice",dcc_kvs_cmd_voice); KVSM_REGISTER_SIMPLE_COMMAND(m,"recv",dcc_kvs_cmd_recv); KVSM_REGISTER_SIMPLE_COMMAND(m,"rsend",dcc_kvs_cmd_rsend); diff --git a/src/modules/dcc/requests.cpp b/src/modules/dcc/requests.cpp index 5078dea91..3b27014c5 100644 --- a/src/modules/dcc/requests.cpp +++ b/src/modules/dcc/requests.cpp @@ -26,6 +26,7 @@ #include "gsmcodec.h" #include "broker.h" +#include "video.h" #include "voice.h" #include "utils.h" #include "send.h" @@ -1041,6 +1042,79 @@ static void dccModuleParseDccVoice(KviDccRequest *dcc) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// VIDEO +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void dccModuleParseDccVideo(KviDccRequest *dcc) +{ + // + // We have received a DCC VIDEO request in the following form: + // + // DCC VIDEO codec <ipaddress> <port> + // + // This means that we're requested to setup an ACTIVE voice connection + // ... Easy task :) + // + + if(!dcc_module_check_limits(dcc))return; + + if(!dcc_module_normalize_target_data(dcc,dcc->szParam2,dcc->szParam3))return; + +#ifdef COMPILE_DISABLE_DCC_VIDEO + if(!dcc->ctcpMsg->msg->haltOutput()) + { + dcc->ctcpMsg->msg->console()->output(KVI_OUT_DCCERROR, + __tr2qs_ctx("The above request cannot be accepted: DCC VIDEO support not enabled at compilation time ","dcc")); + return; + } +#endif + // Actually unused parameter + if(!kvi_dcc_video_is_valid_codec(dcc->szParam1.ptr())) + { + if(!dcc->ctcpMsg->msg->haltOutput()) + { + dcc->ctcpMsg->msg->console()->output(KVI_OUT_DCCERROR, + __tr2qs_ctx("The above request cannot be accepted: Unsupported codec '%s'","dcc"),dcc->szParam1.ptr()); + return; + } + } + +// bool bOk; + +// int iSampleRate = dcc->szParam4.toInt(&bOk); +// if(!bOk) +// { +// if(!dcc->ctcpMsg->msg->haltOutput()) +// { +// dcc->ctcpMsg->msg->console()->output(KVI_OUT_DCCMSG, +// __tr2qs_ctx("The above request appears to be broken: Invalid sample-rate '%s', defaulting to 8000","dcc"),dcc->szParam4.ptr()); +// } +// iSampleRate = 8000; +// } + + + KviDccDescriptor * d = new KviDccDescriptor(dcc->pConsole); + d->szNick = dcc->ctcpMsg->pSource->nick(); + d->szUser = dcc->ctcpMsg->pSource->user(); + d->szHost = dcc->ctcpMsg->pSource->host(); + dcc_fill_local_nick_user_host(d,dcc); + + + d->szIp = dcc->szParam2.ptr(); + d->szPort = dcc->szParam3.ptr(); + d->bActive = true; // we have to connect + d->bIsTdcc = false; + d->bNoAcks = false; // this has no meaning in voice + d->szCodec = dcc->szParam1; +// d->iSampleRate = iSampleRate; + d->bOverrideMinimize = false; + d->bAutoAccept = KVI_OPTION_BOOL(KviOption_boolAutoAcceptDccVideo); + dcc_module_set_dcc_type(d,"VIDEO"); + d->triggerCreationEvent(); + g_pDccBroker->activeVideoManage(d); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CANVAS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1101,7 +1175,7 @@ typedef struct _dccParseProcEntry dccParseProc proc; } dccParseProcEntry; -#define KVI_NUM_KNOWN_DCC_TYPES 27 +#define KVI_NUM_KNOWN_DCC_TYPES 28 static dccParseProcEntry dccParseProcTable[KVI_NUM_KNOWN_DCC_TYPES]= { @@ -1131,7 +1205,8 @@ static dccParseProcEntry dccParseProcTable[KVI_NUM_KNOWN_DCC_TYPES]= { "STRSEND", dccModuleParseDccRSend }, { "TSRSEND", dccModuleParseDccRSend }, { "CANVAS" , dccModuleParseDccCanvas }, - { "VOICE" , dccModuleParseDccVoice } + { "VOICE" , dccModuleParseDccVoice }, + { "VIDEO" , dccModuleParseDccVideo } }; diff --git a/src/modules/dcc/video.cpp b/src/modules/dcc/video.cpp new file mode 100644 index 000000000..525b356c7 --- /dev/null +++ b/src/modules/dcc/video.cpp @@ -0,0 +1,686 @@ +//============================================================================= +// +// File : video.cpp +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "video.h" +#include "marshal.h" +#include "broker.h" + +#include "kvi_settings.h" +#include "kvi_iconmanager.h" +#include "kvi_ircview.h" +#include "kvi_locale.h" +#include "kvi_out.h" +#include "kvi_error.h" +#include "kvi_netutils.h" +#include "kvi_options.h" +#include "kvi_console.h" +#include "kvi_malloc.h" +#include "kvi_socket.h" +#include "kvi_ircconnection.h" +#include "kvi_tal_vbox.h" + +#include <QToolTip> +#include <QByteArray> +#include <QBuffer> + +extern KviDccBroker * g_pDccBroker; + +//Check for the *SS Api....we don't want to fail here... + +bool kvi_dcc_video_is_valid_codec(const char * codecName) +{ +// if(kvi_strEqualCI("jpeg",codecName))return true; + if(kvi_strEqualCI("null",codecName))return true; + return false; +} + +static KviDccVideoCodec * kvi_dcc_video_get_codec(const char *) +{ +// if(kvi_strEqualCI("jpeg",codecName))return new KviDccVoiceAdpcmCodec(); + //if(kvi_strEqualCI("null",codecName)) + return new KviDccVideoNullCodec(); +// return new KviDccVoiceAdpcmCodec(); +} + + +KviDccVideoThread::KviDccVideoThread(KviWindow * wnd,kvi_socket_t fd,KviDccVideoThreadOptions * opt) +: KviDccThread(wnd,fd) +{ +#ifndef COMPILE_DISABLE_DCC_VIDEO + m_pOpt = opt; + m_bPlaying = false; + m_bRecording = false; + m_pInfoMutex = new KviMutex(); + m_bRecordingRequestPending = false; +#endif + startRecording(); + startPlaying(); +} + +KviDccVideoThread::~KviDccVideoThread() +{ + stopRecording(); +#ifndef COMPILE_DISABLE_DCC_VIDEO + delete m_pOpt->pCodec; + delete m_pOpt; + delete m_pInfoMutex; +#endif +} + +bool KviDccVideoThread::readWriteStep() +{ +#ifndef COMPILE_DISABLE_DCC_VIDEO + // Socket management + bool bCanRead; + bool bCanWrite; + + if(kvi_select(m_fd,&bCanRead,&bCanWrite)) + { + if(bCanRead) + { + unsigned int actualSize = m_inFrameBuffer.size(); + m_inFrameBuffer.resize(actualSize + 1024); + int readLen = kvi_socket_recv(m_fd,(void *)(m_inFrameBuffer.data() + actualSize),1024); + if(readLen > 0) + { + if(readLen < 1024)m_inFrameBuffer.resize(actualSize + readLen); + m_pOpt->pCodec->decode(&m_inFrameBuffer,&m_inSignalBuffer); +//#warning "A maximum length for the signal buffer is actually needed!!!" + } else { + if(!handleInvalidSocketRead(readLen))return false; + m_inFrameBuffer.resize(actualSize); + } + }// else { + // m_uSleepTime += 100; + //} + + if(bCanWrite) + { + // Have somethihg to write ? + if(m_outFrameBuffer.size() > 0) + { + int written = kvi_socket_send(m_fd,m_outFrameBuffer.data(),m_outFrameBuffer.size()); + if(written > 0) + { + m_outFrameBuffer.remove(written); + } else { + if(!handleInvalidSocketRead(written))return false; + } + }// else { + // m_uSleepTime += 100; + // } + }// else { + // m_uSleepTime += 100; +// } +//#warning "Usleep here ?" + }// else { +// if(!(m_bPlaying || m_bRecording)) +// { +// // Really NOTHING is happening...sleep a bit more +// m_uSleepTime += 800; +// } else { +// m_uSleepTime += 100; +// } +// } + +#endif // !COMPILE_DISABLE_DCC_VOICE + return true; +} + +bool KviDccVideoThread::videoStep() +{ +#ifndef COMPILE_DISABLE_DCC_VIDEO + // Are we playing ? + if(m_bPlaying) + { + if(m_inSignalBuffer.size() > 0) + { + unsigned const char jpg_magic_init[4] = { 0xFF, 0xD8, 0xFF, 0xE0}; //SOI + APP0 + unsigned const char jpg_magic_end[2] = { 0xFF, 0xD9}; //EOI + int start = m_inSignalBuffer.find(jpg_magic_init, 4); + int end = m_inSignalBuffer.find(jpg_magic_end, 2); + qDebug("start %d end %d", start, end); + if(start != -1 && end != -1) + { + //remove junk before jpeg start + m_inSignalBuffer.remove(start); + int len = end - start + 1; + QImage img; + img.loadFromData(m_inSignalBuffer.data(), len, "JPEG"); + if(!img.isNull()) + { + m_inImage = img; + qDebug("img in"); + } + m_inSignalBuffer.remove(len); + } + } + } + + // Are we recording ? + if(m_bRecording) + { + //grab the image, compress using the codec + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + //0 to obtain small compressed files, + //100 for large uncompressed files, + //and -1 (the default) to use the default settings. + ((KviDccVideo*)KviDccThread::parent())->m_Image.save(&buffer, "JPEG", 20); + if(ba.size() > 0) + { + m_outSignalBuffer.append((const unsigned char*) ba.data(), ba.size()); + m_pOpt->pCodec->encode(&m_outSignalBuffer,&m_outFrameBuffer); + } + } + +#endif // !COMPILE_DISABLE_DCC_VIDEO + return true; +} + +void KviDccVideoThread::startRecording() +{ +#ifndef COMPILE_DISABLE_DCC_VIDEO + //debug("Start recording"); + if(m_bRecording)return; // already started + + //if(openSoundcardForReading()) + if(1) + { +// debug("Posting event"); + KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION); + e->setData(new int(KVI_DCC_VIDEO_THREAD_ACTION_START_RECORDING)); + postEvent(KviDccThread::parent(),e); + + m_bRecording = true; + m_bRecordingRequestPending = false; + } else { + m_bRecordingRequestPending = true; + } +#endif +} + +void KviDccVideoThread::stopRecording() +{ +#ifndef COMPILE_DISABLE_DCC_VIDEO + //debug("Stop recording"); + m_bRecordingRequestPending = false; + if(!m_bRecording)return; // already stopped + + KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION); + e->setData(new int(KVI_DCC_VIDEO_THREAD_ACTION_STOP_RECORDING)); + postEvent(KviDccThread::parent(),e); + + m_bRecording = false; +// if(!m_bPlaying)closeSoundcard(); +#endif +} + +void KviDccVideoThread::startPlaying() +{ +#ifndef COMPILE_DISABLE_DCC_VIDEO + //debug("Start playing"); + if(m_bPlaying)return; + + KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION); + e->setData(new int(KVI_DCC_VIDEO_THREAD_ACTION_START_PLAYING)); + postEvent(KviDccThread::parent(),e); + m_bPlaying = true; + +#endif +} + +void KviDccVideoThread::stopPlaying() +{ +#ifndef COMPILE_DISABLE_DCC_VIDEO + //debug("Stop playing"); + if(!m_bPlaying)return; + + KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION); + e->setData(new int(KVI_DCC_VIDEO_THREAD_ACTION_STOP_PLAYING)); + postEvent(KviDccThread::parent(),e); + + m_bPlaying = false; +#endif +} + +void KviDccVideoThread::run() +{ +#ifndef COMPILE_DISABLE_DCC_VIDEO + for(;;) + { +// m_uSleepTime = 0; + + // Dequeue events + while(KviThreadEvent * e = dequeueEvent()) + { + if(e->id() == KVI_THREAD_EVENT_TERMINATE) + { + delete e; + goto exit_dcc; + } else if(e->id() == KVI_DCC_THREAD_EVENT_ACTION) + { + int * act = ((KviThreadDataEvent<int> *)e)->getData(); + if(*act)startRecording(); + else stopRecording(); + delete act; + delete e; + } else { + // Other events are senseless to us + delete e; + } + } + + if(!readWriteStep())goto exit_dcc; + if(!videoStep())goto exit_dcc; + + m_pInfoMutex->lock(); + m_iInputBufferSize = m_inSignalBuffer.size(); + m_iOutputBufferSize = (m_outFrameBuffer.size() / m_pOpt->pCodec->encodedFrameSize()) * m_pOpt->pCodec->decodedFrameSize(); + m_pInfoMutex->unlock(); + + // Start recording if the request was not fulfilled yet + if(m_bRecordingRequestPending)startRecording(); + } + + +exit_dcc: + +#endif //! COMPILE_DISABLE_DCC_VIDEO + kvi_socket_close(m_fd); + m_fd = KVI_INVALID_SOCKET; +} + +KviDccVideo::KviDccVideo(KviFrame *pFrm,KviDccDescriptor * dcc,const char * name) +: KviDccWindow(KVI_WINDOW_TYPE_DCCVOICE,pFrm,name,dcc) +{ + m_pDescriptor = dcc; + m_pSlaveThread = 0; + m_pszTarget = 0; + + m_pLayout = new QGridLayout(); + + //remote video + m_pInVideoLabel = new QLabel(); + m_pInVideoLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_pInVideoLabel->setMinimumSize(320, 240); + m_pInVideoLabel->setFrameShape(QFrame::Box); + m_pInVideoLabel->setScaledContents(true); + m_pInVideoLabel->setAlignment(Qt::AlignCenter); + m_pLayout->addWidget(m_pInVideoLabel, 0, 0, 10, 1); + + //local video + m_pOutVideoLabel = new QLabel(); + m_pOutVideoLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_pOutVideoLabel->setMinimumSize(320, 240); + m_pOutVideoLabel->setFrameShape(QFrame::Box); + m_pOutVideoLabel->setScaledContents(true); + m_pOutVideoLabel->setAlignment(Qt::AlignCenter); + m_pLayout->addWidget(m_pOutVideoLabel, 11, 0, 10, 1); + + //local video input + m_pVideoDevicePool = Kopete::AV::VideoDevicePool::self(); + m_pVideoDevicePool->open(); + m_pVideoDevicePool->setSize(320, 240); + + //local video input: config + m_pLabel[0] = new QLabel(); + m_pLabel[0]->setText(__tr2qs_ctx("Video device:","dcc")); + m_pLayout->addWidget(m_pLabel[0], 11, 1, 1, 1); + + m_pCDevices = new QComboBox(); + m_pVideoDevicePool->fillDeviceQComboBox(m_pCDevices); + m_pLayout->addWidget(m_pCDevices, 12, 1, 1, 1); + + m_pLabel[1] = new QLabel(); + m_pLabel[1]->setText(__tr2qs_ctx("Input:","dcc")); + m_pLayout->addWidget(m_pLabel[1], 13, 1, 1, 1); + + m_pCInputs = new QComboBox(); + m_pVideoDevicePool->fillInputQComboBox(m_pCInputs); + m_pLayout->addWidget(m_pCInputs, 14, 1, 1, 1); + + m_pLabel[2] = new QLabel(); + m_pLabel[2]->setText(__tr2qs_ctx("Standard:","dcc")); + m_pLayout->addWidget(m_pLabel[2], 15, 1, 1, 1); + + m_pCStandards = new QComboBox(); + m_pVideoDevicePool->fillStandardQComboBox(m_pCStandards); + m_pLayout->addWidget(m_pCStandards, 16, 1, 1, 1); + + setLayout(m_pLayout); + + m_pVideoDevicePool->startCapturing(); + + connect(m_pVideoDevicePool, SIGNAL(deviceRegistered(const QString &) ), SLOT(deviceRegistered(const QString &)) ); + connect(m_pVideoDevicePool, SIGNAL(deviceUnregistered(const QString &) ), SLOT(deviceUnregistered(const QString &)) ); + + connect(&m_Timer, SIGNAL(timeout()), this, SLOT(slotUpdateImage()) ); + if ( m_pVideoDevicePool->hasDevices() ) + { + m_Timer.start(40); //25fps + } + + m_pMarshal = new KviDccMarshal(this); + connect(m_pMarshal,SIGNAL(error(int)),this,SLOT(handleMarshalError(int))); + connect(m_pMarshal,SIGNAL(connected()),this,SLOT(connected())); + connect(m_pMarshal,SIGNAL(inProgress()),this,SLOT(connectionInProgress())); + + startConnection(); +} + +KviDccVideo::~KviDccVideo() +{ + m_pVideoDevicePool->close(); + + if(m_pInVideoLabel) + { + delete m_pInVideoLabel; + m_pInVideoLabel=0; + } + if(m_pOutVideoLabel) + { + delete m_pOutVideoLabel; + m_pOutVideoLabel=0; + } + if(m_pCDevices) + { + delete m_pCDevices; + m_pCDevices=0; + } + if(m_pCInputs) + { + delete m_pCInputs; + m_pCInputs=0; + } + if(m_pCStandards) + { + delete m_pCStandards; + m_pCStandards=0; + } + if(m_pLabel[0]) + { + delete m_pLabel[2]; + delete m_pLabel[1]; + delete m_pLabel[0]; + m_pLabel[2] = 0; + m_pLabel[1] = 0; + m_pLabel[0] = 0; + } + if(m_pLayout) + { + delete m_pLayout; + m_pLayout=0; + } + + g_pDccBroker->unregisterDccWindow(this); + + if(m_pSlaveThread) + { + m_pSlaveThread->terminate(); + delete m_pSlaveThread; + m_pSlaveThread = 0; + } + + KviThreadManager::killPendingEvents(this); + + if(m_pszTarget) + { + delete m_pszTarget; + m_pszTarget = 0; + } +} + +void KviDccVideo::startConnection() +{ + if(!(m_pDescriptor->bActive)) + { + // PASSIVE CONNECTION + output(KVI_OUT_DCCMSG,__tr2qs_ctx("Attempting a passive DCC VIDEO connection","dcc")); + int ret = m_pMarshal->dccListen(m_pDescriptor->szListenIp,m_pDescriptor->szListenPort,m_pDescriptor->bDoTimeout); + if(ret != KviError_success)handleMarshalError(ret); + } else { + // ACTIVE CONNECTION + output(KVI_OUT_DCCMSG,__tr2qs_ctx("Attempting an active DCC VIDEO connection","dcc")); + int ret = m_pMarshal->dccConnect(m_pDescriptor->szIp.toUtf8().data(),m_pDescriptor->szPort.toUtf8().data(),m_pDescriptor->bDoTimeout); + if(ret != KviError_success)handleMarshalError(ret); + } +} + +void KviDccVideo::connectionInProgress() +{ + if(m_pDescriptor->bActive) + { + output(KVI_OUT_DCCMSG,__tr2qs_ctx("Contacting host %Q on port %Q","dcc"),&(m_pDescriptor->szIp),&(m_pDescriptor->szPort)); + } else { + + output(KVI_OUT_DCCMSG,__tr2qs_ctx("Listening on interface %Q port %Q","dcc"), + &(m_pMarshal->localIp()),&(m_pMarshal->localPort())); + + if(m_pDescriptor->bSendRequest) + { + QString ip = !m_pDescriptor->szFakeIp.isEmpty() ? m_pDescriptor->szFakeIp : m_pDescriptor->szListenIp; + KviStr port = !m_pDescriptor->szFakePort.isEmpty() ? m_pDescriptor->szFakePort : m_pMarshal->localPort(); +//#warning "OPTION FOR SENDING 127.0.0.1 and so on (not an unsigned nuumber)" + struct in_addr a; + if(KviNetUtils::stringIpToBinaryIp(ip,&a)) { + ip.setNum(htonl(a.s_addr)); + } + + m_pDescriptor->console()->connection()->sendFmtData("PRIVMSG %s :%cDCC VIDEO %s %Q %s %d%c", + m_pDescriptor->console()->connection()->encodeText(m_pDescriptor->szNick).data(), + 0x01,m_pDescriptor->szCodec.ptr(), + &ip,port.ptr(),m_pDescriptor->iSampleRate,0x01); + output(KVI_OUT_DCCMSG,__tr2qs_ctx("Sent DCC VIDEO (%s) request to %Q, waiting for the remote client to connect...","dcc"), + m_pDescriptor->szCodec.ptr(),&(m_pDescriptor->szNick)); + } else output(KVI_OUT_DCCMSG,__tr2qs_ctx("DCC VIDEO request not sent: awaiting manual connections","dcc")); + } +} + +const QString & KviDccVideo::target() +{ + // This may change on the fly... + if(!m_pszTarget) + m_pszTarget = new QString(); + + m_pszTarget->sprintf("%s@%s:%s",m_pDescriptor->szNick.toUtf8().data(),m_pDescriptor->szIp.toUtf8().data(),m_pDescriptor->szPort.toUtf8().data()); + return *m_pszTarget; +} + +void KviDccVideo::getBaseLogFileName(QString &buffer) +{ + buffer.sprintf("dccvideo_%s_%s_%s",m_pDescriptor->szNick.toUtf8().data(),m_pDescriptor->szLocalFileName.toUtf8().data(),m_pDescriptor->szPort.toUtf8().data()); +} + +void KviDccVideo::fillCaptionBuffers() +{ + KviStr tmp(KviStr::Format,"DCC Video %s@%s:%s %s", + m_pDescriptor->szNick.toUtf8().data(),m_pDescriptor->szIp.toUtf8().data(),m_pDescriptor->szPort.toUtf8().data(), + m_pDescriptor->szLocalFileName.toUtf8().data()); + + m_szPlainTextCaption = tmp; +} + +QPixmap * KviDccVideo::myIconPtr() +{ + return g_pIconManager->getSmallIcon(KVI_SMALLICON_DCCVOICE); +} + +bool KviDccVideo::event(QEvent *e) +{ + if(e->type() == KVI_THREAD_EVENT) + { + switch(((KviThreadEvent *)e)->id()) + { + case KVI_DCC_THREAD_EVENT_ERROR: + { + int * err = ((KviThreadDataEvent<int> *)e)->getData(); + QString ssss = KviError::getDescription(*err); + output(KVI_OUT_DCCERROR,__tr2qs_ctx("ERROR: %Q","dcc"),&(ssss)); + delete err; +/* m_pTalkButton->setEnabled(false); + m_pRecordingLabel->setEnabled(false); + m_pPlayingLabel->setEnabled(false);*/ + return true; + } + break; + case KVI_DCC_THREAD_EVENT_MESSAGE: + { + KviStr * str = ((KviThreadDataEvent<KviStr> *)e)->getData(); + outputNoFmt(KVI_OUT_DCCMSG,__tr_no_xgettext_ctx(str->ptr(),"dcc")); + delete str; + return true; + } + break; + case KVI_DCC_THREAD_EVENT_ACTION: + { + int * act = ((KviThreadDataEvent<int> *)e)->getData(); + switch(*act) + { + case KVI_DCC_VIDEO_THREAD_ACTION_START_RECORDING: +// m_pRecordingLabel->setEnabled(true); + break; + case KVI_DCC_VIDEO_THREAD_ACTION_STOP_RECORDING: +// m_pRecordingLabel->setEnabled(false); + break; + case KVI_DCC_VIDEO_THREAD_ACTION_START_PLAYING: +// m_pPlayingLabel->setEnabled(true); + break; + case KVI_DCC_VIDEO_THREAD_ACTION_STOP_PLAYING: +// m_pPlayingLabel->setEnabled(false); + break; + } + delete act; + return true; + } + break; + default: + debug("Invalid event type %d received",((KviThreadEvent *)e)->id()); + break; + } + + } + + return KviWindow::event(e); +} + +void KviDccVideo::handleMarshalError(int err) +{ + QString ssss = KviError::getDescription(err); + output(KVI_OUT_DCCERROR,__tr2qs_ctx("DCC Failed: %Q","dcc"),&ssss); +/* m_pTalkButton->setEnabled(false); + m_pTalkButton->setChecked(false); + m_pRecordingLabel->setEnabled(false); + m_pPlayingLabel->setEnabled(false);*/ +} + +void KviDccVideo::connected() +{ + output(KVI_OUT_DCCMSG,__tr2qs_ctx("Connected to %Q:%Q","dcc"), + &(m_pMarshal->remoteIp()),&(m_pMarshal->remotePort())); + output(KVI_OUT_DCCMSG,__tr2qs_ctx("Local end is %Q:%Q","dcc"), + &(m_pMarshal->localIp()),&(m_pMarshal->localPort())); + if(!(m_pDescriptor->bActive)) + { + m_pDescriptor->szIp = m_pMarshal->remoteIp(); + m_pDescriptor->szPort = m_pMarshal->remotePort(); + m_pDescriptor->szHost = m_pMarshal->remoteIp(); + } + updateCaption(); + + KviDccVideoThreadOptions * opt = new KviDccVideoThreadOptions; + + opt->pCodec = kvi_dcc_video_get_codec(m_pDescriptor->szCodec.ptr()); + + output(KVI_OUT_DCCMSG,__tr2qs_ctx("Actual codec used is '%s'","dcc"),opt->pCodec->name()); + + m_pSlaveThread = new KviDccVideoThread(this,m_pMarshal->releaseSocket(),opt); + m_pSlaveThread->start(); + +// m_pTalkButton->setEnabled(true); +} + +void KviDccVideo::stopTalking() +{ + KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION); + e->setData(new int(0)); + m_pSlaveThread->enqueueEvent(e); +} + +void KviDccVideo::startTalking() +{ + KviThreadDataEvent<int> * e = new KviThreadDataEvent<int>(KVI_DCC_THREAD_EVENT_ACTION); + e->setData(new int(1)); + m_pSlaveThread->enqueueEvent(e); +} + +void KviDccVideo::startOrStopTalking(bool bStart) +{ + if(bStart)startTalking(); + else stopTalking(); +} + +void KviDccVideo::slotUpdateImage() +{ + m_pVideoDevicePool->getFrame(); + m_pVideoDevicePool->getImage(&m_Image); + if(isVisible()) + { + m_pOutVideoLabel->setPixmap(QPixmap::fromImage(m_Image.mirrored(m_pVideoDevicePool->getImageAsMirror(),false))); + if(m_pSlaveThread) + m_pInVideoLabel->setPixmap(QPixmap::fromImage(m_pSlaveThread->m_inImage)); + } +} + +void KviDccVideo::deviceRegistered(const QString &) +{ + m_pVideoDevicePool->fillDeviceQComboBox(m_pCDevices); + m_pVideoDevicePool->fillInputQComboBox(m_pCInputs); + m_pVideoDevicePool->fillStandardQComboBox(m_pCStandards); + + // update the mVideoImageLabel to show the camera frames + m_pVideoDevicePool->open(); + m_pVideoDevicePool->setSize(320, 240); + m_pVideoDevicePool->startCapturing(); + +// setVideoInputParameters(); + + if ( m_pVideoDevicePool->hasDevices() ) + { + m_Timer.start(200); //5fps + } +} + + +void KviDccVideo::deviceUnregistered(const QString & ) +{ + m_pVideoDevicePool->fillDeviceQComboBox(m_pCDevices); + m_pVideoDevicePool->fillInputQComboBox(m_pCInputs); + m_pVideoDevicePool->fillStandardQComboBox(m_pCStandards); +} + +#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES +#include "m_video.moc" +#endif //!COMPILE_USE_STANDALONE_MOC_SOURCES diff --git a/src/modules/dcc/video.h b/src/modules/dcc/video.h new file mode 100644 index 000000000..abae4db38 --- /dev/null +++ b/src/modules/dcc/video.h @@ -0,0 +1,155 @@ +#ifndef _VIDEO_H_ +#define _VIDEO_H_ +//============================================================================= +// +// File : video.h +// Creation date : Tue Nov 10 18:08:09 2009 GMT by Fabio Bas +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2009 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "codec.h" +#include "descriptor.h" +#include "thread.h" +#include "window.h" + +#include "kvi_window.h" +#include "kvi_databuffer.h" +#include "kvi_sockettype.h" +#include "kvi_tal_hbox.h" + +#include <QLabel> +#include <QToolButton> +#include <QTimer> +#include <QImage> +#include <QPixmap> +#include <QComboBox> +#include <QGridLayout> + +#include "avdevice/videodevicepool.h" + +class QSlider; +class KviDccMarshal; + +#ifndef _DCC_VIDEO_CPP_ + extern bool kvi_dcc_video_is_valid_codec(const char * codecName); +#endif + +#define KVI_DCC_VIDEO_THREAD_ACTION_START_RECORDING 0 +#define KVI_DCC_VIDEO_THREAD_ACTION_STOP_RECORDING 1 +#define KVI_DCC_VIDEO_THREAD_ACTION_START_PLAYING 2 +#define KVI_DCC_VIDEO_THREAD_ACTION_STOP_PLAYING 3 + +typedef struct _KviDccVideoThreadOptions +{ + QString szVideoDevice; + KviDccVideoCodec * pCodec; +} KviDccVideoThreadOptions; + +class KviDccVideoThread : public KviDccThread +{ + friend class KviDccVideo; +public: + KviDccVideoThread(KviWindow * wnd,kvi_socket_t fd,KviDccVideoThreadOptions * opt); + ~KviDccVideoThread(); +protected: + KviDccVideoThreadOptions * m_pOpt; + KviDataBuffer m_outFrameBuffer; + KviDataBuffer m_inFrameBuffer; + KviDataBuffer m_inSignalBuffer; + KviDataBuffer m_outSignalBuffer; + bool m_bPlaying; + bool m_bRecording; + bool m_bRecordingRequestPending; + KviMutex * m_pInfoMutex; + // stuff protected by the mutex: + int m_iInputBufferSize; + int m_iOutputBufferSize; + QImage m_inImage; +protected: + bool readWriteStep(); + bool videoStep(); + void startRecording(); + void stopRecording(); + void startPlaying(); + void stopPlaying(); + inline bool isPlaying() { return m_bPlaying; }; + virtual void run(); +}; + + +class KviDccVideo : public KviDccWindow +{ + Q_OBJECT + friend class KviDccVideoThread; +public: + KviDccVideo(KviFrame *pFrm,KviDccDescriptor * dcc,const char * name); + ~KviDccVideo(); +protected: + QLabel *m_pInVideoLabel; + QLabel *m_pOutVideoLabel; + Kopete::AV::VideoDevicePool *m_pVideoDevicePool; + QComboBox *m_pCDevices; + QComboBox *m_pCInputs; + QComboBox *m_pCStandards; + QGridLayout *m_pLayout; + QImage m_Image; + QTimer m_Timer; + QLabel * m_pLabel[2]; +/* + KviTalHBox * m_pHBox; + QSlider * m_pVolumeSlider; + QLabel * m_pInputLabel; + QLabel * m_pOutputLabel; + QLabel * m_pRecordingLabel; + QLabel * m_pPlayingLabel; + QToolButton * m_pTalkButton; +*/ + QString * m_pszTarget; + KviDccVideoThread * m_pSlaveThread; +protected: +// virtual void focusInEvent(QFocusEvent *); + virtual const QString & target(); + virtual void fillCaptionBuffers(); + virtual QPixmap * myIconPtr(); +/* + virtual void resizeEvent(QResizeEvent *e); + virtual QSize sizeHint() const; +*/ + virtual bool event(QEvent *e); + virtual void getBaseLogFileName(QString &buffer); + void startTalking(); + void stopTalking(); + void startConnection(); +// int getMixerVolume(void) const; +protected slots: + void handleMarshalError(int err); + void connected(); + void startOrStopTalking(bool bStart); +/* + void setMixerVolume(int); +*/ + void connectionInProgress(); + void slotUpdateImage(); + void deviceRegistered(const QString &); + void deviceUnregistered(const QString &); +}; + + +#endif //_VOICE_H_ |
