diff -Nru webcamoid-8.6.1+dfsg/appveyor.yml webcamoid-8.8.0+dfsg/appveyor.yml --- webcamoid-8.6.1+dfsg/appveyor.yml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/appveyor.yml 2021-02-15 15:25:23.000000000 +0000 @@ -1,7 +1,7 @@ -version: 8.6.1.{build}-{branch} +version: 8.8.0.{build}-{branch} os: MinGW -image: Visual Studio 2017 +image: Visual Studio 2019 platform: - x64 @@ -14,63 +14,42 @@ - release # - debug -branches: - only: - - master - environment: global: - FFMPEG_VERSION: 4.1 - GSTREAMER_VERSION: 1.14.4 - PYTHON_VERSION: Python37 - QMAKESPEC: win32-g++ - MAKETOOL: mingw32-make INSTALL_PREFIX: C:/projects/webcamoid/ports/deploy/temp_priv/usr # api key from https://bintray.com/profile/edit - # encrypted in https://ci.appveyor.com/tools/encrypt + # encrypted with https://ci.appveyor.com/tools/encrypt BT_KEY: - secure: seneRk4ppI4bquIsdweI8pd8FT0RXUvU2LOUNGSBEA28IhFQijypil2CfC3WtJxa + secure: UovqScFlz2shj+pxGyhQUYFiCvYJWEBGuhRCbaC3Bfxm0k9qo/pHYlp6Vx3jLIt9 matrix: - - MSYS2_BUILD: 1 - - QTDIR: C:\Qt\5.12\mingw73_64 - TOOLSDIR: C:\Qt\Tools\mingw730_64 - - QTDIR: C:\Qt\5.12\msvc2017 - TOOLSDIR: C:\Qt\Tools\QtCreator - QMAKESPEC: win32-msvc - VSPATH: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build - MAKETOOL: jom - PLATFORM: x86 - - QTDIR: C:\Qt\5.12\msvc2017_64 - TOOLSDIR: C:\Qt\Tools\QtCreator - QMAKESPEC: win32-msvc - VSPATH: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build - MAKETOOL: jom + - PLATFORM: x86 + DAILY_BUILD: 1 + - PLATFORM: x64 + DAILY_BUILD: 1 + - PLATFORM: x86 + RELEASE_BUILD: 1 + - PLATFORM: x64 + RELEASE_BUILD: 1 + - PLATFORM: x86 + - PLATFORM: x64 install: - - if "%MSYS2_BUILD%" == "" ( - ports\ci\appveyor\install_deps.bat - ) else ( - C:\msys64\usr\bin\bash -lc "cd /c/projects/webcamoid && ./ports/ci/appveyor/install_deps.sh" - ) + - ports\ci\appveyor\environment_setup.bat + - C:\msys64\usr\bin\bash -lc "cd /c/projects/webcamoid && ./ports/ci/appveyor/install_deps.sh" build_script: - - if "%MSYS2_BUILD%" == "" ( - ports\ci\appveyor\build.bat - ) else ( - C:\msys64\usr\bin\bash -lc "cd /c/projects/webcamoid && ./ports/ci/appveyor/build.sh '%INSTALL_PREFIX%'" - ) + - ports\ci\appveyor\environment_setup.bat + - C:\msys64\usr\bin\bash -lc "cd /c/projects/webcamoid && ./ports/ci/appveyor/build.sh after_build: - - if "%MSYS2_BUILD%" == "" ( - ports\ci\appveyor\deploy.bat - ) else ( - C:\msys64\usr\bin\bash -lc "cd /c/projects/webcamoid && ./ports/ci/appveyor/deploy.sh" - ) - - ports\ci\appveyor\push_artifacts.bat + - ports\ci\appveyor\environment_setup.bat + - C:\msys64\usr\bin\bash -lc "cd /c/projects/webcamoid && ./ports/ci/appveyor/deploy.sh" + - C:\msys64\usr\bin\bash -lc "cd /c/projects/webcamoid && ./ports/ci/appveyor/push_artifacts.sh" deploy_script: - - ports\ci\appveyor\upload.bat + - ports\ci\appveyor\environment_setup.bat + - C:\msys64\usr\bin\bash -lc "cd /c/projects/webcamoid && ./ports/ci/appveyor/upload.sh" notifications: - provider: Email diff -Nru webcamoid-8.6.1+dfsg/ChangeLog webcamoid-8.8.0+dfsg/ChangeLog --- webcamoid-8.6.1+dfsg/ChangeLog 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ChangeLog 2021-02-15 15:25:23.000000000 +0000 @@ -1,3 +1,32 @@ +Webcamoid 8.8.0: + +- Fixed bug when setting boolean type automatic controls in Windows + (issue #148) +- Added option for blurring outside detected face in FaceDetect plugin + (thanks Erich Schubert!). +- Added plublic method for detecteding face rectangles in FaceDetect plugin + (thanks Chris Barth!). +- Fixed some minor bugs when capturing from camera. + +Webcamoid 8.7.1: + +- Fixed memory grow when using the virtual camera in Mac. +- Disabled camera controls in Mac. +- Request access permissions for capturing from webcam when necessary in Mac. +- Load virtual camera default frame from file instead of resources. + +Webcamoid 8.7.0: + +- Android port more or less working, but not usable yet, you can test it in the + daily builds. There in not an official release yet. +- Removed unnecessary Bin and Probe plugins. +- Added audio latency control. +- Removed OSS and QtAudio submodules. +- Fixed a bug that happened when changing the format, resolution or FPS of the + camera (commit 41448aa). +- Improved error messages for the virtual camera (issue #187). +- Fixed segfaults. + Webcamoid 8.6.1: - AppImage now properly show the icon (issue #94). diff -Nru webcamoid-8.6.1+dfsg/.cirrus.yml webcamoid-8.8.0+dfsg/.cirrus.yml --- webcamoid-8.6.1+dfsg/.cirrus.yml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/.cirrus.yml 2021-02-15 15:25:23.000000000 +0000 @@ -1,10 +1,8 @@ build_task: freebsd_instance: matrix: - image: freebsd-12-0-release-amd64 - image: freebsd-11-2-release-amd64 - #image: freebsd-11-1-release-amd64 - #image: freebsd-10-4-release-amd64 + image_family: freebsd-13-0-snap + image_family: freebsd-12-2 cpu: 2 memory: 4G diff -Nru webcamoid-8.6.1+dfsg/commons.pri webcamoid-8.8.0+dfsg/commons.pri --- webcamoid-8.6.1+dfsg/commons.pri 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/commons.pri 2021-02-15 15:25:23.000000000 +0000 @@ -17,8 +17,8 @@ # Web-Site: http://webcamoid.github.io/ VER_MAJ = 8 -VER_MIN = 6 -VER_PAT = 1 +VER_MIN = 8 +VER_PAT = 0 VERSION = $${VER_MAJ}.$${VER_MIN}.$${VER_PAT} isEmpty(BUILDDOCS): BUILDDOCS = 0 @@ -126,7 +126,13 @@ } isEmpty(LOCALEDIR): LOCALEDIR = $${DATAROOTDIR}/locale isEmpty(MANDIR): MANDIR = $${DATAROOTDIR}/man -isEmpty(LICENSEDIR): LICENSEDIR = $${DATAROOTDIR}/licenses/$${COMMONS_TARGET} +isEmpty(LICENSEDIR) { + android { + LICENSEDIR = $${DATAROOTDIR} + } else { + LICENSEDIR = $${DATAROOTDIR}/licenses/$${COMMONS_TARGET} + } +} isEmpty(LOCALDIR): LOCALDIR = $${PREFIX}/local isEmpty(LOCALLIBDIR): LOCALLIBDIR = $${LOCALDIR}/lib isEmpty(INSTALLQMLDIR) { @@ -148,6 +154,7 @@ INSTALLPLUGINSDIR = $${LIBDIR}/$${COMMONS_TARGET} } } +isEmpty(JARDIR): JARDIR = $${EXECPREFIX}/libs macx: !isEmpty(NOAPPBUNDLE): DEFINES += NOAPPBUNDLE @@ -205,6 +212,8 @@ COMMONS_BUILD_PATH = release/Qt$${QT_VERSION}/$$COMPILER/$${TARGET_ARCH} } +android: COMMONS_BUILD_PATH = $${COMMONS_BUILD_PATH}/$${ANDROID_PLATFORM} + BIN_DIR = $${COMMONS_BUILD_PATH}/bin MOC_DIR = $${COMMONS_BUILD_PATH}/moc OBJECTS_DIR = $${COMMONS_BUILD_PATH}/obj @@ -235,7 +244,7 @@ win32-g++: QMAKE_LFLAGS = -static-libgcc -static-libstdc++ } } -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config # Enable c++11 support in all platforms !CONFIG(c++11): CONFIG += c++11 diff -Nru webcamoid-8.6.1+dfsg/debian/changelog webcamoid-8.8.0+dfsg/debian/changelog --- webcamoid-8.6.1+dfsg/debian/changelog 2021-08-12 05:28:45.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/changelog 2022-01-09 10:43:04.000000000 +0000 @@ -1,9 +1,21 @@ -webcamoid (8.6.1+dfsg-2.1ubuntu1) impish; urgency=medium +webcamoid (8.8.0+dfsg-1) unstable; urgency=medium - * Fix build with g++ 11 by adding an include of that was apparently - implicitly included by some other header. + * Update uscan support file + * New upstream version (closes: #956630) + * Refer to common license file for CC0-1.0. + * Use secure URI in Homepage field. + * Bump debhelper from old 12 to 13. + * Set upstream metadata fields: + Bug-Database, Bug-Submit, Repository, Repository-Browse. + * Update standards version to 4.6.0, no changes needed. + * Remove quilt patch: no need to specify full path of icon in desktop file + * Add quilt patch, need to #include (closes: #1002960) + * Adjust installation scripts for upstream changes and dh_missing + * Remove debian/*.symbols; it's not much use for this churning C++ library + * Adopt package; much thanks to Herbert Parentes Fortes Neto, the + previous maintainer - -- Michael Hudson-Doyle Thu, 12 Aug 2021 17:28:45 +1200 + -- Barak A. Pearlmutter Sun, 09 Jan 2022 10:43:04 +0000 webcamoid (8.6.1+dfsg-2.1) unstable; urgency=medium diff -Nru webcamoid-8.6.1+dfsg/debian/control webcamoid-8.8.0+dfsg/debian/control --- webcamoid-8.6.1+dfsg/debian/control 2021-08-12 05:28:45.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/control 2022-01-09 10:41:40.000000000 +0000 @@ -1,9 +1,8 @@ Source: webcamoid Section: video Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Herbert Parentes Fortes Neto -Build-Depends: debhelper-compat (= 12), +Maintainer: Barak A. Pearlmutter +Build-Depends: debhelper-compat (= 13), libasound2-dev, libavcodec-dev (>= 4.0), libavdevice-dev (>= 4.0), @@ -24,8 +23,8 @@ qtmultimedia5-dev, qtquickcontrols2-5-dev, qttools5-dev-tools -Standards-Version: 4.4.0 -Homepage: http://webcamoid.github.io/ +Standards-Version: 4.6.0 +Homepage: https://webcamoid.github.io/ Vcs-Git: https://salsa.debian.org/debian/webcamoid.git Vcs-Browser: https://salsa.debian.org/debian/webcamoid diff -Nru webcamoid-8.6.1+dfsg/debian/copyright webcamoid-8.8.0+dfsg/debian/copyright --- webcamoid-8.6.1+dfsg/debian/copyright 2020-03-06 21:11:09.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/copyright 2022-01-05 21:42:29.000000000 +0000 @@ -23,7 +23,7 @@ Files: libAvKys/Plugins/FaceDetect/share/masks/* Copyright: 2017 ? -License: CC0 +License: CC0-1.0 Comment: All files in THIS FOLDER incorporates work from https://openclipart.org/ @@ -78,125 +78,13 @@ arising in any way out of the use of this software, even if advised of the possibility of such damage. -License: CC0 - Creative Commons Legal Code +License: CC0-1.0 + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. . - CC0 1.0 Universal + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . . - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - . - Statement of Purpose - . - The laws of most jurisdictions throughout the world automatically confer - exclusive Copyright and Related Rights (defined below) upon the creator - and subsequent owner(s) (each and all, an "owner") of an original work of - authorship and/or a database (each, a "Work"). - . - Certain owners wish to permanently relinquish those rights to a Work for - the purpose of contributing to a commons of creative, cultural and - scientific works ("Commons") that the public can reliably and without fear - of later claims of infringement build upon, modify, incorporate in other - works, reuse and redistribute as freely as possible in any form whatsoever - and for any purposes, including without limitation commercial purposes. - These owners may contribute to the Commons to promote the ideal of a free - culture and the further production of creative, cultural and scientific - works, or to gain reputation or greater distribution for their Work in - part through the use and efforts of others. - . - For these and/or other purposes and motivations, and without any - expectation of additional consideration or compensation, the person - associating CC0 with a Work (the "Affirmer"), to the extent that he or she - is an owner of Copyright and Related Rights in the Work, voluntarily - elects to apply CC0 to the Work and publicly distribute the Work under its - terms, with knowledge of his or her Copyright and Related Rights in the - Work and the meaning and intended legal effect of CC0 on those rights. - . - 1. Copyright and Related Rights. A Work made available under CC0 may be - protected by copyright and related or neighboring rights ("Copyright and - Related Rights"). Copyright and Related Rights include, but are not - limited to, the following: - . - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); - iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and - vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - . - 2. Waiver. To the greatest extent permitted by, but not in contravention - of, applicable law, Affirmer hereby overtly, fully, permanently, - irrevocably and unconditionally waives, abandons, and surrenders all of - Affirmer's Copyright and Related Rights and associated claims and causes - of action, whether now known or unknown (including existing as well as - future claims and causes of action), in the Work (i) in all territories - worldwide, (ii) for the maximum duration provided by applicable law or - treaty (including future time extensions), (iii) in any current or future - medium and for any number of copies, and (iv) for any purpose whatsoever, - including without limitation commercial, advertising or promotional - purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each - member of the public at large and to the detriment of Affirmer's heirs and - successors, fully intending that such Waiver shall not be subject to - revocation, rescission, cancellation, termination, or any other legal or - equitable action to disrupt the quiet enjoyment of the Work by the public - as contemplated by Affirmer's express Statement of Purpose. - . - 3. Public License Fallback. Should any part of the Waiver for any reason - be judged legally invalid or ineffective under applicable law, then the - Waiver shall be preserved to the maximum extent permitted taking into - account Affirmer's express Statement of Purpose. In addition, to the - extent the Waiver is so judged Affirmer hereby grants to each affected - person a royalty-free, non transferable, non sublicensable, non exclusive, - irrevocable and unconditional license to exercise Affirmer's Copyright and - Related Rights in the Work (i) in all territories worldwide, (ii) for the - maximum duration provided by applicable law or treaty (including future - time extensions), (iii) in any current or future medium and for any number - of copies, and (iv) for any purpose whatsoever, including without - limitation commercial, advertising or promotional purposes (the - "License"). The License shall be deemed effective as of the date CC0 was - applied by Affirmer to the Work. Should any part of the License for any - reason be judged legally invalid or ineffective under applicable law, such - partial invalidity or ineffectiveness shall not invalidate the remainder - of the License, and in such case Affirmer hereby affirms that he or she - will not (i) exercise any of his or her remaining Copyright and Related - Rights in the Work or (ii) assert any associated claims and causes of - action with respect to the Work, in either case contrary to Affirmer's - express Statement of Purpose. - . - 4. Limitations and Disclaimers. - . - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. + On Debian systems, the full text of the CC0 1.0 Universal license can be found + in the file `/usr/share/common-licenses/CC0-1.0'. diff -Nru webcamoid-8.6.1+dfsg/debian/libavkys8.symbols webcamoid-8.8.0+dfsg/debian/libavkys8.symbols --- webcamoid-8.6.1+dfsg/debian/libavkys8.symbols 2020-03-06 21:11:09.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/libavkys8.symbols 1970-01-01 00:00:00.000000000 +0000 @@ -1,654 +0,0 @@ -libavkys.so.8 libavkys8 #MINVER# - _Z17qRegisterMetaTypeI11AkAudioCapsEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS3_Xaasr12QMetaTypeId2IS3_E7DefinedntsrS8_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeI11AkVideoCapsEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS3_Xaasr12QMetaTypeId2IS3_E7DefinedntsrS8_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeI6AkCapsEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS3_Xaasr12QMetaTypeId2IS3_E7DefinedntsrS8_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeI6AkFracEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS3_Xaasr12QMetaTypeId2IS3_E7DefinedntsrS8_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeI8AkPacketEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS3_Xaasr12QMetaTypeId2IS3_E7DefinedntsrS8_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeIN11AkAudioCaps12SampleFormatEEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS4_Xaasr12QMetaTypeId2IS4_E7DefinedntsrS9_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeIN11AkAudioCaps13ChannelLayoutEEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS4_Xaasr12QMetaTypeId2IS4_E7DefinedntsrS9_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeIN11AkVideoCaps11PixelFormatEEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS4_Xaasr12QMetaTypeId2IS4_E7DefinedntsrS9_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeIN6AkCaps8CapsTypeEEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS4_Xaasr12QMetaTypeId2IS4_E7DefinedntsrS9_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z17qRegisterMetaTypeIN9AkElement12ElementStateEEiPKcPT_N9QtPrivate21MetaTypeDefinedHelperIS4_Xaasr12QMetaTypeId2IS4_E7DefinedntsrS9_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z27qRegisterNormalizedMetaTypeI14QSharedPointerI9AkElementEEiRK10QByteArrayPT_N9QtPrivate21MetaTypeDefinedHelperIS6_Xaasr12QMetaTypeId2IS6_E7DefinedntsrSB_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _Z27qRegisterNormalizedMetaTypeI5QListIiEEiRK10QByteArrayPT_N9QtPrivate21MetaTypeDefinedHelperIS5_Xaasr12QMetaTypeId2IS5_E7DefinedntsrSA_9IsBuiltInEE11DefinedTypeE@Base 8.6.1+dfsg-1 - _ZGVZN11VideoFormat7formatsEvE12videoFormats@Base 8.6.1+dfsg-1 - _ZGVZN13SampleFormats7formatsEvE13sampleFormats@Base 8.6.1+dfsg-1 - _ZGVZN14ChannelLayouts7layoutsEvE14channelLayouts@Base 8.6.1+dfsg-1 - _ZGVZN9QtPrivate19ValueTypeIsMetaTypeI5QListIiELb1EE17registerConverterEiE1f@Base 8.6.1+dfsg-1 - _ZGVZN9QtPrivate26MetaTypeSmartPointerHelperI14QSharedPointerI9AkElementEvE17registerConverterEiE1f@Base 8.6.1+dfsg-1 - _ZN10QByteArrayD1Ev@Base 8.6.1+dfsg-1 - _ZN10QByteArrayD2Ev@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps10bpsChangedEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps10endiannessENS_12SampleFormatE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps10endiannessERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps10fromStringERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps10resetAlignEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps10sampleTypeENS_12SampleFormatE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps10sampleTypeERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps10setSamplesEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps11rateChangedEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps11resetFormatEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps11resetLayoutEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps11setChannelsEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps12alignChangedEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps12channelCountENS_13ChannelLayoutE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps12channelCountERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps12resetSamplesEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps13bitsPerSampleENS_12SampleFormatE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps13bitsPerSampleERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps13formatChangedENS_12SampleFormatE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps13layoutChangedENS_13ChannelLayoutE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps13resetChannelsEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps14samplesChangedEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps15channelsChangedEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps20defaultChannelLayoutEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps20sampleFormatToStringENS_12SampleFormatE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps21channelLayoutToStringENS_13ChannelLayoutE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps22sampleFormatFromStringERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps22sampleFormatPropertiesENS_12SampleFormatEPNS_10SampleTypeEPiS3_Pb@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps22sampleFormatPropertiesERK7QStringPNS_10SampleTypeEPiS5_Pb@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps23channelLayoutFromStringERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps26defaultChannelLayoutStringEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps26sampleFormatFromPropertiesENS_10SampleTypeEiib@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps3bpsEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps4rateEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps5alignEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps6formatEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps6layoutEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps6setBpsEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps6updateERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps7fromMapERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps7isValidEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps7samplesEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps7setRateEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps8channelsEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps8isPlanarENS_12SampleFormatE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps8isPlanarERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps8resetBpsEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps8setAlignEi@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps9resetRateEv@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps9setFormatENS_12SampleFormatE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCaps9setLayoutENS_13ChannelLayoutE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC1ENS_12SampleFormatEii@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC1ERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC1ERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC1ERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC1ERKS_@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC2ENS_12SampleFormatEii@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC2ERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC2ERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC2ERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsC2ERKS_@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsD0Ev@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsD1Ev@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsD2Ev@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsaSERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsaSERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkAudioCapsaSERKS_@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps10bppChangedEi@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps10fpsChangedERK6AkFrac@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps10fromStringERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps10resetWidthEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps11resetFormatEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps11resetHeightEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps11sizeChangedERK5QSize@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps12bitsPerPixelENS_11PixelFormatE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps12bitsPerPixelERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps12widthChangedEi@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps13formatChangedENS_11PixelFormatE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps13heightChangedEi@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps19pixelFormatToStringENS_11PixelFormatE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps21pixelFormatFromStringERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps3bppEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps3fpsEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps5clearEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps5widthEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps6formatEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps6fourCCENS_11PixelFormatE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps6fourCCERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps6heightEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps6setBppEi@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps6setFpsERK6AkFrac@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps6updateERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps7fromMapERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps7isValidEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps7setSizeERK5QSize@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps8resetBppEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps8resetFpsEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps8setWidthEi@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps9resetSizeEv@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps9setFormatENS_11PixelFormatE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCaps9setHeightEi@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC1ERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC1ERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC1ERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC1ERKS_@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC2ERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC2ERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC2ERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsC2ERKS_@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsD0Ev@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsD1Ev@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsD2Ev@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsaSERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsaSERK7QString@Base 8.6.1+dfsg-1 - _ZN11AkVideoCapsaSERKS_@Base 8.6.1+dfsg-1 - _ZN11QMetaTypeIdIN9AkElement12ElementStateEE14qt_metatype_idEv@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacket11capsChangedERK11AkAudioCaps@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacket11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacket11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacket16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacket4capsEv@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacket7setCapsERK11AkAudioCaps@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacket9resetCapsEv@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketC1ERK11AkAudioCapsRK10QByteArrayxRK6AkFracix@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketC1ERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketC1ERKS_@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketC2ERK11AkAudioCapsRK10QByteArrayxRK6AkFracix@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketC2ERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketC2ERKS_@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketD0Ev@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketD1Ev@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketD2Ev@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketaSERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN13AkAudioPacketaSERKS_@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacket11capsChangedERK11AkVideoCaps@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacket11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacket11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacket16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacket4capsEv@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacket7setCapsERK11AkVideoCaps@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacket9fromImageERK6QImageRKS_@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacket9resetCapsEv@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketC1ERK11AkVideoCapsRK10QByteArrayxRK6AkFracix@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketC1ERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketC1ERKS_@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketC2ERK11AkVideoCapsRK10QByteArrayxRK6AkFracix@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketC2ERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketC2ERKS_@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketD0Ev@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketD1Ev@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketD2Ev@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketaSERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN13AkVideoPacketaSERKS_@Base 8.6.1+dfsg-1 - _ZN14ChannelLayouts7layoutsEv@Base 8.6.1+dfsg-1 - _ZN15QtSharedPointer33ExternalRefCountWithCustomDeleterI9AkElementNS_13NormalDeleterEE7deleterEPNS_20ExternalRefCountDataE@Base 8.6.1+dfsg-1 - _ZN16AkElementPrivate11listPluginsEv@Base 8.6.1+dfsg-1 - _ZN16AkElementPrivate11submoduleIdERK7QStringS2_@Base 8.6.1+dfsg-1 - _ZN16AkElementPrivate12methodCompatERK11QMetaMethodS2_@Base 8.6.1+dfsg-1 - _ZN16AkElementPrivate13methodsByNameEPK7QObjectRK7QString@Base 8.6.1+dfsg-1 - _ZN16AkElementPrivate8pluginIdERK7QString@Base 8.6.1+dfsg-1 - _ZN16AkElementPrivateC1Ev@Base 8.6.1+dfsg-1 - _ZN16AkElementPrivateC2Ev@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate19IteratorOwnerCommonIN5QListIiE14const_iteratorEE5equalEPKPvS7_@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate19IteratorOwnerCommonIN5QListIiE14const_iteratorEE6assignEPPvPKS5_@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate19IteratorOwnerCommonIN5QListIiE14const_iteratorEE7advanceEPPvi@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate19IteratorOwnerCommonIN5QListIiE14const_iteratorEE7destroyEPPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI11AkAudioCapsLb1EE4LoadER11QDataStreamPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI11AkAudioCapsLb1EE4SaveER11QDataStreamPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI11AkAudioCapsLb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI11AkAudioCapsLb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI11AkVideoCapsLb1EE4LoadER11QDataStreamPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI11AkVideoCapsLb1EE4SaveER11QDataStreamPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI11AkVideoCapsLb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI11AkVideoCapsLb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI13AkVideoPacketLb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI13AkVideoPacketLb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI14QSharedPointerI9AkElementELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI14QSharedPointerI9AkElementELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI5QListIiELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI5QListIiELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6AkCapsLb1EE4LoadER11QDataStreamPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6AkCapsLb1EE4SaveER11QDataStreamPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6AkCapsLb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6AkCapsLb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6AkFracLb1EE4LoadER11QDataStreamPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6AkFracLb1EE4SaveER11QDataStreamPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6AkFracLb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6AkFracLb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6QColorLb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI6QColorLb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI8AkPacketLb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperI8AkPacketLb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN11AkAudioCaps10SampleTypeELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN11AkAudioCaps10SampleTypeELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN11AkAudioCaps12SampleFormatELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN11AkAudioCaps12SampleFormatELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN11AkAudioCaps13ChannelLayoutELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN11AkAudioCaps13ChannelLayoutELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN11AkVideoCaps11PixelFormatELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN11AkVideoCaps11PixelFormatELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN6AkCaps8CapsTypeELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN6AkCaps8CapsTypeELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN9AkElement12ElementStateELb1EE4LoadER11QDataStreamPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN9AkElement12ElementStateELb1EE4SaveER11QDataStreamPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN9AkElement12ElementStateELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIN9AkElement12ElementStateELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperINS_23QSequentialIterableImplELb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperINS_23QSequentialIterableImplELb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIjLb1EE8DestructEPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QMetaTypeFunctionHelperIjLb1EE9ConstructEPvPKv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QSequentialIterableImpl13moveToEndImplI5QListIiEEEvPKvPPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QSequentialIterableImpl15moveToBeginImplI5QListIiEEEvPKvPPv@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QSequentialIterableImpl6atImplI5QListIiEEEPKvS5_i@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QSequentialIterableImpl7getImplI5QListIiEEENS_11VariantDataEPKPvij@Base 8.6.1+dfsg-1 - _ZN17QtMetaTypePrivate23QSequentialIterableImpl8sizeImplI5QListIiEEEiPKv@Base 8.6.1+dfsg-1 - _ZN19AkPluginInfoPrivateD1Ev@Base 8.6.1+dfsg-1 - _ZN19AkPluginInfoPrivateD2Ev@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement10resetMediaEv@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement10setStreamsERK5QListIiE@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement11descriptionERK7QString@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement12resetStreamsEv@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement13defaultStreamERK7QString@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement4capsEi@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement6mediasEv@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement7setLoopEb@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement7streamsEv@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement8setMediaERK7QString@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElement9resetLoopEv@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElementC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElementC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElementD0Ev@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElementD1Ev@Base 8.6.1+dfsg-1 - _ZN25AkMultimediaSourceElementD2Ev@Base 8.6.1+dfsg-1 - _ZN2Ak12setQmlEngineEP10QQmlEngine@Base 8.6.1+dfsg-1 - _ZN2Ak16addQmlImportPathERK7QString@Base 8.6.1+dfsg-1 - _ZN2Ak17qmlImportPathListEv@Base 8.6.1+dfsg-1 - _ZN2Ak20setQmlImportPathListERK11QStringList@Base 8.6.1+dfsg-1 - _ZN2Ak22resetQmlImportPathListEv@Base 8.6.1+dfsg-1 - _ZN2Ak2idEv@Base 8.6.1+dfsg-1 - _ZN4QMapI7QString8QVariantE13detach_helperEv@Base 8.6.1+dfsg-1 - _ZN4QMapI7QString8QVariantEC1ERKS2_@Base 8.6.1+dfsg-1 - _ZN4QMapI7QString8QVariantEC2ERKS2_@Base 8.6.1+dfsg-1 - _ZN4QMapI7QString8QVariantED1Ev@Base 8.6.1+dfsg-1 - _ZN4QMapI7QString8QVariantED2Ev@Base 8.6.1+dfsg-1 - _ZN5QListI10QByteArrayE13detach_helperEi@Base 8.6.1+dfsg-1 - _ZN5QListI10QByteArrayED1Ev@Base 8.6.1+dfsg-1 - _ZN5QListI10QByteArrayED2Ev@Base 8.6.1+dfsg-1 - _ZN5QListI11QMetaMethodE13detach_helperEi@Base 8.6.1+dfsg-1 - _ZN5QListI11QMetaMethodE18detach_helper_growEii@Base 8.6.1+dfsg-1 - _ZN5QListI11QMetaMethodE6appendERKS0_@Base 8.6.1+dfsg-1 - _ZN5QListI11QMetaMethodED1Ev@Base 8.6.1+dfsg-1 - _ZN5QListI11QMetaMethodED2Ev@Base 8.6.1+dfsg-1 - _ZN5QListI19AkPluginInfoPrivateE13detach_helperEi@Base 8.6.1+dfsg-1 - _ZN5QListI19AkPluginInfoPrivateE18detach_helper_growEii@Base 8.6.1+dfsg-1 - _ZN5QListI19AkPluginInfoPrivateE6appendERKS0_@Base 8.6.1+dfsg-1 - _ZN5QListI19AkPluginInfoPrivateE9node_copyEPNS1_4NodeES3_S3_@Base 8.6.1+dfsg-1 - _ZN5QListI19AkPluginInfoPrivateED1Ev@Base 8.6.1+dfsg-1 - _ZN5QListI19AkPluginInfoPrivateED2Ev@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringE13detach_helperEi@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringE18detach_helper_growEii@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringE5clearEv@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringE6appendERKS0_@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringE6detachEv@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringE7reserveEi@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringEC1ERKS1_@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringEC2ERKS1_@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringED1Ev@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringED2Ev@Base 8.6.1+dfsg-1 - _ZN5QListI7QStringEpLERKS1_@Base 8.6.1+dfsg-1 - _ZN5QListIN11AkVideoCaps11PixelFormatEE13detach_helperEi@Base 8.6.1+dfsg-1 - _ZN5QListIN11AkVideoCaps11PixelFormatEE18detach_helper_growEii@Base 8.6.1+dfsg-1 - _ZN5QListIN11AkVideoCaps11PixelFormatEE6appendERKS1_@Base 8.6.1+dfsg-1 - _ZN5QListIN11AkVideoCaps11PixelFormatEED1Ev@Base 8.6.1+dfsg-1 - _ZN5QListIN11AkVideoCaps11PixelFormatEED2Ev@Base 8.6.1+dfsg-1 - _ZN5QListIiEC1ERKS0_@Base 8.6.1+dfsg-1 - _ZN5QListIiEC2ERKS0_@Base 8.6.1+dfsg-1 - _ZN5QListIiED1Ev@Base 8.6.1+dfsg-1 - _ZN5QListIiED2Ev@Base 8.6.1+dfsg-1 - _ZN6AkCaps10fromStringERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkCaps11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN6AkCaps11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN6AkCaps11setMimeTypeERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkCaps13resetMimeTypeEv@Base 8.6.1+dfsg-1 - _ZN6AkCaps15mimeTypeChangedERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkCaps16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN6AkCaps5clearEv@Base 8.6.1+dfsg-1 - _ZN6AkCaps6updateERKS_@Base 8.6.1+dfsg-1 - _ZN6AkCaps7fromMapERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN6AkCaps7isValidEv@Base 8.6.1+dfsg-1 - _ZN6AkCapsC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN6AkCapsC1ERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN6AkCapsC1ERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkCapsC1ERKS_@Base 8.6.1+dfsg-1 - _ZN6AkCapsC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN6AkCapsC2ERK4QMapI7QString8QVariantE@Base 8.6.1+dfsg-1 - _ZN6AkCapsC2ERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkCapsC2ERKS_@Base 8.6.1+dfsg-1 - _ZN6AkCapsD0Ev@Base 8.6.1+dfsg-1 - _ZN6AkCapsD1Ev@Base 8.6.1+dfsg-1 - _ZN6AkCapsD2Ev@Base 8.6.1+dfsg-1 - _ZN6AkCapsaSERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkCapsaSERKS_@Base 8.6.1+dfsg-1 - _ZN6AkFrac10denChangedEv@Base 8.6.1+dfsg-1 - _ZN6AkFrac10numChangedEv@Base 8.6.1+dfsg-1 - _ZN6AkFrac11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN6AkFrac11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN6AkFrac12valueChangedEv@Base 8.6.1+dfsg-1 - _ZN6AkFrac13stringChangedEv@Base 8.6.1+dfsg-1 - _ZN6AkFrac14isValidChangedEv@Base 8.6.1+dfsg-1 - _ZN6AkFrac16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN6AkFrac6setDenEx@Base 8.6.1+dfsg-1 - _ZN6AkFrac6setNumEx@Base 8.6.1+dfsg-1 - _ZN6AkFrac8resetDenEv@Base 8.6.1+dfsg-1 - _ZN6AkFrac8resetNumEv@Base 8.6.1+dfsg-1 - _ZN6AkFrac9setNumDenERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkFrac9setNumDenExx@Base 8.6.1+dfsg-1 - _ZN6AkFracC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN6AkFracC1ERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkFracC1ERKS_@Base 8.6.1+dfsg-1 - _ZN6AkFracC1Exx@Base 8.6.1+dfsg-1 - _ZN6AkFracC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN6AkFracC2ERK7QString@Base 8.6.1+dfsg-1 - _ZN6AkFracC2ERKS_@Base 8.6.1+dfsg-1 - _ZN6AkFracC2Exx@Base 8.6.1+dfsg-1 - _ZN6AkFracD0Ev@Base 8.6.1+dfsg-1 - _ZN6AkFracD1Ev@Base 8.6.1+dfsg-1 - _ZN6AkFracD2Ev@Base 8.6.1+dfsg-1 - _ZN6AkFracaSERKS_@Base 8.6.1+dfsg-1 - _ZN6QDebuglsEPKc@Base 8.6.1+dfsg-1 - _ZN7QStringC1EPKc@Base 8.6.1+dfsg-1 - _ZN7QStringC2EPKc@Base 8.6.1+dfsg-1 - _ZN7QStringD1Ev@Base 8.6.1+dfsg-1 - _ZN7QStringD2Ev@Base 8.6.1+dfsg-1 - _ZN7QVectorI11VideoFormatED1Ev@Base 8.6.1+dfsg-1 - _ZN7QVectorI11VideoFormatED2Ev@Base 8.6.1+dfsg-1 - _ZN7QVectorI13SampleFormatsED1Ev@Base 8.6.1+dfsg-1 - _ZN7QVectorI13SampleFormatsED2Ev@Base 8.6.1+dfsg-1 - _ZN7QVectorI14ChannelLayoutsED1Ev@Base 8.6.1+dfsg-1 - _ZN7QVectorI14ChannelLayoutsED2Ev@Base 8.6.1+dfsg-1 - _ZN7QVectorIP11QStringListE11reallocDataEii6QFlagsIN10QArrayData16AllocationOptionEE@Base 8.6.1+dfsg-1 - _ZN8AkPacket10ptsChangedEx@Base 8.6.1+dfsg-1 - _ZN8AkPacket10resetIndexEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket11capsChangedERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN8AkPacket11dataChangedERK8QVariant@Base 8.6.1+dfsg-1 - _ZN8AkPacket11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN8AkPacket11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN8AkPacket11resetBufferEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket11setTimeBaseERK6AkFrac@Base 8.6.1+dfsg-1 - _ZN8AkPacket12indexChangedEi@Base 8.6.1+dfsg-1 - _ZN8AkPacket13bufferChangedERK10QByteArray@Base 8.6.1+dfsg-1 - _ZN8AkPacket13resetTimeBaseEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket15timeBaseChangedERK6AkFrac@Base 8.6.1+dfsg-1 - _ZN8AkPacket16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN8AkPacket2idEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket3ptsEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket4capsEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket4dataEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket5indexEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket5setIdEx@Base 8.6.1+dfsg-1 - _ZN8AkPacket6bufferEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket6setPtsEx@Base 8.6.1+dfsg-1 - _ZN8AkPacket7resetIdEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket7setCapsERK6AkCaps@Base 8.6.1+dfsg-1 - _ZN8AkPacket7setDataERK8QVariant@Base 8.6.1+dfsg-1 - _ZN8AkPacket8resetPtsEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket8setIndexEi@Base 8.6.1+dfsg-1 - _ZN8AkPacket8timeBaseEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket9idChangedEx@Base 8.6.1+dfsg-1 - _ZN8AkPacket9resetCapsEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket9resetDataEv@Base 8.6.1+dfsg-1 - _ZN8AkPacket9setBufferERK10QByteArray@Base 8.6.1+dfsg-1 - _ZN8AkPacketC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN8AkPacketC1ERK6AkCapsRK10QByteArrayxRK6AkFracix@Base 8.6.1+dfsg-1 - _ZN8AkPacketC1ERKS_@Base 8.6.1+dfsg-1 - _ZN8AkPacketC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN8AkPacketC2ERK6AkCapsRK10QByteArrayxRK6AkFracix@Base 8.6.1+dfsg-1 - _ZN8AkPacketC2ERKS_@Base 8.6.1+dfsg-1 - _ZN8AkPacketD0Ev@Base 8.6.1+dfsg-1 - _ZN8AkPacketD1Ev@Base 8.6.1+dfsg-1 - _ZN8AkPacketD2Ev@Base 8.6.1+dfsg-1 - _ZN8AkPacketaSERKS_@Base 8.6.1+dfsg-1 - _ZN8QMapDataI7QString8QVariantE10createNodeERKS0_RKS1_P8QMapNodeIS0_S1_Eb@Base 8.6.1+dfsg-1 - _ZN8QMapNodeI7QString8QVariantE14destroySubTreeEv@Base 8.6.1+dfsg-1 - _ZN9AkElement10clearCacheEv@Base 8.6.1+dfsg-1 - _ZN9AkElement10pluginInfoERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement10pluginPathERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement10resetStateEv@Base 8.6.1+dfsg-1 - _ZN9AkElement11listPluginsERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement11qt_metacallEN11QMetaObject4CallEiPPv@Base 8.6.1+dfsg-1 - _ZN9AkElement11qt_metacastEPKc@Base 8.6.1+dfsg-1 - _ZN9AkElement11searchPathsEv@Base 8.6.1+dfsg-1 - _ZN9AkElement11stateChangeENS_12ElementStateES0_@Base 8.6.1+dfsg-1 - _ZN9AkElement12stateChangedENS_12ElementStateE@Base 8.6.1+dfsg-1 - _ZN9AkElement13addSearchPathERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement13loadSubModuleERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement13loadSubModuleERK7QStringS2_@Base 8.6.1+dfsg-1 - _ZN9AkElement13setPluginInfoERK7QStringRK4QMapIS0_8QVariantE@Base 8.6.1+dfsg-1 - _ZN9AkElement14listSubModulesERK11QStringList@Base 8.6.1+dfsg-1 - _ZN9AkElement14listSubModulesERK7QStringS2_@Base 8.6.1+dfsg-1 - _ZN9AkElement14setPluginPathsERK11QStringList@Base 8.6.1+dfsg-1 - _ZN9AkElement14setSearchPathsERK11QStringList@Base 8.6.1+dfsg-1 - _ZN9AkElement14subModulesPathEv@Base 8.6.1+dfsg-1 - _ZN9AkElement15listPluginPathsERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement15listPluginPathsEb@Base 8.6.1+dfsg-1 - _ZN9AkElement15recursiveSearchEv@Base 8.6.1+dfsg-1 - _ZN9AkElement16pluginsBlackListEv@Base 8.6.1+dfsg-1 - _ZN9AkElement16resetSearchPathsEv@Base 8.6.1+dfsg-1 - _ZN9AkElement16staticMetaObjectE@Base 8.6.1+dfsg-1 - _ZN9AkElement17setSubModulesPathERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement18setRecursiveSearchEb@Base 8.6.1+dfsg-1 - _ZN9AkElement19listSubModulesPathsERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement19listSubModulesPathsEv@Base 8.6.1+dfsg-1 - _ZN9AkElement19resetSubModulesPathEv@Base 8.6.1+dfsg-1 - _ZN9AkElement19setPluginsBlackListERK11QStringList@Base 8.6.1+dfsg-1 - _ZN9AkElement4linkEPK7QObjectS2_N2Qt14ConnectionTypeE@Base 8.6.1+dfsg-1 - _ZN9AkElement4linkERK14QSharedPointerIS_EPK7QObjectN2Qt14ConnectionTypeE@Base 8.6.1+dfsg-1 - _ZN9AkElement4linkERK14QSharedPointerIS_ES3_N2Qt14ConnectionTypeE@Base 8.6.1+dfsg-1 - _ZN9AkElement6createERK7QStringS2_@Base 8.6.1+dfsg-1 - _ZN9AkElement6unlinkEPK7QObjectS2_@Base 8.6.1+dfsg-1 - _ZN9AkElement6unlinkERK14QSharedPointerIS_EPK7QObject@Base 8.6.1+dfsg-1 - _ZN9AkElement6unlinkERK14QSharedPointerIS_ES3_@Base 8.6.1+dfsg-1 - _ZN9AkElement7iStreamERK13AkAudioPacket@Base 8.6.1+dfsg-1 - _ZN9AkElement7iStreamERK13AkVideoPacket@Base 8.6.1+dfsg-1 - _ZN9AkElement7iStreamERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN9AkElement7oStreamERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN9AkElement8pluginIdERK7QString@Base 8.6.1+dfsg-1 - _ZN9AkElement8setStateENS_12ElementStateE@Base 8.6.1+dfsg-1 - _ZN9AkElement9createPtrERK7QStringS2_@Base 8.6.1+dfsg-1 - _ZN9AkElementC1EP7QObject@Base 8.6.1+dfsg-1 - _ZN9AkElementC2EP7QObject@Base 8.6.1+dfsg-1 - _ZN9AkElementD0Ev@Base 8.6.1+dfsg-1 - _ZN9AkElementD1Ev@Base 8.6.1+dfsg-1 - _ZN9AkElementD2Ev@Base 8.6.1+dfsg-1 - _ZN9AkElementclERK13AkAudioPacket@Base 8.6.1+dfsg-1 - _ZN9AkElementclERK13AkVideoPacket@Base 8.6.1+dfsg-1 - _ZN9AkElementclERK8AkPacket@Base 8.6.1+dfsg-1 - _ZN9AkPrivateC1Ev@Base 8.6.1+dfsg-1 - _ZN9AkPrivateC2Ev@Base 8.6.1+dfsg-1 - _ZN9QtPrivate16ConverterFunctorI14QSharedPointerI9AkElementEP7QObjectNS_27QSmartPointerConvertFunctorIS3_EEE7convertEPKNS_25AbstractConverterFunctionEPKvPv@Base 8.6.1+dfsg-1 - _ZN9QtPrivate16ConverterFunctorI14QSharedPointerI9AkElementEP7QObjectNS_27QSmartPointerConvertFunctorIS3_EEED1Ev@Base 8.6.1+dfsg-1 - _ZN9QtPrivate16ConverterFunctorI14QSharedPointerI9AkElementEP7QObjectNS_27QSmartPointerConvertFunctorIS3_EEED2Ev@Base 8.6.1+dfsg-1 - _ZN9QtPrivate16ConverterFunctorI5QListIiEN17QtMetaTypePrivate23QSequentialIterableImplENS3_33QSequentialIterableConvertFunctorIS2_EEE7convertEPKNS_25AbstractConverterFunctionEPKvPv@Base 8.6.1+dfsg-1 - _ZN9QtPrivate16ConverterFunctorI5QListIiEN17QtMetaTypePrivate23QSequentialIterableImplENS3_33QSequentialIterableConvertFunctorIS2_EEED1Ev@Base 8.6.1+dfsg-1 - _ZN9QtPrivate16ConverterFunctorI5QListIiEN17QtMetaTypePrivate23QSequentialIterableImplENS3_33QSequentialIterableConvertFunctorIS2_EEED2Ev@Base 8.6.1+dfsg-1 - _ZN9QtPrivate8RefCount3refEv@Base 8.6.1+dfsg-1 - _ZN9QtPrivate8RefCount5derefEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps3bpsEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps4rateEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps5alignEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps5toMapEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps6formatEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps6layoutEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps6toCapsEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps7isValidEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps7samplesEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps8channelsEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCaps8toStringEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCapscv6AkCapsEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCapscvbEv@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCapseqERKS_@Base 8.6.1+dfsg-1 - _ZNK11AkAudioCapsneERKS_@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps11pictureSizeEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps3bppEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps3fpsEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps4sizeEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps5toMapEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps5widthEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps6formatEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps6fourCCEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps6heightEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps6toCapsEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps7isValidEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCaps8toStringEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCapscv6AkCapsEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCapscvbEv@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCapseqERKS_@Base 8.6.1+dfsg-1 - _ZNK11AkVideoCapsneERKS_@Base 8.6.1+dfsg-1 - _ZNK13AkAudioPacket10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK13AkAudioPacket4capsEv@Base 8.6.1+dfsg-1 - _ZNK13AkAudioPacket8toPacketEv@Base 8.6.1+dfsg-1 - _ZNK13AkAudioPacket8toStringEv@Base 8.6.1+dfsg-1 - _ZNK13AkAudioPacketcvbEv@Base 8.6.1+dfsg-1 - _ZNK13AkVideoPacket10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK13AkVideoPacket11roundSizeToEi@Base 8.6.1+dfsg-1 - _ZNK13AkVideoPacket4capsEv@Base 8.6.1+dfsg-1 - _ZNK13AkVideoPacket7convertEN11AkVideoCaps11PixelFormatERK5QSize@Base 8.6.1+dfsg-1 - _ZNK13AkVideoPacket7toImageEv@Base 8.6.1+dfsg-1 - _ZNK13AkVideoPacket8toPacketEv@Base 8.6.1+dfsg-1 - _ZNK13AkVideoPacket8toStringEv@Base 8.6.1+dfsg-1 - _ZNK13AkVideoPacketcvbEv@Base 8.6.1+dfsg-1 - _ZNK16AkElementPrivate17convertToAbsoluteERK7QString@Base 8.6.1+dfsg-1 - _ZNK25AkMultimediaSourceElement10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK25AkMultimediaSourceElement4loopEv@Base 8.6.1+dfsg-1 - _ZNK25AkMultimediaSourceElement5mediaEv@Base 8.6.1+dfsg-1 - _ZNK4QMapIN6QImage6FormatEN11AkVideoCaps11PixelFormatEE3keyERKS3_RKS1_@Base 8.6.1+dfsg-1 - _ZNK4QMapIN6QImage6FormatEN11AkVideoCaps11PixelFormatEE6valuesEv@Base 8.6.1+dfsg-1 - _ZNK6AkCaps10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK6AkCaps12isCompatibleERKS_@Base 8.6.1+dfsg-1 - _ZNK6AkCaps5toMapEv@Base 8.6.1+dfsg-1 - _ZNK6AkCaps7isValidEv@Base 8.6.1+dfsg-1 - _ZNK6AkCaps8containsERK7QString@Base 8.6.1+dfsg-1 - _ZNK6AkCaps8mimeTypeEv@Base 8.6.1+dfsg-1 - _ZNK6AkCaps8toStringEv@Base 8.6.1+dfsg-1 - _ZNK6AkCapscvbEv@Base 8.6.1+dfsg-1 - _ZNK6AkCapseqERK7QString@Base 8.6.1+dfsg-1 - _ZNK6AkCapseqERKS_@Base 8.6.1+dfsg-1 - _ZNK6AkCapsneERK7QString@Base 8.6.1+dfsg-1 - _ZNK6AkCapsneERKS_@Base 8.6.1+dfsg-1 - _ZNK6AkFrac10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK6AkFrac3denEv@Base 8.6.1+dfsg-1 - _ZNK6AkFrac3numEv@Base 8.6.1+dfsg-1 - _ZNK6AkFrac5valueEv@Base 8.6.1+dfsg-1 - _ZNK6AkFrac6invertEv@Base 8.6.1+dfsg-1 - _ZNK6AkFrac7isValidEv@Base 8.6.1+dfsg-1 - _ZNK6AkFrac8toStringEv@Base 8.6.1+dfsg-1 - _ZNK6AkFrac9fastValueEv@Base 8.6.1+dfsg-1 - _ZNK6AkFraceqERKS_@Base 8.6.1+dfsg-1 - _ZNK6AkFracmlERKS_@Base 8.6.1+dfsg-1 - _ZNK6AkFracneERKS_@Base 8.6.1+dfsg-1 - _ZNK8AkPacket10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacket2idEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacket3ptsEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacket4capsEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacket4dataEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacket5indexEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacket6bufferEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacket8timeBaseEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacket8toStringEv@Base 8.6.1+dfsg-1 - _ZNK8AkPacketcvbEv@Base 8.6.1+dfsg-1 - _ZNK8QMapDataI7QString8QVariantE8findNodeERKS0_@Base 8.6.1+dfsg-1 - _ZNK8QMapNodeI7QString8QVariantE4copyEP8QMapDataIS0_S1_E@Base 8.6.1+dfsg-1 - _ZNK8QMapNodeIN6QImage6FormatEN11AkVideoCaps11PixelFormatEE4copyEP8QMapDataIS1_S3_E@Base 8.6.1+dfsg-1 - _ZNK9AkElement10metaObjectEv@Base 8.6.1+dfsg-1 - _ZNK9AkElement10pluginPathEv@Base 8.6.1+dfsg-1 - _ZNK9AkElement16controlInterfaceEP10QQmlEngineRK7QString@Base 8.6.1+dfsg-1 - _ZNK9AkElement23controlInterfaceProvideERK7QString@Base 8.6.1+dfsg-1 - _ZNK9AkElement25controlInterfaceConfigureEP11QQmlContextRK7QString@Base 8.6.1+dfsg-1 - _ZNK9AkElement4linkEPK7QObjectN2Qt14ConnectionTypeE@Base 8.6.1+dfsg-1 - _ZNK9AkElement4linkERK14QSharedPointerIS_EN2Qt14ConnectionTypeE@Base 8.6.1+dfsg-1 - _ZNK9AkElement5stateEv@Base 8.6.1+dfsg-1 - _ZNK9AkElement6unlinkEPK7QObject@Base 8.6.1+dfsg-1 - _ZNK9AkElement6unlinkERK14QSharedPointerIS_E@Base 8.6.1+dfsg-1 - _ZNK9AkElement8pluginIdEv@Base 8.6.1+dfsg-1 - _ZNK9AkPrivate14qmlImportPathsEv@Base 8.6.1+dfsg-1 - _ZNK9AkPrivate17convertToAbsoluteERK7QString@Base 8.6.1+dfsg-1 - _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag@Base 8.6.1+dfsg-1 - _ZSt9__find_ifIPK10QByteArrayN9__gnu_cxx5__ops16_Iter_equals_valIS1_EEET_S7_S7_T0_St26random_access_iterator_tag@Base 8.6.1+dfsg-1 - _ZTI11AkAudioCaps@Base 8.6.1+dfsg-1 - _ZTI11AkVideoCaps@Base 8.6.1+dfsg-1 - _ZTI13AkAudioPacket@Base 8.6.1+dfsg-1 - _ZTI13AkVideoPacket@Base 8.6.1+dfsg-1 - _ZTI25AkMultimediaSourceElement@Base 8.6.1+dfsg-1 - _ZTI6AkCaps@Base 8.6.1+dfsg-1 - _ZTI6AkFrac@Base 8.6.1+dfsg-1 - _ZTI8AkPacket@Base 8.6.1+dfsg-1 - _ZTI9AkElement@Base 8.6.1+dfsg-1 - _ZTS11AkAudioCaps@Base 8.6.1+dfsg-1 - _ZTS11AkVideoCaps@Base 8.6.1+dfsg-1 - _ZTS13AkAudioPacket@Base 8.6.1+dfsg-1 - _ZTS13AkVideoPacket@Base 8.6.1+dfsg-1 - _ZTS25AkMultimediaSourceElement@Base 8.6.1+dfsg-1 - _ZTS6AkCaps@Base 8.6.1+dfsg-1 - _ZTS6AkFrac@Base 8.6.1+dfsg-1 - _ZTS8AkPacket@Base 8.6.1+dfsg-1 - _ZTS9AkElement@Base 8.6.1+dfsg-1 - _ZTV11AkAudioCaps@Base 8.6.1+dfsg-1 - _ZTV11AkVideoCaps@Base 8.6.1+dfsg-1 - _ZTV13AkAudioPacket@Base 8.6.1+dfsg-1 - _ZTV13AkVideoPacket@Base 8.6.1+dfsg-1 - _ZTV25AkMultimediaSourceElement@Base 8.6.1+dfsg-1 - _ZTV6AkCaps@Base 8.6.1+dfsg-1 - _ZTV6AkFrac@Base 8.6.1+dfsg-1 - _ZTV8AkPacket@Base 8.6.1+dfsg-1 - _ZTV9AkElement@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdI11AkAudioCapsE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdI11AkVideoCapsE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdI13AkVideoPacketE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdI5QListIiEE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdI6AkCapsE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdI6AkFracE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdI8AkPacketE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdIN11AkAudioCaps12SampleFormatEE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdIN11AkAudioCaps13ChannelLayoutEE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdIN11AkVideoCaps11PixelFormatEE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdIN17QtMetaTypePrivate23QSequentialIterableImplEE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdIN6AkCaps8CapsTypeEE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11QMetaTypeIdIN9AkElement12ElementStateEE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZZN11VideoFormat7formatsEvE12videoFormats@Base 8.6.1+dfsg-1 - _ZZN13SampleFormats7formatsEvE13sampleFormats@Base 8.6.1+dfsg-1 - _ZZN14ChannelLayouts7layoutsEvE14channelLayouts@Base 8.6.1+dfsg-1 - _ZZN9QtPrivate19ValueTypeIsMetaTypeI5QListIiELb1EE17registerConverterEiE1f@Base 8.6.1+dfsg-1 - _ZZN9QtPrivate26MetaTypeSmartPointerHelperI14QSharedPointerI9AkElementEvE17registerConverterEiE1f@Base 8.6.1+dfsg-1 - _ZZN9QtPrivate29SharedPointerMetaTypeIdHelperI14QSharedPointerI9AkElementELb1EE14qt_metatype_idEvE11metatype_id@Base 8.6.1+dfsg-1 - _ZdvRK6AkFracS1_@Base 8.6.1+dfsg-1 - _ZdviRK6AkFrac@Base 8.6.1+dfsg-1 - _Zls6QDebugRK11AkAudioCaps@Base 8.6.1+dfsg-1 - _Zls6QDebugRK11AkVideoCaps@Base 8.6.1+dfsg-1 - _Zls6QDebugRK13AkAudioPacket@Base 8.6.1+dfsg-1 - _Zls6QDebugRK13AkVideoPacket@Base 8.6.1+dfsg-1 - _Zls6QDebugRK6AkCaps@Base 8.6.1+dfsg-1 - _Zls6QDebugRK6AkFrac@Base 8.6.1+dfsg-1 - _Zls6QDebugRK8AkPacket@Base 8.6.1+dfsg-1 - _ZlsR11QDataStreamN9AkElement12ElementStateE@Base 8.6.1+dfsg-1 - _ZlsR11QDataStreamRK11AkAudioCaps@Base 8.6.1+dfsg-1 - _ZlsR11QDataStreamRK11AkVideoCaps@Base 8.6.1+dfsg-1 - _ZlsR11QDataStreamRK6AkCaps@Base 8.6.1+dfsg-1 - _ZlsR11QDataStreamRK6AkFrac@Base 8.6.1+dfsg-1 - _ZmiRK6AkFracS1_@Base 8.6.1+dfsg-1 - _ZmliRK6AkFrac@Base 8.6.1+dfsg-1 - _ZplRK6AkFracS1_@Base 8.6.1+dfsg-1 - _ZrsR11QDataStreamR11AkAudioCaps@Base 8.6.1+dfsg-1 - _ZrsR11QDataStreamR11AkVideoCaps@Base 8.6.1+dfsg-1 - _ZrsR11QDataStreamR6AkCaps@Base 8.6.1+dfsg-1 - _ZrsR11QDataStreamR6AkFrac@Base 8.6.1+dfsg-1 - _ZrsR11QDataStreamRN9AkElement12ElementStateE@Base 8.6.1+dfsg-1 diff -Nru webcamoid-8.6.1+dfsg/debian/not-installed webcamoid-8.8.0+dfsg/debian/not-installed --- webcamoid-8.6.1+dfsg/debian/not-installed 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/not-installed 2022-01-08 21:32:08.000000000 +0000 @@ -0,0 +1,2 @@ +usr/share/licenses/avkys/COPYING +usr/share/licenses/webcamoid/COPYING diff -Nru webcamoid-8.6.1+dfsg/debian/patches/0001-include-limits.patch webcamoid-8.8.0+dfsg/debian/patches/0001-include-limits.patch --- webcamoid-8.6.1+dfsg/debian/patches/0001-include-limits.patch 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/patches/0001-include-limits.patch 2022-01-08 21:32:08.000000000 +0000 @@ -0,0 +1,21 @@ +From: "Barak A. Pearlmutter" +Date: Tue, 4 Jan 2022 14:10:45 +0000 +Subject: include limits + +for std::numeric_limits<>::max() +--- + libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp b/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp +index 2a32732..5175d1d 100644 +--- a/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp ++++ b/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp +@@ -19,6 +19,7 @@ + + #include + #include ++#include + + #include "videoformat.h" + #include "../utils.h" diff -Nru webcamoid-8.6.1+dfsg/debian/patches/include-limits.patch webcamoid-8.8.0+dfsg/debian/patches/include-limits.patch --- webcamoid-8.6.1+dfsg/debian/patches/include-limits.patch 2021-08-12 05:28:43.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/patches/include-limits.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ ---- a/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp -+++ b/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp -@@ -19,6 +19,7 @@ - - #include - #include -+#include - - #include "videoformat.h" - #include "../utils.h" diff -Nru webcamoid-8.6.1+dfsg/debian/patches/series webcamoid-8.8.0+dfsg/debian/patches/series --- webcamoid-8.6.1+dfsg/debian/patches/series 2021-08-12 05:27:22.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/patches/series 2022-01-08 21:32:08.000000000 +0000 @@ -1,2 +1 @@ -webcamoid_desktop_icon.patch -include-limits.patch +0001-include-limits.patch diff -Nru webcamoid-8.6.1+dfsg/debian/patches/webcamoid_desktop_icon.patch webcamoid-8.8.0+dfsg/debian/patches/webcamoid_desktop_icon.patch --- webcamoid-8.6.1+dfsg/debian/patches/webcamoid_desktop_icon.patch 2020-03-06 21:11:09.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/patches/webcamoid_desktop_icon.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -Description: Fix - AppStream error: icon not found -Author: Herbert Parentes Fortes Neto -Last-Update: 2019-01-22 -Index: webcamoid/webcamoid.desktop -=================================================================== ---- webcamoid.orig/webcamoid.desktop -+++ webcamoid/webcamoid.desktop -@@ -30,7 +30,7 @@ Comment[zh_CN]=拍摄照片和录制视 - Comment[zh_TW]=拍攝照片和錄製視頻與您的攝像頭 - Keywords=photo;video;webcam; - Exec=webcamoid --Icon=webcamoid -+Icon=/usr/share/webcamoid/icons/hicolor/64x64/webcamoid.png - Terminal=false - Type=Application - Categories=AudioVideo;Player;Qt; diff -Nru webcamoid-8.6.1+dfsg/debian/rules webcamoid-8.8.0+dfsg/debian/rules --- webcamoid-8.6.1+dfsg/debian/rules 2020-03-06 21:11:09.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/rules 2022-01-08 21:32:08.000000000 +0000 @@ -2,14 +2,15 @@ export DH_VERBOSE=1 -export PVER=$(shell dpkg-parsechangelog --show-field version | cut -d"+" -f1 ) +include /usr/share/dpkg/architecture.mk +include /usr/share/dpkg/pkg-info.mk + +export PVER=$(shell echo $(DEB_VERSION_UPSTREAM) | cut -d"+" -f1 ) export DEB_BUILD_MAINT_OPTIONS := hardening=+all export DEB_LDFLAGS_MAINT_APPEND := -fPIE -pie -Wl,--as-needed export QT_SELECT=5 -DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) - %: dh $@ --buildsystem=qmake @@ -22,11 +23,10 @@ override_dh_makeshlibs: dh_makeshlibs -- -v$(PVER) -override_dh_clean: - dh_clean - find ./libAvKys/Tests/ -name "test_auto" | xargs -i rm {} - find ./libAvKys/Tests/ -name "test.o" | xargs -i rm {} - find ./libAvKys/Tests/ -name "Makefile" | xargs -i rm {} +execute_after_dh_clean: + find ./libAvKys/Tests/ -name "test_auto" -delete + find ./libAvKys/Tests/ -name "test.o" -delete + find ./libAvKys/Tests/ -name "Makefile" -delete rm -f ./libAvKys/config.log rm -f ./libAvKys/.qmake.cache rm -f ./libAvKys/.qmake.stash diff -Nru webcamoid-8.6.1+dfsg/debian/upstream/metadata webcamoid-8.8.0+dfsg/debian/upstream/metadata --- webcamoid-8.6.1+dfsg/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/upstream/metadata 2022-01-08 21:32:08.000000000 +0000 @@ -0,0 +1,6 @@ +--- +Bug-Database: https://github.com/webcamoid/webcamoid/issues +Bug-Submit: https://github.com/webcamoid/webcamoid/issues/new +Repository: https://github.com/webcamoid/webcamoid.git +Repository-Browse: https://github.com/webcamoid/webcamoid +Security-Contact: https://github.com/webcamoid/webcamoid/tree/HEAD/SECURITY.md diff -Nru webcamoid-8.6.1+dfsg/debian/watch webcamoid-8.8.0+dfsg/debian/watch --- webcamoid-8.6.1+dfsg/debian/watch 2020-03-06 21:11:09.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/watch 2022-01-02 19:56:38.000000000 +0000 @@ -1,6 +1,5 @@ version=4 opts=\ -repacksuffix=+dfsg,\ -repack,compression=xz,\ -dversionmangle=s/\+dfsg// \ -https://github.com/hipersayanX/webcamoid/releases .*/archive/v?(\d\S+)\.(?:zip|tar)\.?(?:gz|bz2|xz)? debian uupdate + repacksuffix=+dfsg,\ + dversionmangle=s/\+dfsg// \ + https://github.com/@PACKAGE@/@PACKAGE@/tags .*/v?@ANY_VERSION@@ARCHIVE_EXT@ diff -Nru webcamoid-8.6.1+dfsg/debian/webcamoid-data.install webcamoid-8.8.0+dfsg/debian/webcamoid-data.install --- webcamoid-8.6.1+dfsg/debian/webcamoid-data.install 2020-03-06 21:11:09.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/webcamoid-data.install 2022-01-08 21:32:08.000000000 +0000 @@ -3,3 +3,5 @@ StandAlone/share/icons usr/share/webcamoid/ StandAlone/share/qml usr/share/webcamoid/ StandAlone/share/ts/*.qm usr/share/webcamoid/locale +usr/share/icons/hicolor/*x*/apps/webcamoid.png +usr/share/icons/hicolor/scalable/apps/webcamoid.svg diff -Nru webcamoid-8.6.1+dfsg/debian/webcamoid.install webcamoid-8.8.0+dfsg/debian/webcamoid.install --- webcamoid-8.6.1+dfsg/debian/webcamoid.install 2020-03-06 21:11:09.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/webcamoid.install 2022-01-08 21:32:08.000000000 +0000 @@ -1,2 +1,3 @@ usr/bin usr/share/applications +usr/share/man/man1/webcamoid.1.gz diff -Nru webcamoid-8.6.1+dfsg/debian/webcamoid.manpages webcamoid-8.8.0+dfsg/debian/webcamoid.manpages --- webcamoid-8.6.1+dfsg/debian/webcamoid.manpages 2020-03-06 21:11:09.000000000 +0000 +++ webcamoid-8.8.0+dfsg/debian/webcamoid.manpages 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -StandAlone/share/man/webcamoid.1 diff -Nru webcamoid-8.6.1+dfsg/.gitignore webcamoid-8.8.0+dfsg/.gitignore --- webcamoid-8.6.1+dfsg/.gitignore 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/.gitignore 2021-02-15 15:25:23.000000000 +0000 @@ -38,11 +38,11 @@ ._* .Spotlight-V100 .Trashes -Icon? ehthumbs.db Thumbs.db *~ *_resource.rc +Info.plist # Ignore files generated by Qt # ################################ @@ -66,6 +66,7 @@ *.plugin *_qmlcache.qrc test.o-* +object_script.* # Ignore files generated by Python # #################################### @@ -110,7 +111,7 @@ # Project Files # ################# Webcamoid -webcamoid +bin/webcamoid AkVCamAssistant # Ignore Directories # diff -Nru webcamoid-8.6.1+dfsg/libAvKys/AkQml/src/akqml.cpp webcamoid-8.8.0+dfsg/libAvKys/AkQml/src/akqml.cpp --- webcamoid-8.6.1+dfsg/libAvKys/AkQml/src/akqml.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/AkQml/src/akqml.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,7 +21,6 @@ #include "ak.h" #include "akfrac.h" #include "akcaps.h" -#include "akvideocaps.h" #include "akelement.h" AkQml::AkQml(QQuickItem *parent): @@ -59,19 +58,9 @@ return new AkFrac(frac); } -QObject *AkQml::newCaps() const +QObject *AkQml::newCaps(const QString &mimeType) const { - return new AkCaps(); -} - -QObject *AkQml::newCaps(const QVariantMap &caps) const -{ - return new AkCaps(caps); -} - -QObject *AkQml::newCaps(const QString &caps) const -{ - return new AkCaps(caps); + return new AkCaps(mimeType); } QObject *AkQml::newCaps(const AkCaps &caps) const @@ -84,16 +73,6 @@ return new AkAudioCaps(); } -QObject *AkQml::newAudioCaps(const QVariantMap &caps) const -{ - return new AkAudioCaps(caps); -} - -QObject *AkQml::newAudioCaps(const QString &caps) const -{ - return new AkAudioCaps(caps); -} - QObject *AkQml::newAudioCaps(const AkCaps &caps) const { return new AkAudioCaps(caps); @@ -105,10 +84,28 @@ } QObject *AkQml::newAudioCaps(AkAudioCaps::SampleFormat format, - int channels, - int rate) -{ - return new AkAudioCaps(format, channels, rate); + AkAudioCaps::ChannelLayout layout, + int rate, + int samples, + bool planar, + int align) +{ + return new AkAudioCaps(format, layout, rate, samples, planar, align); +} + +QObject *AkQml::newAudioCaps(const QString &format, + const QString &layout, + int rate, + int samples, + bool planar, + int align) +{ + return new AkAudioCaps(AkAudioCaps::sampleFormatFromString(format), + AkAudioCaps::channelLayoutFromString(layout), + rate, + samples, + planar, + align); } QObject *AkQml::newVideoCaps() const @@ -116,30 +113,81 @@ return new AkVideoCaps(); } -QObject *AkQml::newVideoCaps(const QVariantMap &caps) const +QObject *AkQml::newVideoCaps(const AkCaps &caps) const { return new AkVideoCaps(caps); } -QObject *AkQml::newVideoCaps(const QString &caps) const +QObject *AkQml::newVideoCaps(const AkVideoCaps &caps) const { return new AkVideoCaps(caps); } -QObject *AkQml::newVideoCaps(const AkCaps &caps) const +QObject *AkQml::newVideoCaps(AkVideoCaps::PixelFormat format, + int width, + int height, + const AkFrac &fps, + int align) const { - return new AkVideoCaps(caps); + return new AkVideoCaps(format, width, height, fps, align); } -QObject *AkQml::newVideoCaps(const AkVideoCaps &caps) const +QObject *AkQml::newVideoCaps(const QString &format, + int width, + int height, + const AkFrac &fps, + int align) const { - return new AkVideoCaps(caps); + return new AkVideoCaps(AkVideoCaps::pixelFormatFromString(format), + width, + height, + fps, + align); +} + +QObject *AkQml::newVideoCaps(AkVideoCaps::PixelFormat format, + const QSize &size, + const AkFrac &fps, + int align) const +{ + return new AkVideoCaps(format, size, fps, align); +} + +QObject *AkQml::newVideoCaps(const QString &format, + const QSize &size, + const AkFrac &fps, + int align) const +{ + return new AkVideoCaps(AkVideoCaps::pixelFormatFromString(format), + size, + fps, + align); } QObject *AkQml::newElement(const QString &pluginId, - const QString &elementName) const + const QString &pluginSub) const { - return AkElement::createPtr(pluginId, elementName); + return AkElement::createPtr(pluginId, pluginSub); +} + +QVariantList AkQml::newList(const QList &sampleFormats) const +{ + QVariantList list; + + for (auto &format: sampleFormats) + list << format; + + return list; +} + +QVariantList AkQml::newList(const QList &channelLayouts) const +{ + QVariantList list; + + for (auto &layout: channelLayouts) + list << layout; + + return list; } QVariant AkQml::varFrac(QObject *frac) const @@ -166,5 +214,25 @@ { return QVariant::fromValue(*caps); } + +QVariant AkQml::varAudioCaps(QObject *caps) const +{ + return QVariant::fromValue(*qobject_cast(caps)); +} + +QVariant AkQml::varAudioCaps(AkAudioCaps *caps) const +{ + return QVariant::fromValue(*caps); +} + +QVariant AkQml::varVideoCaps(QObject *caps) const +{ + return QVariant::fromValue(*qobject_cast(caps)); +} + +QVariant AkQml::varVideoCaps(AkAudioCaps *caps) const +{ + return QVariant::fromValue(*caps); +} #include "moc_akqml.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/AkQml/src/akqml.h webcamoid-8.8.0+dfsg/libAvKys/AkQml/src/akqml.h --- webcamoid-8.6.1+dfsg/libAvKys/AkQml/src/akqml.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/AkQml/src/akqml.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,10 +22,10 @@ #include #include +#include class AkFrac; class AkCaps; -class AkVideoCaps; class AkQml: public QQuickItem { @@ -43,28 +43,52 @@ Q_INVOKABLE QObject *newFrac(const QString &frac) const; Q_INVOKABLE QObject *newFrac(const AkFrac &frac) const; - Q_INVOKABLE QObject *newCaps() const; - Q_INVOKABLE QObject *newCaps(const QVariantMap &caps) const; - Q_INVOKABLE QObject *newCaps(const QString &caps) const; + Q_INVOKABLE QObject *newCaps(const QString &mimeType={}) const; Q_INVOKABLE QObject *newCaps(const AkCaps &caps) const; Q_INVOKABLE QObject *newAudioCaps() const; - Q_INVOKABLE QObject *newAudioCaps(const QVariantMap &caps) const; - Q_INVOKABLE QObject *newAudioCaps(const QString &caps) const; Q_INVOKABLE QObject *newAudioCaps(const AkCaps &caps) const; Q_INVOKABLE QObject *newAudioCaps(const AkAudioCaps &caps) const; Q_INVOKABLE QObject *newAudioCaps(AkAudioCaps::SampleFormat format, - int channels, - int rate); + AkAudioCaps::ChannelLayout layout, + int rate, + int samples=0, + bool planar=false, + int align=1); + Q_INVOKABLE QObject *newAudioCaps(const QString &format, + const QString &layout, + int rate, + int samples=0, + bool planar=false, + int align=1); Q_INVOKABLE QObject *newVideoCaps() const; - Q_INVOKABLE QObject *newVideoCaps(const QVariantMap &caps) const; - Q_INVOKABLE QObject *newVideoCaps(const QString &caps) const; Q_INVOKABLE QObject *newVideoCaps(const AkCaps &caps) const; Q_INVOKABLE QObject *newVideoCaps(const AkVideoCaps &caps) const; + Q_INVOKABLE QObject *newVideoCaps(AkVideoCaps::PixelFormat format, + int width, + int height, + const AkFrac &fps, + int align=1) const; + Q_INVOKABLE QObject *newVideoCaps(const QString &format, + int width, + int height, + const AkFrac &fps, + int align=1) const; + Q_INVOKABLE QObject *newVideoCaps(AkVideoCaps::PixelFormat format, + const QSize &size, + const AkFrac &fps, + int align=1) const; + Q_INVOKABLE QObject *newVideoCaps(const QString &format, + const QSize &size, + const AkFrac &fps, + int align=1) const; Q_INVOKABLE QObject *newElement(const QString &pluginId, - const QString &elementName={}) const; + const QString &pluginSub={}) const; + + Q_INVOKABLE QVariantList newList(const QList &sampleFormats) const; + Q_INVOKABLE QVariantList newList(const QList &channelLayouts) const; Q_INVOKABLE QVariant varFrac(QObject *frac) const; Q_INVOKABLE QVariant varFrac(AkFrac *frac) const; @@ -72,6 +96,12 @@ Q_INVOKABLE QVariant varCaps(QObject *caps) const; Q_INVOKABLE QVariant varCaps(AkCaps *caps) const; + + Q_INVOKABLE QVariant varAudioCaps(QObject *caps) const; + Q_INVOKABLE QVariant varAudioCaps(AkAudioCaps *caps) const; + + Q_INVOKABLE QVariant varVideoCaps(QObject *caps) const; + Q_INVOKABLE QVariant varVideoCaps(AkAudioCaps *caps) const; }; #endif // AKQML_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akaudiocaps.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akaudiocaps.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akaudiocaps.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akaudiocaps.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include "akaudiocaps.h" #include "akcaps.h" @@ -32,50 +33,29 @@ AkAudioCaps::SampleType type; int bps; int endianness; - bool planar; static inline const QVector &formats() { - static const QVector sampleFormats = { - {AkAudioCaps::SampleFormat_none , AkAudioCaps::SampleType_unknown, 0, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_s8 , AkAudioCaps::SampleType_int , 8, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_u8 , AkAudioCaps::SampleType_uint , 8, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_s16 , AkAudioCaps::SampleType_int , 16, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_s16le, AkAudioCaps::SampleType_int , 16, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_s16be, AkAudioCaps::SampleType_int , 16, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_u16 , AkAudioCaps::SampleType_uint , 16, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_u16le, AkAudioCaps::SampleType_uint , 16, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_u16be, AkAudioCaps::SampleType_uint , 16, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_s24 , AkAudioCaps::SampleType_int , 24, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_s24le, AkAudioCaps::SampleType_int , 24, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_s24be, AkAudioCaps::SampleType_int , 24, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_u24 , AkAudioCaps::SampleType_uint , 24, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_u24le, AkAudioCaps::SampleType_uint , 24, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_u24be, AkAudioCaps::SampleType_uint , 24, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_s32 , AkAudioCaps::SampleType_int , 32, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_s32le, AkAudioCaps::SampleType_int , 32, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_s32be, AkAudioCaps::SampleType_int , 32, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_u32 , AkAudioCaps::SampleType_uint , 32, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_u32le, AkAudioCaps::SampleType_uint , 32, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_u32be, AkAudioCaps::SampleType_uint , 32, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_s64 , AkAudioCaps::SampleType_int , 64, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_s64le, AkAudioCaps::SampleType_int , 64, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_s64be, AkAudioCaps::SampleType_int , 64, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_u64 , AkAudioCaps::SampleType_uint , 64, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_u64le, AkAudioCaps::SampleType_uint , 64, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_u64be, AkAudioCaps::SampleType_uint , 64, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_flt , AkAudioCaps::SampleType_float , 32, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_fltle, AkAudioCaps::SampleType_float , 32, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_fltbe, AkAudioCaps::SampleType_float , 32, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_dbl , AkAudioCaps::SampleType_float , 64, Q_BYTE_ORDER , false}, - {AkAudioCaps::SampleFormat_dblle, AkAudioCaps::SampleType_float , 64, Q_LITTLE_ENDIAN, false}, - {AkAudioCaps::SampleFormat_dblbe, AkAudioCaps::SampleType_float , 64, Q_BIG_ENDIAN , false}, - {AkAudioCaps::SampleFormat_u8p , AkAudioCaps::SampleType_uint , 8, Q_BYTE_ORDER , true}, - {AkAudioCaps::SampleFormat_s16p , AkAudioCaps::SampleType_int , 16, Q_BYTE_ORDER , true}, - {AkAudioCaps::SampleFormat_s32p , AkAudioCaps::SampleType_int , 32, Q_BYTE_ORDER , true}, - {AkAudioCaps::SampleFormat_s64p , AkAudioCaps::SampleType_int , 64, Q_BYTE_ORDER , true}, - {AkAudioCaps::SampleFormat_fltp , AkAudioCaps::SampleType_float , 32, Q_BYTE_ORDER , true}, - {AkAudioCaps::SampleFormat_dblp , AkAudioCaps::SampleType_float , 64, Q_BYTE_ORDER , true}, + static const QVector sampleFormats { + {AkAudioCaps::SampleFormat_none , AkAudioCaps::SampleType_unknown, 0, Q_BYTE_ORDER }, + {AkAudioCaps::SampleFormat_s8 , AkAudioCaps::SampleType_int , 8, Q_BYTE_ORDER }, + {AkAudioCaps::SampleFormat_u8 , AkAudioCaps::SampleType_uint , 8, Q_BYTE_ORDER }, + {AkAudioCaps::SampleFormat_s16le, AkAudioCaps::SampleType_int , 16, Q_LITTLE_ENDIAN}, + {AkAudioCaps::SampleFormat_s16be, AkAudioCaps::SampleType_int , 16, Q_BIG_ENDIAN }, + {AkAudioCaps::SampleFormat_u16le, AkAudioCaps::SampleType_uint , 16, Q_LITTLE_ENDIAN}, + {AkAudioCaps::SampleFormat_u16be, AkAudioCaps::SampleType_uint , 16, Q_BIG_ENDIAN }, + {AkAudioCaps::SampleFormat_s32le, AkAudioCaps::SampleType_int , 32, Q_LITTLE_ENDIAN}, + {AkAudioCaps::SampleFormat_s32be, AkAudioCaps::SampleType_int , 32, Q_BIG_ENDIAN }, + {AkAudioCaps::SampleFormat_u32le, AkAudioCaps::SampleType_uint , 32, Q_LITTLE_ENDIAN}, + {AkAudioCaps::SampleFormat_u32be, AkAudioCaps::SampleType_uint , 32, Q_BIG_ENDIAN }, + {AkAudioCaps::SampleFormat_s64le, AkAudioCaps::SampleType_int , 64, Q_LITTLE_ENDIAN}, + {AkAudioCaps::SampleFormat_s64be, AkAudioCaps::SampleType_int , 64, Q_BIG_ENDIAN }, + {AkAudioCaps::SampleFormat_u64le, AkAudioCaps::SampleType_uint , 64, Q_LITTLE_ENDIAN}, + {AkAudioCaps::SampleFormat_u64be, AkAudioCaps::SampleType_uint , 64, Q_BIG_ENDIAN }, + {AkAudioCaps::SampleFormat_fltle, AkAudioCaps::SampleType_float , 32, Q_LITTLE_ENDIAN}, + {AkAudioCaps::SampleFormat_fltbe, AkAudioCaps::SampleType_float , 32, Q_BIG_ENDIAN }, + {AkAudioCaps::SampleFormat_dblle, AkAudioCaps::SampleType_float , 64, Q_LITTLE_ENDIAN}, + {AkAudioCaps::SampleFormat_dblbe, AkAudioCaps::SampleType_float , 64, Q_BIG_ENDIAN }, }; return sampleFormats; @@ -117,55 +97,171 @@ return &formats().front(); } - static inline const SampleFormats *byPlanar(bool planar) + template + static inline T alignUp(const T &value, const T &align) { - for (auto &format: formats()) - if (format.planar == planar) - return &format; + return (value + align - 1) & ~(align - 1); + } +}; - return &formats().front(); +class SpeakerPositions +{ + public: + AkAudioCaps::Position position; + qreal azimuth; + qreal elevation; + + static inline const QVector &positions() + { + /* Speakers positions based on: + * + * https://mediaarea.net/AudioChannelLayout + */ + static const QVector positions { + {AkAudioCaps::Position_unknown , 0.0, 0.0}, + {AkAudioCaps::Position_FrontCenter , 0.0, 0.0}, + {AkAudioCaps::Position_FrontLeft , 45.0, 0.0}, + {AkAudioCaps::Position_FrontRight , -45.0, 0.0}, + {AkAudioCaps::Position_BackCenter , 180.0, 0.0}, + {AkAudioCaps::Position_BackLeft , 150.0, 0.0}, + {AkAudioCaps::Position_BackRight , -150.0, 0.0}, + {AkAudioCaps::Position_FrontLeftOfCenter , 15.0, 0.0}, + {AkAudioCaps::Position_FrontRightOfCenter , -15.0, 0.0}, + {AkAudioCaps::Position_WideLeft , 60.0, 0.0}, + {AkAudioCaps::Position_WideRight , -60.0, 0.0}, + {AkAudioCaps::Position_SideLeft , 90.0, 0.0}, + {AkAudioCaps::Position_SideRight , -90.0, 0.0}, + {AkAudioCaps::Position_LowFrequency1 , 60.0, -30.0}, + {AkAudioCaps::Position_LowFrequency2 , -60.0, -30.0}, + {AkAudioCaps::Position_TopCenter , 0.0, 90.0}, + {AkAudioCaps::Position_TopFrontCenter , 0.0, 45.0}, + {AkAudioCaps::Position_TopFrontLeft , 45.0, 45.0}, + {AkAudioCaps::Position_TopFrontRight , -45.0, 45.0}, + {AkAudioCaps::Position_TopBackCenter , 180.0, 45.0}, + {AkAudioCaps::Position_TopBackLeft , 135.0, 45.0}, + {AkAudioCaps::Position_TopBackRight , -135.0, 45.0}, + {AkAudioCaps::Position_TopSideLeft , 90.0, 45.0}, + {AkAudioCaps::Position_TopSideRight , -90.0, 45.0}, + {AkAudioCaps::Position_BottomFrontCenter , 0.0, -30.0}, + {AkAudioCaps::Position_BottomFrontLeft , 45.0, -30.0}, + {AkAudioCaps::Position_BottomFrontRight , -45.0, -30.0}, + {AkAudioCaps::Position_StereoLeft , 110.0, 0.0}, + {AkAudioCaps::Position_StereoRight , -110.0, 0.0}, + {AkAudioCaps::Position_SurroundDirectLeft , 90.0, 0.0}, + {AkAudioCaps::Position_SurroundDirectRight, -90.0, 0.0}, + }; + + return positions; + } + + static inline const SpeakerPositions *byPosition(AkAudioCaps::Position position) + { + for (auto &position_: positions()) + if (position_.position == position) + return &position_; + + return &positions().front(); } }; +#define LAYOUT_MONO AkAudioCaps::Position_FrontCenter +#define LAYOUT_STEREO AkAudioCaps::Position_FrontLeft, \ + AkAudioCaps::Position_FrontRight +#define LAYOUT_DOWNMIX AkAudioCaps::Position_StereoLeft, \ + AkAudioCaps::Position_StereoRight +#define LAYOUT_2P1 LAYOUT_STEREO, AkAudioCaps::Position_LowFrequency1 +#define LAYOUT_3P0 LAYOUT_STEREO, AkAudioCaps::Position_FrontCenter +#define LAYOUT_3P0_BACK LAYOUT_STEREO, AkAudioCaps::Position_BackCenter +#define LAYOUT_3P1 LAYOUT_3P0, AkAudioCaps::Position_LowFrequency1 +#define LAYOUT_4P0 LAYOUT_3P0, AkAudioCaps::Position_BackCenter +#define LAYOUT_QUAD LAYOUT_STEREO, \ + AkAudioCaps::Position_BackLeft, \ + AkAudioCaps::Position_BackRight +#define LAYOUT_QUAD_SIDE LAYOUT_STEREO, \ + AkAudioCaps::Position_SideLeft, \ + AkAudioCaps::Position_SideRight +#define LAYOUT_4P1 LAYOUT_4P0, AkAudioCaps::Position_LowFrequency1 +#define LAYOUT_5P0 LAYOUT_3P0, AkAudioCaps::Position_BackLeft, \ + AkAudioCaps::Position_BackRight +#define LAYOUT_5P0_SIDE LAYOUT_3P0, AkAudioCaps::Position_SideLeft, \ + AkAudioCaps::AkAudioCaps::Position_SideRight +#define LAYOUT_5P1 LAYOUT_5P0, AkAudioCaps::Position_LowFrequency1 +#define LAYOUT_5P1_SIDE LAYOUT_5P0_SIDE, \ + AkAudioCaps::Position_LowFrequency1 +#define LAYOUT_6P0 LAYOUT_5P0_SIDE, AkAudioCaps::Position_BackCenter +#define LAYOUT_6P0_FRONT LAYOUT_QUAD_SIDE, \ + AkAudioCaps::Position_FrontLeftOfCenter, \ + AkAudioCaps::Position_FrontRightOfCenter +#define LAYOUT_HEXAGONAL LAYOUT_5P0, AkAudioCaps::Position_BackCenter +#define LAYOUT_6P1 LAYOUT_5P1_SIDE, AkAudioCaps::Position_BackCenter +#define LAYOUT_6P1_BACK LAYOUT_5P1, AkAudioCaps::Position_BackCenter +#define LAYOUT_6P1_FRONT LAYOUT_6P0_FRONT, \ + AkAudioCaps::Position_LowFrequency1 +#define LAYOUT_7P0 LAYOUT_5P0_SIDE, \ + AkAudioCaps::Position_BackLeft, \ + AkAudioCaps::Position_BackRight +#define LAYOUT_7P0_FRONT LAYOUT_5P0_SIDE, \ + AkAudioCaps::Position_FrontLeftOfCenter, \ + AkAudioCaps::Position_FrontRightOfCenter +#define LAYOUT_7P1 LAYOUT_5P1_SIDE, \ + AkAudioCaps::Position_BackLeft, \ + AkAudioCaps::Position_BackRight +#define LAYOUT_7P1_WIDE LAYOUT_5P1_SIDE, \ + AkAudioCaps::Position_FrontLeftOfCenter, \ + AkAudioCaps::Position_FrontRightOfCenter +#define LAYOUT_7P1_WIDE_BACK LAYOUT_5P1, \ + AkAudioCaps::Position_FrontLeftOfCenter, \ + AkAudioCaps::Position_FrontRightOfCenter +#define LAYOUT_OCTAGONAL LAYOUT_7P0, AkAudioCaps::Position_BackCenter +#define LAYOUT_HEXADECAGONAL LAYOUT_OCTAGONAL, \ + AkAudioCaps::Position_WideLeft, \ + AkAudioCaps::Position_WideRight, \ + AkAudioCaps::Position_TopBackLeft, \ + AkAudioCaps::Position_TopBackRight, \ + AkAudioCaps::Position_TopBackCenter, \ + AkAudioCaps::Position_TopFrontCenter, \ + AkAudioCaps::Position_TopFrontLeft, \ + AkAudioCaps::Position_TopFrontRight + class ChannelLayouts { public: AkAudioCaps::ChannelLayout layout; - int channels; + QVector channels; QString description; static inline const QVector &layouts() { - static const QVector channelLayouts = { - {AkAudioCaps::Layout_none , 0, "none" }, - {AkAudioCaps::Layout_mono , 1, "mono" }, - {AkAudioCaps::Layout_stereo , 2, "stereo" }, - {AkAudioCaps::Layout_2p1 , 3, "2.1" }, - {AkAudioCaps::Layout_3p0 , 3, "3.0" }, - {AkAudioCaps::Layout_3p0_back , 3, "3.0(back)" }, - {AkAudioCaps::Layout_3p1 , 4, "3.1" }, - {AkAudioCaps::Layout_4p0 , 4, "4.0" }, - {AkAudioCaps::Layout_quad , 4, "quad" }, - {AkAudioCaps::Layout_quad_side , 4, "quad(side)" }, - {AkAudioCaps::Layout_4p1 , 5, "4.1" }, - {AkAudioCaps::Layout_5p0 , 5, "5.0" }, - {AkAudioCaps::Layout_5p0_side , 5, "5.0(side)" }, - {AkAudioCaps::Layout_5p1 , 6, "5.1" }, - {AkAudioCaps::Layout_5p1_side , 6, "5.1(side)" }, - {AkAudioCaps::Layout_6p0 , 6, "6.0" }, - {AkAudioCaps::Layout_6p0_front , 6, "6.0(front)" }, - {AkAudioCaps::Layout_hexagonal , 6, "hexagonal" }, - {AkAudioCaps::Layout_6p1 , 7, "6.1" }, - {AkAudioCaps::Layout_6p1_front , 7, "6.1(back)" }, - {AkAudioCaps::Layout_6p1_front , 7, "6.1(front)" }, - {AkAudioCaps::Layout_7p0 , 7, "7.0" }, - {AkAudioCaps::Layout_7p0_front , 7, "7.0(front)" }, - {AkAudioCaps::Layout_7p1 , 8, "7.1" }, - {AkAudioCaps::Layout_7p1_wide , 8, "7.1(wide)" }, - {AkAudioCaps::Layout_7p1_wide_side, 8, "7.1(wide-side)"}, - {AkAudioCaps::Layout_octagonal , 8, "octagonal" }, - {AkAudioCaps::Layout_hexadecagonal, 16, "hexadecagonal" }, - {AkAudioCaps::Layout_downmix , 2, "downmix" }, + static const QVector channelLayouts { + {AkAudioCaps::Layout_none , {} , "none" }, + {AkAudioCaps::Layout_mono , {LAYOUT_MONO} , "mono" }, + {AkAudioCaps::Layout_stereo , {LAYOUT_STEREO} , "stereo" }, + {AkAudioCaps::Layout_downmix , {LAYOUT_DOWNMIX} , "downmix" }, + {AkAudioCaps::Layout_2p1 , {LAYOUT_2P1} , "2.1" }, + {AkAudioCaps::Layout_3p0 , {LAYOUT_3P0} , "3.0" }, + {AkAudioCaps::Layout_3p0_back , {LAYOUT_3P0_BACK} , "3.0(back)" }, + {AkAudioCaps::Layout_3p1 , {LAYOUT_3P1} , "3.1" }, + {AkAudioCaps::Layout_4p0 , {LAYOUT_4P0} , "4.0" }, + {AkAudioCaps::Layout_quad , {LAYOUT_QUAD} , "quad" }, + {AkAudioCaps::Layout_quad_side , {LAYOUT_QUAD_SIDE} , "quad(side)" }, + {AkAudioCaps::Layout_4p1 , {LAYOUT_4P1} , "4.1" }, + {AkAudioCaps::Layout_5p0 , {LAYOUT_5P0} , "5.0" }, + {AkAudioCaps::Layout_5p0_side , {LAYOUT_5P0_SIDE} , "5.0(side)" }, + {AkAudioCaps::Layout_5p1 , {LAYOUT_5P1} , "5.1" }, + {AkAudioCaps::Layout_5p1_side , {LAYOUT_5P1_SIDE} , "5.1(side)" }, + {AkAudioCaps::Layout_6p0 , {LAYOUT_6P0} , "6.0" }, + {AkAudioCaps::Layout_6p0_front , {LAYOUT_6P0_FRONT} , "6.0(front)" }, + {AkAudioCaps::Layout_hexagonal , {LAYOUT_HEXAGONAL} , "hexagonal" }, + {AkAudioCaps::Layout_6p1 , {LAYOUT_6P1} , "6.1" }, + {AkAudioCaps::Layout_6p1_back , {LAYOUT_6P1_BACK} , "6.1(back)" }, + {AkAudioCaps::Layout_6p1_front , {LAYOUT_6P1_FRONT} , "6.1(front)" }, + {AkAudioCaps::Layout_7p0 , {LAYOUT_7P0} , "7.0" }, + {AkAudioCaps::Layout_7p0_front , {LAYOUT_7P0_FRONT} , "7.0(front)" }, + {AkAudioCaps::Layout_7p1 , {LAYOUT_7P1} , "7.1" }, + {AkAudioCaps::Layout_7p1_wide , {LAYOUT_7P1_WIDE} , "7.1(wide)" }, + {AkAudioCaps::Layout_7p1_wide_back, {LAYOUT_7P1_WIDE_BACK}, "7.1(wide-back)"}, + {AkAudioCaps::Layout_octagonal , {LAYOUT_OCTAGONAL} , "octagonal" }, + {AkAudioCaps::Layout_hexadecagonal, {LAYOUT_HEXADECAGONAL}, "hexadecagonal" }, }; return channelLayouts; @@ -180,10 +276,10 @@ return &layouts().front(); } - static inline const ChannelLayouts *byChannels(int channels) + static inline const ChannelLayouts *byChannelCount(int channels) { for (auto &layout: layouts()) - if (layout.channels == channels) + if (layout.channels.size() == channels) return &layout; return &layouts().front(); @@ -203,13 +299,10 @@ { public: AkAudioCaps::SampleFormat m_format {AkAudioCaps::SampleFormat_none}; - int m_bps {0}; - int m_channels {0}; - int m_rate {0}; AkAudioCaps::ChannelLayout m_layout {AkAudioCaps::Layout_none}; - int m_samples {false}; - int m_align {0}; - bool m_isValid {false}; + QVector m_planeSize; + int m_rate {0}; + int m_samples {0}; }; AkAudioCaps::AkAudioCaps(QObject *parent): @@ -218,71 +311,54 @@ this->d = new AkAudioCapsPrivate(); } -AkAudioCaps::AkAudioCaps(const QVariantMap &caps) +AkAudioCaps::AkAudioCaps(SampleFormat format, + ChannelLayout layout, + int rate, + int samples, + bool planar, + int align) { this->d = new AkAudioCapsPrivate(); - this->d->m_format = caps["format"].value(); - this->d->m_isValid = this->d->m_format != SampleFormat_none; - this->d->m_bps = caps["bps"].toInt(); - this->d->m_channels = caps["channels"].toInt(); - this->d->m_rate = caps["rate"].toInt(); - this->d->m_layout = caps["layout"].value(); - this->d->m_samples = caps["samples"].toInt(); - this->d->m_align = caps["align"].toInt(); + this->d->m_format = format; + this->d->m_layout = layout; + this->d->m_rate = rate; + this->d->m_samples = samples; + this->updatePlaneSize(planar, align); } -AkAudioCaps::AkAudioCaps(const QString &caps) +AkAudioCaps::AkAudioCaps(AkAudioCaps::SampleFormat format, + AkAudioCaps::ChannelLayout layout, + int rate, + int samples, + const QVector &planeSize) { - this->d = new AkAudioCapsPrivate(); - *this = caps; + this->d->m_format = format; + this->d->m_layout = layout; + this->d->m_rate = rate; + this->d->m_samples = samples; + this->d->m_planeSize = planeSize; } AkAudioCaps::AkAudioCaps(const AkCaps &caps) { this->d = new AkAudioCapsPrivate(); - if (caps.mimeType() == "audio/x-raw") { - this->d->m_isValid = caps.isValid(); - - this->d->m_format = - AkAudioCaps::sampleFormatFromString(caps.property("format").toString()); - this->d->m_bps = caps.property("bps").toInt(); - this->d->m_channels = caps.property("channels").toInt(); - this->d->m_rate = caps.property("rate").toInt(); - - QString layout = caps.property("layout").toString(); - this->d->m_layout = ChannelLayouts::byDescription(layout)->layout; - - this->d->m_samples = caps.property("samples").toInt(); - this->d->m_align = caps.property("align").toInt(); - } + if (caps.mimeType() == "audio/x-raw") + this->update(caps); } AkAudioCaps::AkAudioCaps(const AkAudioCaps &other): QObject() { this->d = new AkAudioCapsPrivate(); - this->d->m_isValid = other.d->m_isValid; this->d->m_format = other.d->m_format; - this->d->m_bps = other.d->m_bps; - this->d->m_channels = other.d->m_channels; - this->d->m_rate = other.d->m_rate; this->d->m_layout = other.d->m_layout; + this->d->m_rate = other.d->m_rate; this->d->m_samples = other.d->m_samples; - this->d->m_align = other.d->m_align; -} + this->d->m_planeSize = other.d->m_planeSize; -AkAudioCaps::AkAudioCaps(AkAudioCaps::SampleFormat format, - int channels, - int rate) -{ - this->d = new AkAudioCapsPrivate(); - this->d->m_format = format; - this->d->m_isValid = this->d->m_format != SampleFormat_none; - this->d->m_bps = AkAudioCaps::bitsPerSample(format); - this->d->m_channels = channels; - this->d->m_rate = rate; - this->d->m_layout = AkAudioCaps::defaultChannelLayout(channels); + for (auto &property: other.dynamicPropertyNames()) + this->setProperty(property, other.property(property)); } AkAudioCaps::~AkAudioCaps() @@ -293,14 +369,16 @@ AkAudioCaps &AkAudioCaps::operator =(const AkAudioCaps &other) { if (this != &other) { - this->d->m_isValid = other.d->m_isValid; this->d->m_format = other.d->m_format; - this->d->m_bps = other.d->m_bps; - this->d->m_channels = other.d->m_channels; - this->d->m_rate = other.d->m_rate; this->d->m_layout = other.d->m_layout; + this->d->m_rate = other.d->m_rate; this->d->m_samples = other.d->m_samples; - this->d->m_align = other.d->m_align; + this->d->m_planeSize = other.d->m_planeSize; + + this->clear(); + + for (auto &property: other.dynamicPropertyNames()) + this->setProperty(property, other.property(property)); } return *this; @@ -309,50 +387,32 @@ AkAudioCaps &AkAudioCaps::operator =(const AkCaps &caps) { if (caps.mimeType() == "audio/x-raw") { - this->d->m_isValid = caps.isValid(); - - this->d->m_format = - AkAudioCaps::sampleFormatFromString(caps.property("format").toString()); - this->d->m_bps = caps.property("bps").toInt(); - this->d->m_channels = caps.property("channels").toInt(); - this->d->m_rate = caps.property("rate").toInt(); - - QString layout = caps.property("layout").toString(); - this->d->m_layout = ChannelLayouts::byDescription(layout)->layout; - - this->d->m_samples = caps.property("samples").toInt(); - this->d->m_align = caps.property("align").toInt(); + this->update(caps); } else { - this->d->m_isValid = false; this->d->m_format = SampleFormat_none; - this->d->m_bps = 0; - this->d->m_channels = 0; - this->d->m_rate = 0; this->d->m_layout = Layout_none; + this->d->m_rate = 0; this->d->m_samples = 0; - this->d->m_align = 0; + this->d->m_planeSize.clear(); } return *this; } -AkAudioCaps &AkAudioCaps::operator =(const QString &caps) -{ - this->operator =(AkCaps(caps)); - - return *this; -} - bool AkAudioCaps::operator ==(const AkAudioCaps &other) const { - return this->d->m_isValid == other.d->m_isValid - && this->d->m_format == other.d->m_format - && this->d->m_bps == other.d->m_bps - && this->d->m_channels == other.d->m_channels - && this->d->m_rate == other.d->m_rate - && this->d->m_layout == other.d->m_layout - && this->d->m_samples == other.d->m_samples - && this->d->m_align == other.d->m_align; + if (this->dynamicPropertyNames() != other.dynamicPropertyNames()) + return false; + + for (auto &property: this->dynamicPropertyNames()) + if (this->property(property) != other.property(property)) + return false; + + return this->d->m_format == other.d->m_format + && this->d->m_layout == other.d->m_layout + && this->d->m_rate == other.d->m_rate + && this->d->m_samples == other.d->m_samples + && this->d->m_planeSize == other.d->m_planeSize; } bool AkAudioCaps::operator !=(const AkAudioCaps &other) const @@ -362,17 +422,28 @@ AkAudioCaps::operator AkCaps() const { - return this->toCaps(); -} + AkCaps caps("audio/x-raw"); + caps.setProperty("format", this->d->m_format); + caps.setProperty("layout" , this->d->m_layout); + caps.setProperty("rate", this->d->m_rate); + caps.setProperty("samples", this->d->m_samples); + caps.setProperty("planeSize", QVariant::fromValue(this->d->m_planeSize)); -bool AkAudioCaps::isValid() const -{ - return this->d->m_isValid; + return caps; } -bool &AkAudioCaps::isValid() +AkAudioCaps::operator bool() const { - return this->d->m_isValid; + auto af = SampleFormats::byFormat(this->d->m_format); + auto layouts = ChannelLayouts::byLayout(this->d->m_layout); + + if (!af || !layouts) + return false; + + if (af->format == SampleFormat_none || layouts->layout == Layout_none) + return false; + + return this->d->m_rate > 0; } AkAudioCaps::SampleFormat AkAudioCaps::format() const @@ -380,29 +451,19 @@ return this->d->m_format; } -AkAudioCaps::SampleFormat &AkAudioCaps::format() +AkAudioCaps::ChannelLayout AkAudioCaps::layout() const { - return this->d->m_format; + return this->d->m_layout; } int AkAudioCaps::bps() const { - return this->d->m_bps; -} - -int &AkAudioCaps::bps() -{ - return this->d->m_bps; + return AkAudioCaps::bitsPerSample(this->d->m_format); } int AkAudioCaps::channels() const { - return this->d->m_channels; -} - -int &AkAudioCaps::channels() -{ - return this->d->m_channels; + return AkAudioCaps::channelCount(this->d->m_layout); } int AkAudioCaps::rate() const @@ -415,135 +476,188 @@ return this->d->m_rate; } -AkAudioCaps::ChannelLayout AkAudioCaps::layout() const -{ - return this->d->m_layout; -} - -AkAudioCaps::ChannelLayout &AkAudioCaps::layout() -{ - return this->d->m_layout; -} - int AkAudioCaps::samples() const { return this->d->m_samples; } -int &AkAudioCaps::samples() +size_t AkAudioCaps::frameSize() const { - return this->d->m_samples; + size_t frameSize = 0; + + for (auto &size: this->d->m_planeSize) + frameSize += size; + + return frameSize; } -int AkAudioCaps::align() const +const QVector AkAudioCaps::positions() const { - return this->d->m_align; + auto layouts = ChannelLayouts::byLayout(this->d->m_layout); + + if (!layouts) + return {}; + + if (layouts->layout == Layout_none) + return {}; + + return layouts->channels; } -int &AkAudioCaps::align() +QVariantMap AkAudioCaps::toMap() const { - return this->d->m_align; + QVariantMap map { + {"mimeType" , "audio/x-raw" }, + {"format" , this->d->m_format }, + {"layout" , this->d->m_layout }, + {"rate" , this->d->m_rate }, + {"samples" , this->d->m_samples }, + {"planeSize", QVariant::fromValue(this->d->m_planeSize)}, + }; + + for (auto &property: this->dynamicPropertyNames()) { + auto key = QString::fromUtf8(property.constData()); + map[key] = this->property(property); + } + + return map; } -AkAudioCaps &AkAudioCaps::fromMap(const QVariantMap &caps) +AkAudioCaps &AkAudioCaps::update(const AkCaps &caps) { - this->d->m_format = caps["format"].value(); - this->d->m_isValid = this->d->m_format != AkAudioCaps::SampleFormat_none; - this->d->m_bps = caps["bps"].toInt(); - this->d->m_channels = caps["channels"].toInt(); - this->d->m_rate = caps["rate"].toInt(); - this->d->m_layout = caps["layout"].value(); - this->d->m_samples = caps["samples"].toInt(); - this->d->m_align = caps["align"].toInt(); + if (caps.mimeType() != "audio/x-raw") + return *this; + + this->clear(); + + for (auto &property: caps.dynamicPropertyNames()) { + int i = this->metaObject()->indexOfProperty(property); + + if (this->metaObject()->property(i).isWritable()) + this->setProperty(property, caps.property(property)); + } + + auto planeSizeVar = caps.property("planeSize"); + bool planar = false; + + if (planeSizeVar.isValid()) { + auto planeSize = caps.property("planeSize").value>(); + planar = planeSize.size() > 1; + } + + this->updatePlaneSize(planar); return *this; } -AkAudioCaps::operator bool() const +size_t AkAudioCaps::planeOffset(int plane) const { - return this->d->m_isValid; + if (plane < 1 || plane > this->planes()) + return 0; + + size_t offset = 0; + + for (int i = 0; i < plane; i++) + offset += this->d->m_planeSize[i]; + + return offset; } -AkAudioCaps &AkAudioCaps::fromString(const QString &caps) +bool AkAudioCaps::planar() const { - return *this = caps; + return this->d->m_planeSize.size() > 1; } -QVariantMap AkAudioCaps::toMap() const +int AkAudioCaps::planes() const { - return QVariantMap { - {"format" , this->d->m_format }, - {"bps" , this->d->m_bps }, - {"channels", this->d->m_channels}, - {"rate" , this->d->m_rate }, - {"layout" , this->d->m_layout }, - {"samples" , this->d->m_samples }, - {"align" , this->d->m_align } - }; + return this->d->m_planeSize.size(); } -QString AkAudioCaps::toString() const +QVector AkAudioCaps::planeSize() const { - if (!this->d->m_isValid) - return QString(); + return this->d->m_planeSize; +} - QString sampleFormat = AkAudioCaps::sampleFormatToString(this->d->m_format); - QString layout = ChannelLayouts::byLayout(this->d->m_layout)->description; +size_t AkAudioCaps::bytesPerPlane() const +{ + if (this->planar()) + return size_t(this->bps() * this->d->m_samples / 8); - return QString("audio/x-raw," - "format=%1," - "bps=%2," - "channels=%3," - "rate=%4," - "layout=%5," - "samples=%6," - "align=%7").arg(sampleFormat) - .arg(this->d->m_bps) - .arg(this->d->m_channels) - .arg(this->d->m_rate) - .arg(layout) - .arg(this->d->m_samples) - .arg(this->d->m_align); + return size_t(this->bps() + * this->channels() + * this->d->m_samples + / 8); } -AkAudioCaps &AkAudioCaps::update(const AkCaps &caps) +void AkAudioCaps::realign(int align) { - if (caps.mimeType() != "audio/x-raw") - return *this; + this->updatePlaneSize(this->planar(), align); +} - if (caps.contains("format")) - this->d->m_format = - AkAudioCaps::sampleFormatFromString(caps.property("format").toString()); +void AkAudioCaps::updatePlaneSize(bool planar, int align) +{ + auto af = SampleFormats::byFormat(this->d->m_format); + auto layouts = ChannelLayouts::byLayout(this->d->m_layout); + auto isEmpty = this->d->m_planeSize.isEmpty(); + this->d->m_planeSize.clear(); - if (caps.contains("bps")) - this->d->m_bps = caps.property("bps").toInt(); + if (!af || !layouts) { + if (!isEmpty) + emit this->planeSizeChanged({}); - if (caps.contains("channels")) - this->d->m_channels = caps.property("channels").toInt(); + return; + } - if (caps.contains("rate")) - this->d->m_rate = caps.property("rate").toInt(); + if (align < 1) + align = 1; - if (caps.contains("layout")) { - QString layout = caps.property("layout").toString(); - this->d->m_layout = ChannelLayouts::byDescription(layout)->layout; - } + QVector planes; - if (caps.contains("samples")) - this->d->m_samples = caps.property("samples").toInt(); + if (planar) { + auto planeSize = + SampleFormats::alignUp(size_t(af->bps + * this->d->m_samples + / 8), + size_t(align)); - if (caps.contains("align")) - this->d->m_align = caps.property("align").toInt(); + for (int channel = 0; channel < layouts->channels.size(); channel++) + planes << planeSize; + } else { + auto planeSize = + SampleFormats::alignUp(size_t(af->bps + * layouts->channels.size() + * this->d->m_samples + / 8), + size_t(align)); + planes = {planeSize}; + } - return *this; + if (this->d->m_planeSize != planes) { + this->d->m_planeSize = planes; + emit this->planeSizeChanged(this->d->m_planeSize); + } } -AkCaps AkAudioCaps::toCaps() const +AkAudioCaps AkAudioCaps::fromMap(const QVariantMap &caps) { - return AkCaps(this->toString()); + AkAudioCaps audioCaps; + + if (!caps.contains("mimeType") || caps["mimeType"] != "audio/x-raw") + return audioCaps; + + for (auto it = caps.begin(); it != caps.end(); it++) { + auto value = it.value(); + + if (it.key() == "mimeType") + continue; + + audioCaps.setProperty(it.key().toStdString().c_str(), value); + } + + return audioCaps; } -int AkAudioCaps::bitsPerSample(AkAudioCaps::SampleFormat sampleFormat) +int AkAudioCaps::bitsPerSample(SampleFormat sampleFormat) { return SampleFormats::byFormat(sampleFormat)->bps; } @@ -553,7 +667,7 @@ return AkAudioCaps::bitsPerSample(AkAudioCaps::sampleFormatFromString(sampleFormat)); } -QString AkAudioCaps::sampleFormatToString(AkAudioCaps::SampleFormat sampleFormat) +QString AkAudioCaps::sampleFormatToString(SampleFormat sampleFormat) { AkAudioCaps caps; int formatIndex = caps.metaObject()->indexOfEnumerator("SampleFormat"); @@ -575,27 +689,24 @@ return static_cast(formatInt); } -AkAudioCaps::SampleFormat AkAudioCaps::sampleFormatFromProperties(AkAudioCaps::SampleType type, +AkAudioCaps::SampleFormat AkAudioCaps::sampleFormatFromProperties(SampleType type, int bps, - int endianness, - bool planar) + int endianness) { - for (const SampleFormats &sampleFormat: SampleFormats::formats()) + for (auto &sampleFormat: SampleFormats::formats()) if (sampleFormat.type == type && sampleFormat.bps == bps - && sampleFormat.endianness == endianness - && sampleFormat.planar == planar) { + && sampleFormat.endianness == endianness) { return sampleFormat.format; } return AkAudioCaps::SampleFormat_none; } -bool AkAudioCaps::sampleFormatProperties(AkAudioCaps::SampleFormat sampleFormat, - AkAudioCaps::SampleType *type, +bool AkAudioCaps::sampleFormatProperties(SampleFormat sampleFormat, + SampleType *type, int *bps, - int *endianness, - bool *planar) + int *endianness) { auto format = SampleFormats::byFormat(sampleFormat); @@ -611,26 +722,21 @@ if (endianness) *endianness = format->endianness; - if (planar) - *planar = format->planar; - return true; } bool AkAudioCaps::sampleFormatProperties(const QString &sampleFormat, - AkAudioCaps::SampleType *type, + SampleType *type, int *bps, - int *endianness, - bool *planar) + int *endianness) { return AkAudioCaps::sampleFormatProperties(AkAudioCaps::sampleFormatFromString(sampleFormat), type, bps, - endianness, - planar); + endianness); } -AkAudioCaps::SampleType AkAudioCaps::sampleType(AkAudioCaps::SampleFormat sampleFormat) +AkAudioCaps::SampleType AkAudioCaps::sampleType(SampleFormat sampleFormat) { return SampleFormats::byFormat(sampleFormat)->type; } @@ -640,7 +746,7 @@ return AkAudioCaps::sampleType(AkAudioCaps::sampleFormatFromString(sampleFormat)); } -QString AkAudioCaps::channelLayoutToString(AkAudioCaps::ChannelLayout channelLayout) +QString AkAudioCaps::channelLayoutToString(ChannelLayout channelLayout) { return ChannelLayouts::byLayout(channelLayout)->description; } @@ -650,17 +756,32 @@ return ChannelLayouts::byDescription(channelLayout)->layout; } -int AkAudioCaps::channelCount(AkAudioCaps::ChannelLayout channelLayout) +AkAudioCaps::ChannelLayout AkAudioCaps::channelLayoutFromPositions(const QVector &positions) { - return ChannelLayouts::byLayout(channelLayout)->channels; + auto positionsSet = QSet::fromList(positions.toList()); + + for (auto &layout: ChannelLayouts::layouts()) { + if (layout.channels.size() != positions.size()) + continue; + + if (positionsSet == QSet::fromList(layout.channels.toList())) + return layout.layout; + } + + return Layout_none; +} + +int AkAudioCaps::channelCount(ChannelLayout channelLayout) +{ + return ChannelLayouts::byLayout(channelLayout)->channels.size(); } int AkAudioCaps::channelCount(const QString &channelLayout) { - return ChannelLayouts::byDescription(channelLayout)->channels; + return ChannelLayouts::byDescription(channelLayout)->channels.size(); } -int AkAudioCaps::endianness(AkAudioCaps::SampleFormat sampleFormat) +int AkAudioCaps::endianness(SampleFormat sampleFormat) { return SampleFormats::byFormat(sampleFormat)->endianness; } @@ -670,51 +791,56 @@ return AkAudioCaps::endianness(AkAudioCaps::sampleFormatFromString(sampleFormat)); } -bool AkAudioCaps::isPlanar(AkAudioCaps::SampleFormat sampleFormat) +AkAudioCaps::ChannelLayout AkAudioCaps::defaultChannelLayout(int channelCount) { - return SampleFormats::byFormat(sampleFormat)->planar; + return ChannelLayouts::byChannelCount(channelCount)->layout; } -bool AkAudioCaps::isPlanar(const QString &sampleFormat) +QString AkAudioCaps::defaultChannelLayoutString(int channelCount) { - return AkAudioCaps::isPlanar(AkAudioCaps::sampleFormatFromString(sampleFormat)); + return ChannelLayouts::byChannelCount(channelCount)->description; } -AkAudioCaps::ChannelLayout AkAudioCaps::defaultChannelLayout(int channelCount) +const QVector &AkAudioCaps::positions(ChannelLayout channelLayout) { - return ChannelLayouts::byChannels(channelCount)->layout; + return ChannelLayouts::byLayout(channelLayout)->channels; } -QString AkAudioCaps::defaultChannelLayoutString(int channelCount) +AkAudioCaps::SpeakerPosition AkAudioCaps::position(Position position) { - return ChannelLayouts::byChannels(channelCount)->description; + auto sp = SpeakerPositions::byPosition(position); + + if (!sp) + return {}; + + return {sp->azimuth, sp->elevation}; } -void AkAudioCaps::setFormat(AkAudioCaps::SampleFormat format) +AkAudioCaps::SpeakerPosition AkAudioCaps::position(int channel) const { - if (this->d->m_format == format) - return; + auto positions = AkAudioCaps::positions(this->d->m_layout); - this->d->m_format = format; - emit this->formatChanged(format); + return AkAudioCaps::position(positions.at(channel)); } -void AkAudioCaps::setBps(int bps) +void AkAudioCaps::setFormat(SampleFormat format) { - if (this->d->m_bps == bps) + if (this->d->m_format == format) return; - this->d->m_bps = bps; - emit this->bpsChanged(bps); + this->d->m_format = format; + this->updatePlaneSize(this->planar()); + emit this->formatChanged(format); } -void AkAudioCaps::setChannels(int channels) +void AkAudioCaps::setLayout(ChannelLayout layout) { - if (this->d->m_channels == channels) + if (this->d->m_layout == layout) return; - this->d->m_channels = channels; - emit this->channelsChanged(channels); + this->d->m_layout = layout; + this->updatePlaneSize(this->planar()); + emit this->layoutChanged(layout); } void AkAudioCaps::setRate(int rate) @@ -726,31 +852,23 @@ emit this->rateChanged(rate); } -void AkAudioCaps::setLayout(AkAudioCaps::ChannelLayout layout) -{ - if (this->d->m_layout == layout) - return; - - this->d->m_layout = layout; - emit this->layoutChanged(layout); -} - void AkAudioCaps::setSamples(int samples) { if (this->d->m_samples == samples) return; this->d->m_samples = samples; + this->updatePlaneSize(this->planar()); emit this->samplesChanged(samples); } -void AkAudioCaps::setAlign(int align) +void AkAudioCaps::setPlaneSize(const QVector &planeSize) { - if (this->d->m_align == align) + if (this->d->m_planeSize == planeSize) return; - this->d->m_align = align; - emit this->alignChanged(align); + this->d->m_planeSize = planeSize; + emit this->planeSizeChanged(planeSize); } void AkAudioCaps::resetFormat() @@ -758,55 +876,166 @@ this->setFormat(SampleFormat_none); } -void AkAudioCaps::resetBps() +void AkAudioCaps::resetLayout() { - this->setBps(0); + this->setLayout(Layout_none); } -void AkAudioCaps::resetChannels() +void AkAudioCaps::resetRate() { - this->setChannels(0); + this->setRate(0); } -void AkAudioCaps::resetRate() +void AkAudioCaps::resetSamples() { - this->setRate(0); + this->setSamples(0); } -void AkAudioCaps::resetLayout() +void AkAudioCaps::resetPlaneSize() { - this->setLayout(Layout_none); + this->setPlaneSize({}); } -void AkAudioCaps::resetSamples() +void AkAudioCaps::clear() { - this->setSamples(0); + for (auto &property: this->dynamicPropertyNames()) + this->setProperty(property.constData(), QVariant()); } -void AkAudioCaps::resetAlign() +qreal operator -(const AkAudioCaps::SpeakerPosition &pos1, + const AkAudioCaps::SpeakerPosition &pos2) { - this->setAlign(0); + auto a1 = qDegreesToRadians(pos1.first); + auto e1 = qDegreesToRadians(pos1.second); + + auto x1 = qCos(e1) * qCos(a1); + auto y1 = qCos(e1) * qSin(a1); + auto z1 = qSin(e1); + + auto a2 = qDegreesToRadians(pos2.first); + auto e2 = qDegreesToRadians(pos2.second); + + auto x2 = qCos(e2) * qCos(a2); + auto y2 = qCos(e2) * qSin(a2); + auto z2 = qSin(e2); + + auto dx = x1 - x2; + auto dy = y1 - y2; + auto dz = z1 - z2; + + return qSqrt(dx * dx + dy * dy + dz * dz); } QDebug operator <<(QDebug debug, const AkAudioCaps &caps) { - debug.nospace() << caps.toString(); + QDebugStateSaver saver(debug); + debug.nospace() << "AkAudioCaps(" + << "format=" + << caps.format() + << ",layout=" + << caps.layout() + << ",rate=" + << caps.rate() + << ",samples=" + << caps.samples() + << ",planeSize=" + << caps.planeSize(); + + QStringList properties; + + for (auto &property: caps.dynamicPropertyNames()) + properties << QString::fromUtf8(property.constData()); + + properties.sort(); + + for (auto &property: properties) + debug << "," + << property.toStdString().c_str() + << "=" + << caps.property(property.toStdString().c_str()); + + debug << ")"; + + return debug; +} + +QDebug operator <<(QDebug debug, AkAudioCaps::SampleFormat format) +{ + QDebugStateSaver saver(debug); + debug.nospace() << AkAudioCaps::sampleFormatToString(format).toStdString().c_str(); + + return debug; +} + +QDebug operator <<(QDebug debug, AkAudioCaps::SampleType sampleType) +{ + AkAudioCaps caps; + int sampleTypeIndex = caps.metaObject()->indexOfEnumerator("SampleType"); + QMetaEnum sampleTypeEnum = caps.metaObject()->enumerator(sampleTypeIndex); + QString sampleTypeStr(sampleTypeEnum.valueToKey(sampleType)); + sampleTypeStr.remove("SampleType_"); + QDebugStateSaver saver(debug); + debug.nospace() << sampleTypeStr.toStdString().c_str(); + + return debug; +} + +QDebug operator <<(QDebug debug, AkAudioCaps::Position position) +{ + AkAudioCaps caps; + int positionIndex = caps.metaObject()->indexOfEnumerator("Position"); + QMetaEnum positionEnum = caps.metaObject()->enumerator(positionIndex); + QString positionStr(positionEnum.valueToKey(position)); + positionStr.remove("Position_"); + QDebugStateSaver saver(debug); + debug.nospace() << positionStr.toStdString().c_str(); + + return debug; +} + +QDebug operator <<(QDebug debug, AkAudioCaps::ChannelLayout layout) +{ + QDebugStateSaver saver(debug); + debug.nospace() << AkAudioCaps::channelLayoutToString(layout).toStdString().c_str(); - return debug.space(); + return debug; } QDataStream &operator >>(QDataStream &istream, AkAudioCaps &caps) { - QString capsStr; - istream >> capsStr; - caps.fromString(capsStr); + int nProperties; + istream >> nProperties; + + for (int i = 0; i < nProperties; i++) { + QByteArray key; + QVariant value; + istream >> key; + istream >> value; + + caps.setProperty(key.toStdString().c_str(), value); + } return istream; } QDataStream &operator <<(QDataStream &ostream, const AkAudioCaps &caps) { - ostream << caps.toString(); + QVariantMap staticProperties { + {"format" , caps.format() }, + {"layout" , caps.layout() }, + {"rate" , caps.rate() }, + {"samples" , caps.samples() }, + {"planeSize", QVariant::fromValue(caps.planeSize())}, + }; + + int nProperties = + staticProperties.size() + caps.dynamicPropertyNames().size(); + ostream << nProperties; + + for (auto &key: caps.dynamicPropertyNames()) { + ostream << key; + ostream << caps.property(key); + } return ostream; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akaudiocaps.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akaudiocaps.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akaudiocaps.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akaudiocaps.h 2021-02-15 15:25:23.000000000 +0000 @@ -26,7 +26,6 @@ class AkAudioCapsPrivate; class AkCaps; -class QDataStream; class AKCOMMONS_EXPORT AkAudioCaps: public QObject { @@ -35,43 +34,41 @@ Q_ENUMS(SampleType) Q_ENUMS(Position) Q_ENUMS(ChannelLayout) - Q_PROPERTY(bool isValid - READ isValid) Q_PROPERTY(SampleFormat format READ format WRITE setFormat RESET resetFormat NOTIFY formatChanged) + Q_PROPERTY(ChannelLayout layout + READ layout + WRITE setLayout + RESET resetLayout + NOTIFY layoutChanged) Q_PROPERTY(int bps - READ bps - WRITE setBps - RESET resetBps - NOTIFY bpsChanged) + READ bps) Q_PROPERTY(int channels - READ channels - WRITE setChannels - RESET resetChannels - NOTIFY channelsChanged) + READ channels) Q_PROPERTY(int rate READ rate WRITE setRate RESET resetRate NOTIFY rateChanged) - Q_PROPERTY(ChannelLayout layout - READ layout - WRITE setLayout - RESET resetLayout - NOTIFY layoutChanged) Q_PROPERTY(int samples READ samples WRITE setSamples RESET resetSamples NOTIFY samplesChanged) - Q_PROPERTY(int align - READ align - WRITE setAlign - RESET resetAlign - NOTIFY alignChanged) + Q_PROPERTY(size_t frameSize + READ frameSize) + Q_PROPERTY(bool planar + READ planar) + Q_PROPERTY(int planes + READ planes) + Q_PROPERTY(QVector planeSize + READ planeSize + WRITE setPlaneSize + RESET resetPlaneSize + NOTIFY planeSizeChanged) public: enum SampleFormat @@ -79,42 +76,42 @@ SampleFormat_none = -1, SampleFormat_s8, SampleFormat_u8, - SampleFormat_s16, SampleFormat_s16le, SampleFormat_s16be, - SampleFormat_u16, SampleFormat_u16le, SampleFormat_u16be, - SampleFormat_s24, - SampleFormat_s24le, - SampleFormat_s24be, - SampleFormat_u24, - SampleFormat_u24le, - SampleFormat_u24be, - SampleFormat_s32, SampleFormat_s32le, SampleFormat_s32be, - SampleFormat_u32, SampleFormat_u32le, SampleFormat_u32be, - SampleFormat_s64, SampleFormat_s64le, SampleFormat_s64be, - SampleFormat_u64, SampleFormat_u64le, SampleFormat_u64be, - SampleFormat_flt, SampleFormat_fltle, SampleFormat_fltbe, - SampleFormat_dbl, SampleFormat_dblle, SampleFormat_dblbe, - SampleFormat_u8p, - SampleFormat_s16p, - SampleFormat_s32p, - SampleFormat_s64p, - SampleFormat_fltp, - SampleFormat_dblp + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + SampleFormat_s16 = SampleFormat_s16le, + SampleFormat_u16 = SampleFormat_u16le, + SampleFormat_s32 = SampleFormat_s32le, + SampleFormat_u32 = SampleFormat_u32le, + SampleFormat_s64 = SampleFormat_s64le, + SampleFormat_u64 = SampleFormat_u64le, + SampleFormat_flt = SampleFormat_fltle, + SampleFormat_dbl = SampleFormat_dblle, +#else + SampleFormat_s16 = SampleFormat_s16be, + SampleFormat_u16 = SampleFormat_u16be, + SampleFormat_s32 = SampleFormat_s32be, + SampleFormat_u32 = SampleFormat_u32be, + SampleFormat_s64 = SampleFormat_s64be, + SampleFormat_u64 = SampleFormat_u64be, + SampleFormat_flt = SampleFormat_fltbe, + SampleFormat_dbl = SampleFormat_dblbe, +#endif }; enum SampleType @@ -122,193 +119,192 @@ SampleType_unknown = -1, SampleType_int, SampleType_uint, - SampleType_float + SampleType_float, }; enum Position { - Position_unknown = 0x00000000, - Position_FrontLeft = 0x00000001, - Position_FrontRight = 0x00000002, - Position_FrontCenter = 0x00000004, - Position_LowFrequency1 = 0x00000008, - Position_BackLeft = 0x00000010, - Position_BackRight = 0x00000020, - Position_FrontLeftOfCenter = 0x00000040, - Position_FrontRightOfCenter = 0x00000080, - Position_BackCenter = 0x00000100, - Position_LowFrequency2 = 0x00000200, - Position_SideLeft = 0x00000400, - Position_SideRight = 0x00000800, - Position_TopCenter = 0x00001000, - Position_TopFrontLeft = 0x00002000, - Position_TopFrontCenter = 0x00004000, - Position_TopFrontRight = 0x00008000, - Position_TopBackLeft = 0x00010000, - Position_TopBackCenter = 0x00020000, - Position_TopBackRight = 0x00040000, - Position_TopSideLeft = 0x00080000, - Position_TopSideRight = 0x00100000, - Position_BottomFrontCenter = 0x00200000, - Position_BottomFrontLeft = 0x00400000, - Position_BottomFrontRight = 0x00800000, - Position_StereoLeft = 0x01000000, - Position_StereoRight = 0x02000000, - Position_WideLeft = 0x04000000, - Position_WideRight = 0x08000000, - Position_SurroundDirectLeft = 0x10000000, - Position_SurroundDirectRight = 0x20000000 + Position_unknown = -1, + Position_FrontCenter, + Position_FrontLeft, + Position_FrontRight, + Position_BackCenter, + Position_BackLeft, + Position_BackRight, + Position_FrontLeftOfCenter, + Position_FrontRightOfCenter, + Position_WideLeft, + Position_WideRight, + Position_SideLeft, + Position_SideRight, + Position_LowFrequency1, + Position_LowFrequency2, + Position_TopCenter, + Position_TopFrontCenter, + Position_TopFrontLeft, + Position_TopFrontRight, + Position_TopBackCenter, + Position_TopBackLeft, + Position_TopBackRight, + Position_TopSideLeft, + Position_TopSideRight, + Position_BottomFrontCenter, + Position_BottomFrontLeft, + Position_BottomFrontRight, + Position_StereoLeft, + Position_StereoRight, + Position_SurroundDirectLeft, + Position_SurroundDirectRight, }; - Q_DECLARE_FLAGS(Positions, Position) - Q_FLAG(Positions) enum ChannelLayout { - Layout_none = 0, - Layout_mono = Position_FrontCenter, - Layout_stereo = Position_FrontLeft | Position_FrontRight, - Layout_2p1 = Layout_stereo | Position_LowFrequency1, - Layout_3p0 = Layout_stereo | Position_FrontCenter, - Layout_3p0_back = Layout_stereo | Position_BackCenter, - Layout_3p1 = Layout_3p0 | Position_LowFrequency1, - Layout_4p0 = Layout_3p0 | Position_BackCenter, - Layout_quad = Layout_stereo | Position_BackLeft | Position_BackRight, - Layout_quad_side = Layout_stereo | Position_SideLeft | Position_SideRight, - Layout_4p1 = Layout_4p0 | Position_LowFrequency1, - Layout_5p0 = Layout_3p0 | Position_BackLeft | Position_BackRight, - Layout_5p0_side = Layout_3p0 | Position_SideLeft | Position_SideRight, - Layout_5p1 = Layout_5p0 | Position_LowFrequency1, - Layout_5p1_side = Layout_5p0_side | Position_LowFrequency1, - Layout_6p0 = Layout_5p0_side | Position_BackCenter, - Layout_6p0_front = Layout_quad_side | Position_FrontLeftOfCenter | Position_FrontRightOfCenter, - Layout_hexagonal = Layout_5p0 | Position_BackCenter, - Layout_6p1 = Layout_5p1_side | Position_BackCenter, - Layout_6p1_back = Layout_5p1 | Position_BackCenter, - Layout_6p1_front = Layout_6p0_front | Position_LowFrequency1, - Layout_7p0 = Layout_5p0_side | Position_BackLeft | Position_BackRight, - Layout_7p0_front = Layout_5p0_side | Position_FrontLeftOfCenter | Position_FrontRightOfCenter, - Layout_7p1 = Layout_5p1_side | Position_BackLeft | Position_BackRight, - Layout_7p1_wide = Layout_5p1_side | Position_FrontLeftOfCenter | Position_FrontRightOfCenter, - Layout_7p1_wide_side = Layout_5p1 | Position_FrontLeftOfCenter | Position_FrontRightOfCenter, - Layout_octagonal = Layout_7p0 | Position_BackCenter, - Layout_hexadecagonal = Layout_octagonal - | Position_WideLeft | Position_WideRight - | Position_BackLeft | Position_BackRight - | Position_TopBackCenter | Position_TopFrontCenter - | Position_TopFrontLeft | Position_TopFrontRight, - Layout_downmix = Position_StereoLeft | Position_StereoRight + Layout_none = -1, + Layout_mono, + Layout_stereo, + Layout_downmix, + Layout_2p1, + Layout_3p0, + Layout_3p0_back, + Layout_3p1, + Layout_4p0, + Layout_quad, + Layout_quad_side, + Layout_4p1, + Layout_5p0, + Layout_5p0_side, + Layout_5p1, + Layout_5p1_side, + Layout_6p0, + Layout_6p0_front, + Layout_hexagonal, + Layout_6p1, + Layout_6p1_back, + Layout_6p1_front, + Layout_7p0, + Layout_7p0_front, + Layout_7p1, + Layout_7p1_wide, + Layout_7p1_wide_back, + Layout_octagonal, + Layout_hexadecagonal, }; + using SpeakerPosition = QPair; + AkAudioCaps(QObject *parent=nullptr); - AkAudioCaps(const QVariantMap &caps); - AkAudioCaps(const QString &caps); + AkAudioCaps(SampleFormat format, + ChannelLayout layout, + int rate, + int samples=0, + bool planar=false, + int align=1); + AkAudioCaps(SampleFormat format, + ChannelLayout layout, + int rate, + int samples, + const QVector &planeSize); AkAudioCaps(const AkCaps &caps); AkAudioCaps(const AkAudioCaps &other); - AkAudioCaps(SampleFormat format, int channels, int rate); ~AkAudioCaps(); AkAudioCaps &operator =(const AkAudioCaps &other); AkAudioCaps &operator =(const AkCaps &caps); - AkAudioCaps &operator =(const QString &caps); bool operator ==(const AkAudioCaps &other) const; bool operator !=(const AkAudioCaps &other) const; operator bool() const; operator AkCaps() const; - Q_INVOKABLE bool isValid() const; - Q_INVOKABLE bool &isValid(); Q_INVOKABLE SampleFormat format() const; - Q_INVOKABLE SampleFormat &format(); + Q_INVOKABLE ChannelLayout layout() const; Q_INVOKABLE int bps() const; - Q_INVOKABLE int &bps(); Q_INVOKABLE int channels() const; - Q_INVOKABLE int &channels(); Q_INVOKABLE int rate() const; Q_INVOKABLE int &rate(); - Q_INVOKABLE ChannelLayout layout() const; - Q_INVOKABLE ChannelLayout &layout(); Q_INVOKABLE int samples() const; - Q_INVOKABLE int &samples(); - Q_INVOKABLE int align() const; - Q_INVOKABLE int &align(); + Q_INVOKABLE size_t frameSize() const; + Q_INVOKABLE const QVector positions() const; - Q_INVOKABLE AkAudioCaps &fromMap(const QVariantMap &caps); - Q_INVOKABLE AkAudioCaps &fromString(const QString &caps); Q_INVOKABLE QVariantMap toMap() const; - Q_INVOKABLE QString toString() const; Q_INVOKABLE AkAudioCaps &update(const AkCaps &caps); - Q_INVOKABLE AkCaps toCaps() const; + Q_INVOKABLE size_t planeOffset(int plane) const; + Q_INVOKABLE bool planar() const; + Q_INVOKABLE int planes() const; + Q_INVOKABLE QVector planeSize() const; + Q_INVOKABLE size_t bytesPerPlane() const; + Q_INVOKABLE void realign(int align); + Q_INVOKABLE void updatePlaneSize(bool planar, int align=1); + Q_INVOKABLE static AkAudioCaps fromMap(const QVariantMap &caps); Q_INVOKABLE static int bitsPerSample(SampleFormat sampleFormat); Q_INVOKABLE static int bitsPerSample(const QString &sampleFormat); Q_INVOKABLE static QString sampleFormatToString(SampleFormat sampleFormat); Q_INVOKABLE static SampleFormat sampleFormatFromString(const QString &sampleFormat); - Q_INVOKABLE static SampleFormat sampleFormatFromProperties(AkAudioCaps::SampleType type, + Q_INVOKABLE static SampleFormat sampleFormatFromProperties(SampleType type, int bps, - int endianness, - bool planar); + int endianness); Q_INVOKABLE static bool sampleFormatProperties(SampleFormat sampleFormat, - AkAudioCaps::SampleType *type=nullptr, + SampleType *type=nullptr, int *bps=nullptr, - int *endianness=nullptr, - bool *planar=nullptr); + int *endianness=nullptr); Q_INVOKABLE static bool sampleFormatProperties(const QString &sampleFormat, - AkAudioCaps::SampleType *type=nullptr, + SampleType *type=nullptr, int *bps=nullptr, - int *endianness=nullptr, - bool *planar=nullptr); + int *endianness=nullptr); Q_INVOKABLE static SampleType sampleType(SampleFormat sampleFormat); Q_INVOKABLE static SampleType sampleType(const QString &sampleFormat); Q_INVOKABLE static QString channelLayoutToString(ChannelLayout channelLayout); Q_INVOKABLE static ChannelLayout channelLayoutFromString(const QString &channelLayout); + Q_INVOKABLE static ChannelLayout channelLayoutFromPositions(const QVector &positions); Q_INVOKABLE static int channelCount(ChannelLayout channelLayout); Q_INVOKABLE static int channelCount(const QString &channelLayout); Q_INVOKABLE static int endianness(SampleFormat sampleFormat); Q_INVOKABLE static int endianness(const QString &sampleFormat); - Q_INVOKABLE static bool isPlanar(SampleFormat sampleFormat); - Q_INVOKABLE static bool isPlanar(const QString &sampleFormat); Q_INVOKABLE static ChannelLayout defaultChannelLayout(int channelCount); Q_INVOKABLE static QString defaultChannelLayoutString(int channelCount); + Q_INVOKABLE static const QVector &positions(ChannelLayout channelLayout); + Q_INVOKABLE static SpeakerPosition position(Position position); + Q_INVOKABLE SpeakerPosition position(int channel) const; private: AkAudioCapsPrivate *d; Q_SIGNALS: void formatChanged(SampleFormat format); - void bpsChanged(int bps); - void channelsChanged(int channels); - void rateChanged(int rate); void layoutChanged(ChannelLayout layout); + void rateChanged(int rate); void samplesChanged(int samples); - void alignChanged(int align); + void planeSizeChanged(const QVector &planeSize); public Q_SLOTS: void setFormat(SampleFormat format); - void setBps(int bps); - void setChannels(int channels); - void setRate(int rate); void setLayout(ChannelLayout layout); + void setRate(int rate); void setSamples(int samples); - void setAlign(int align); + void setPlaneSize(const QVector &planeSize); void resetFormat(); - void resetBps(); - void resetChannels(); - void resetRate(); void resetLayout(); + void resetRate(); void resetSamples(); - void resetAlign(); - - friend QDebug operator <<(QDebug debug, const AkAudioCaps &caps); - friend QDataStream &operator >>(QDataStream &istream, AkAudioCaps &caps); - friend QDataStream &operator <<(QDataStream &ostream, const AkAudioCaps &caps); + void resetPlaneSize(); + void clear(); }; -QDebug operator <<(QDebug debug, const AkAudioCaps &caps); -QDataStream &operator >>(QDataStream &istream, AkAudioCaps &caps); -QDataStream &operator <<(QDataStream &ostream, const AkAudioCaps &caps); +AKCOMMONS_EXPORT qreal operator -(const AkAudioCaps::SpeakerPosition &pos1, + const AkAudioCaps::SpeakerPosition &pos2); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, const AkAudioCaps &caps); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, AkAudioCaps::SampleFormat format); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, AkAudioCaps::SampleType sampleType); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, AkAudioCaps::Position position); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, AkAudioCaps::ChannelLayout layout); +AKCOMMONS_EXPORT QDataStream &operator >>(QDataStream &istream, AkAudioCaps &caps); +AKCOMMONS_EXPORT QDataStream &operator <<(QDataStream &ostream, const AkAudioCaps &caps); Q_DECLARE_METATYPE(AkAudioCaps) Q_DECLARE_METATYPE(AkAudioCaps::SampleFormat) +Q_DECLARE_METATYPE(AkAudioCaps::SampleType) +Q_DECLARE_METATYPE(AkAudioCaps::Position) Q_DECLARE_METATYPE(AkAudioCaps::ChannelLayout) -Q_DECLARE_OPERATORS_FOR_FLAGS(AkAudioCaps::Positions) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) #endif // AKAUDIOCAPS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akaudiopacket.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akaudiopacket.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akaudiopacket.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akaudiopacket.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -18,63 +18,566 @@ */ #include +#include +#include #include +#include +#include #include "akaudiopacket.h" -#include "akaudiocaps.h" +#include "akpacket.h" #include "akcaps.h" +#include "akfrac.h" + +using AudioConvertFuntion = + std::function; class AkAudioPacketPrivate { public: AkAudioCaps m_caps; + QByteArray m_buffer; + qint64 m_pts {0}; + AkFrac m_timeBase; + qint64 m_id {-1}; + int m_index {-1}; + + template + inline static OutputType scaleValue(InputType value) + { + InputType xmin; + InputType xmax; + + if (typeid(InputType) == typeid(float)) { + value = qBound(InputType(-1.0f), + value, + InputType(1.0f)); + xmin = InputType(-1.0f); + xmax = InputType(1.0f); + } else if (typeid(InputType) == typeid(qreal)) { + value = qBound(InputType(-1.0), + value, + InputType(1.0)); + xmin = InputType(-1.0); + xmax = InputType(1.0); + } else { + xmin = std::numeric_limits::min(); + xmax = std::numeric_limits::max(); + } + + OutputType ymin; + OutputType ymax; + + if (typeid(OutputType) == typeid(float)) { + ymin = OutputType(-1.0f); + ymax = OutputType(1.0f); + } else if (typeid(OutputType) == typeid(qreal)) { + ymin = OutputType(-1.0); + ymax = OutputType(1.0); + } else { + ymin = std::numeric_limits::min(); + ymax = std::numeric_limits::max(); + } + + return OutputType((OpType(value - xmin) + * (OpType(ymax) - OpType(ymin)) + + OpType(ymin) * (OpType(xmax) - OpType(xmin))) + / (OpType(xmax) - OpType(xmin))); + } + + template + inline static OutputType scaleValue(InputType value, + InputType xmin, + InputType xmax, + OutputType ymin, + OutputType ymax) + { + return OutputType((OpType(value - xmin) + * (OpType(ymax) - OpType(ymin)) + + OpType(ymin) + * (OpType(xmax) - OpType(xmin))) + / (OpType(xmax) - OpType(xmin))); + } + + template + inline static T from_(T value) { + return value; + } + + template + inline static T fromLE(T value) { + return qFromLittleEndian(value); + } + + template + inline static T fromBE(T value) { + return qFromBigEndian(value); + } + + template + inline static T to_(T value) { + return value; + } + + template + inline static T toLE(T value) { + return qToLittleEndian(value); + } + + template + inline static T toBE(T value) { + return qToBigEndian(value); + } + + template + inline static AkAudioPacket convertSampleFormat(const AkAudioPacket &src, + AkAudioCaps::SampleFormat format, + TransformFuncType1 transformFrom, + TransformFuncType2 transformTo) + { + auto caps = src.caps(); + caps.setFormat(format); + AkAudioPacket dst(caps); + dst.copyMetadata(src); + + for (int plane = 0; plane < caps.planes(); plane++) { + auto src_line = reinterpret_cast(src.constPlaneData(plane)); + auto dst_line = reinterpret_cast(dst.planeData(plane)); + + for (int i = 0; i < caps.samples(); i++) + dst_line[i] = + transformTo(scaleValue(transformFrom(src_line[i]))); + } + + return dst; + } + +#define DEFINE_SAMPLE_CONVERT_FUNCTION(sitype, \ + sotype, \ + itype, \ + otype, \ + optype, \ + inEndian, \ + outEndian) \ + {AkAudioCaps::SampleFormat_##sitype, \ + AkAudioCaps::SampleFormat_##sotype, \ + [] (const AkAudioPacket &src) -> AkAudioPacket { \ + return convertSampleFormat \ + (src, \ + AkAudioCaps::SampleFormat_##sotype, \ + from##inEndian, \ + to##outEndian); \ + }}, \ + {AkAudioCaps::SampleFormat_##sotype, \ + AkAudioCaps::SampleFormat_##sitype, \ + [] (const AkAudioPacket &src) -> AkAudioPacket { \ + return convertSampleFormat \ + (src, \ + AkAudioCaps::SampleFormat_##sitype, \ + from##outEndian, \ + to##inEndian); \ + }} + + struct AudioSampleFormatConvert + { + AkAudioCaps::SampleFormat from; + AkAudioCaps::SampleFormat to; + AudioConvertFuntion convert; + }; + + using AudioSampleFormatConvertFuncs = QVector; + + inline static const AudioSampleFormatConvertFuncs &sampleFormatConvert() + { + // Convert sample formats + static const AudioSampleFormatConvertFuncs convert { + DEFINE_SAMPLE_CONVERT_FUNCTION(s8 , dbl, qint8, qreal, qreal, _, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(u8 , dbl, quint8, qreal, qreal, _, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(s16le, dbl, qint16, qreal, qreal, LE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(s16be, dbl, qint16, qreal, qreal, BE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(u16le, dbl, quint16, qreal, qreal, LE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(u16be, dbl, quint16, qreal, qreal, BE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(s32le, dbl, qint32, qreal, qreal, LE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(s32be, dbl, qint32, qreal, qreal, BE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(u32le, dbl, quint32, qreal, qreal, LE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(u32be, dbl, quint32, qreal, qreal, BE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(s64le, dbl, qint64, qreal, qreal, LE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(s64be, dbl, qint64, qreal, qreal, BE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(u64le, dbl, quint64, qreal, qreal, LE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(u64be, dbl, quint64, qreal, qreal, BE, _), + +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + DEFINE_SAMPLE_CONVERT_FUNCTION(fltle, dbl, float, qreal, qreal, LE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(fltbe, dbl, float, qreal, qreal, BE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(dblle, dbl, qreal, qreal, qreal, LE, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(dblbe, dbl, qreal, qreal, qreal, BE, _), +#else + DEFINE_SAMPLE_CONVERT_FUNCTION(fltle, dbl, float, qreal, qreal, _, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(fltbe, dbl, float, qreal, qreal, _, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(dblle, dbl, qreal, qreal, qreal, _, _), + DEFINE_SAMPLE_CONVERT_FUNCTION(dblbe, dbl, qreal, qreal, qreal, _, _), +#endif + }; + + return convert; + } + + template + inline static AkAudioPacket mixChannels(AkAudioCaps::SampleFormat sumFormat, + AkAudioCaps::ChannelLayout outputLayout, + const AkAudioPacket &src, + TransformFuncType transformFrom, + TransformFuncType transformTo) + { + // Create a summatory packet which type is big enough to contain + // the sum of all values. + auto caps = src.caps(); + caps.setFormat(sumFormat); + caps.setLayout(outputLayout); + AkAudioPacket sumPacket(caps); + sumPacket.buffer().fill(0); + + // Create output packet. + caps = src.caps(); + caps.setLayout(outputLayout); + AkAudioPacket dst(caps); + dst.copyMetadata(src); + + for (int ochannel = 0; ochannel < sumPacket.caps().channels(); ochannel++) { + auto oposition = sumPacket.caps().position(ochannel); + + // Wave limits + auto xmin = std::numeric_limits::max(); + auto xmax = std::numeric_limits::min(); + auto ymin = std::numeric_limits::max(); + auto ymax = std::numeric_limits::min(); + + for (int ichannel = 0; ichannel < src.caps().channels(); ichannel++) { + /* We use inverse square law to sum the samples + * according to the speaker position in the sound dome. + * + * http://digitalsoundandmusic.com/4-3-4-the-mathematics-of-the-inverse-square-law-and-pag-equations/ + */ + auto iposition = src.caps().position(ichannel); + auto d = 1.0 + (oposition - iposition); + auto k = d * d; + + for (int sample = 0; sample < sumPacket.caps().samples(); sample++) { + auto inSample = + reinterpret_cast(src.constSample(ichannel, + sample)); + auto outSample = + reinterpret_cast(sumPacket.sample(ochannel, + sample)); + auto isample = SumType(qreal(transformFrom(*inSample)) / k); + *outSample += isample; + + // Calculate minimum and maximum values of the wave. + if (ichannel == src.caps().channels() - 1) { + xmin = qMin(xmin, *outSample); + xmax = qMax(xmax, *outSample); + } + + ymin = qMin(ymin, *inSample); + ymax = qMax(ymax, *inSample); + } + } + + // Recreate frame with the wave scaled to fit it. + for (int sample = 0; sample < dst.caps().samples(); sample++) { + auto idata = + reinterpret_cast(sumPacket.constSample(ochannel, + sample)); + auto odata = + reinterpret_cast(dst.sample(ochannel, + sample)); + + *odata = transformTo(scaleValue(*idata, + xmin, + xmax, + ymin, + ymax)); + } + } + + return dst; + } + +#define HANDLE_CASE_CONVERT_LAYOUT(olayout, \ + src, \ + format, \ + sumFormat, \ + sampleType, \ + sumType, \ + endian) \ + case AkAudioCaps::SampleFormat_##format: \ + return mixChannels \ + (AkAudioCaps::SampleFormat_##sumFormat, \ + olayout, \ + src, \ + from##endian, \ + to##endian); + + inline static AkAudioPacket convertChannels(AkAudioCaps::ChannelLayout outputLayout, + const AkAudioPacket &src) + { + switch (src.caps().format()) { + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, s8 , dbl, qint8 , qreal, _) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, u8 , dbl, quint8 , qreal, _) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, s16le, dbl, qint16 , qreal, LE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, s16be, dbl, qint16 , qreal, BE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, u16le, dbl, quint16, qreal, LE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, u16be, dbl, quint16, qreal, BE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, s32le, dbl, qint32 , qreal, LE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, s32be, dbl, qint32 , qreal, BE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, u32le, dbl, quint32, qreal, LE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, u32be, dbl, quint32, qreal, BE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, s64le, dbl, qint64 , qreal, LE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, s64be, dbl, qint64 , qreal, BE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, u64le, dbl, quint64, qreal, LE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, u64be, dbl, quint64, qreal, BE) +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, fltle, dbl, float , qreal, LE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, fltbe, dbl, float , qreal, BE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, dblle, dbl, qreal , qreal, LE) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, dblbe, dbl, qreal , qreal, BE) +#else + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, fltle, dbl, float , qreal, _) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, fltbe, dbl, float , qreal, _) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, dblle, dbl, qreal , qreal, _) + HANDLE_CASE_CONVERT_LAYOUT(outputLayout, src, dblbe, dbl, qreal , qreal, _) +#endif + default: + return {}; + } + } + + template + inline static SampleType interpolate(const AkAudioPacket &packet, + int channel, + qreal isample, + int sample1, + int sample2, + TransformFuncType transformFrom, + TransformFuncType transformTo) + { + auto minValue = *reinterpret_cast(packet.constSample(channel, sample1)); + auto maxValue = *reinterpret_cast(packet.constSample(channel, sample2)); + minValue = transformFrom(minValue); + maxValue = transformFrom(maxValue); + auto value = (SumType(isample - sample1) * SumType(maxValue - minValue) + + SumType(minValue) * SumType(sample2 - sample1)) + / (sample2 - sample1); + + return transformTo(SampleType(value)); + } + + template + inline static SampleType interpolate(const AkAudioPacket &packet, + int channel, + qreal isample, + int sample1, + int sample2, + int sample3, + TransformFuncType transformFrom, + TransformFuncType transformTo) + { + auto minValue = *reinterpret_cast(packet.constSample(channel, sample1)); + auto midValue = *reinterpret_cast(packet.constSample(channel, sample2)); + auto maxValue = *reinterpret_cast(packet.constSample(channel, sample3)); + minValue = transformFrom(minValue); + midValue = transformFrom(midValue); + maxValue = transformFrom(maxValue); + auto sample21 = SumType(sample1); + auto sample22 = SumType(sample2); + auto sample23 = SumType(sample3); + /* y = a * x ^ 2 + b * x + c + * + * |a| |x0^2 x0 1|^-1 |y0|; + * |b| = |x1^2 x1 1| |y1|; + * |c| |x2^2 x2 1| |y2|; + */ + auto det = sample21 * SumType(sample2 - sample3) - sample1 * SumType(sample22 - sample23) + SumType(sample22 * sample3 - sample23 * sample2) + - sample22 * SumType(sample2 - sample3) + sample2 * SumType(sample21 - sample23) - SumType(sample21 * sample3 - sample23 * sample1) + + sample23 * SumType(sample1 - sample2) - sample1 * SumType(sample21 - sample22) + SumType(sample21 * sample2 - sample22 * sample1); + const SumType matrixValues[] { + SumType(sample2 - sample3), sample23 - sample22, sample22 * sample3 - sample23 * sample2, + SumType(sample3 - sample1), sample21 - sample23, sample23 * sample1 - sample21 * sample3, + SumType(sample1 - sample2), sample22 - sample21, sample21 * sample2 - sample22 * sample1, + }; + QGenericMatrix<3, 3, SumType> inv(matrixValues); + const SumType yMatrixValues[] { + SumType(minValue), + SumType(midValue), + SumType(maxValue), + }; + QGenericMatrix<1, 3, SumType> valuesMatrix(yMatrixValues); + auto coef = inv * valuesMatrix; + auto value = (coef(0, 0) * isample * isample + coef(1, 0) * isample + coef(2, 0)) + / det; + + return transformTo(SampleType(value)); + } + + using InterpolateLinearFunction = + std::function; + using InterpolateQuadraticFunction = + std::function; + +#define DEFINE_SAMPLE_INTERPOLATION_FUNCTION(sitype, \ + itype, \ + optype, \ + endian) \ + {AkAudioCaps::SampleFormat_##sitype, \ + [] (const AkAudioPacket &packet, \ + int channel, \ + int isample, \ + int sample1, \ + int sample2, \ + quint8 *osample) { \ + auto value = \ + interpolate \ + (packet, \ + channel, \ + isample, \ + sample1, \ + sample2, \ + from##endian, \ + to##endian); \ + memcpy(osample, &value, sizeof(itype)); \ + }, \ + [] (const AkAudioPacket &packet, \ + int channel, \ + int isample, \ + int sample1, \ + int sample2, \ + int sample3, \ + quint8 *osample) { \ + auto value = \ + interpolate \ + (packet, \ + channel, \ + isample, \ + sample1, \ + sample2, \ + sample3, \ + from##endian, \ + to##endian); \ + memcpy(osample, &value, sizeof(itype)); \ + }} + + struct AudioSamplesInterpolation + { + AkAudioCaps::SampleFormat format; + InterpolateLinearFunction linear; + InterpolateQuadraticFunction quadratic; + }; + + using AudioSamplesInterpolationFuncs = QVector; + + inline static const AudioSamplesInterpolationFuncs &samplesInterpolation() + { + static const AudioSamplesInterpolationFuncs interpolation { + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(s8 , qint8, qint64, _), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(u8 , quint8, qint64, _), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(s16le, qint16, qint64, LE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(s16be, qint16, qint64, BE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(u16le, quint16, qint64, LE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(u16be, quint16, qint64, BE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(s32le, qint32, qint64, LE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(s32be, qint32, qint64, BE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(u32le, quint32, qint64, LE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(u32be, quint32, qint64, BE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(s64le, qint64, qreal, LE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(s64be, qint64, qreal, BE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(u64le, quint64, qreal, LE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(u64be, quint64, qreal, BE), + +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(fltle, float, qreal, LE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(fltbe, float, qreal, BE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(dblle, qreal, qreal, LE), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(dblbe, qreal, qreal, BE), +#else + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(fltle, float, qreal, _), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(fltbe, float, qreal, _), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(dblle, qreal, qreal, _), + DEFINE_SAMPLE_INTERPOLATION_FUNCTION(dblbe, qreal, qreal, _), +#endif + }; + + return interpolation; + } + + inline static const AudioSamplesInterpolation *bySamplesInterpolationFormat(AkAudioCaps::SampleFormat format) + { + for (auto &interpolation: samplesInterpolation()) + if (interpolation.format == format) + return &interpolation; + + return &samplesInterpolation().front(); + } }; AkAudioPacket::AkAudioPacket(QObject *parent): - AkPacket(parent) + QObject(parent) { this->d = new AkAudioPacketPrivate(); } -AkAudioPacket::AkAudioPacket(const AkAudioCaps &caps, - const QByteArray &buffer, - qint64 pts, - const AkFrac &timeBase, - int index, - qint64 id) +AkAudioPacket::AkAudioPacket(const AkAudioCaps &caps) { this->d = new AkAudioPacketPrivate(); this->d->m_caps = caps; - this->buffer() = buffer; - this->pts() = pts; - this->timeBase() = timeBase; - this->index() = index; - this->id() = id; + this->d->m_buffer = QByteArray(int(caps.frameSize()), Qt::Uninitialized); } AkAudioPacket::AkAudioPacket(const AkPacket &other) { this->d = new AkAudioPacketPrivate(); this->d->m_caps = other.caps(); - this->data() = other.data(); - this->buffer() = other.buffer(); - this->pts() = other.pts(); - this->timeBase() = other.timeBase(); - this->index() = other.index(); - this->id() = other.id(); + this->d->m_buffer = other.buffer(); + this->d->m_pts = other.pts(); + this->d->m_timeBase = other.timeBase(); + this->d->m_index = other.index(); + this->d->m_id = other.id(); } AkAudioPacket::AkAudioPacket(const AkAudioPacket &other): - AkPacket() + QObject() { this->d = new AkAudioPacketPrivate(); this->d->m_caps = other.d->m_caps; - this->data() = other.data(); - this->buffer() = other.buffer(); - this->pts() = other.pts(); - this->timeBase() = other.timeBase(); - this->index() = other.index(); - this->id() = other.id(); + this->d->m_buffer = other.d->m_buffer; + this->d->m_pts = other.d->m_pts; + this->d->m_timeBase = other.d->m_timeBase; + this->d->m_index = other.d->m_index; + this->d->m_id = other.d->m_id; } AkAudioPacket::~AkAudioPacket() @@ -85,12 +588,11 @@ AkAudioPacket &AkAudioPacket::operator =(const AkPacket &other) { this->d->m_caps = other.caps(); - this->data() = other.data(); - this->buffer() = other.buffer(); - this->pts() = other.pts(); - this->timeBase() = other.timeBase(); - this->index() = other.index(); - this->id() = other.id(); + this->d->m_buffer = other.buffer(); + this->d->m_pts = other.pts(); + this->d->m_timeBase = other.timeBase(); + this->d->m_index = other.index(); + this->d->m_id = other.id(); return *this; } @@ -99,20 +601,83 @@ { if (this != &other) { this->d->m_caps = other.d->m_caps; - this->data() = other.data(); - this->buffer() = other.buffer(); - this->pts() = other.pts(); - this->timeBase() = other.timeBase(); - this->index() = other.index(); - this->id() = other.id(); + this->d->m_buffer = other.d->m_buffer; + this->d->m_pts = other.d->m_pts; + this->d->m_timeBase = other.d->m_timeBase; + this->d->m_index = other.d->m_index; + this->d->m_id = other.d->m_id; + } + + return *this; +} + +AkAudioPacket AkAudioPacket::operator +(const AkAudioPacket &other) +{ + auto tmpPacket = other.convert(this->caps()); + + if (!tmpPacket) + return *this; + + auto caps = this->caps(); + caps.setSamples(this->caps().samples() + tmpPacket.caps().samples()); + AkAudioPacket packet(caps); + packet.copyMetadata(*this); + + for (int plane = 0; plane < caps.planes(); plane++) { + auto start = this->caps().bytesPerPlane(); + memcpy(packet.planeData(plane), + this->constPlaneData(plane), + start); + memcpy(packet.planeData(plane) + start, + other.constPlaneData(plane), + other.caps().bytesPerPlane()); + } + + return packet; +} + +AkAudioPacket &AkAudioPacket::operator +=(const AkAudioPacket &other) +{ + auto tmpPacket = other.convert(this->caps()); + + if (!tmpPacket) + return *this; + + auto caps = this->caps(); + caps.setSamples(this->caps().samples() + tmpPacket.caps().samples()); + AkAudioPacket packet(caps); + packet.copyMetadata(*this); + + for (int plane = 0; plane < caps.planes(); plane++) { + auto start = this->caps().bytesPerPlane(); + memcpy(packet.planeData(plane), + this->constPlaneData(plane), + start); + memcpy(packet.planeData(plane) + start, + other.constPlaneData(plane), + other.caps().bytesPerPlane()); } + *this = packet; + return *this; } +AkAudioPacket::operator AkPacket() const +{ + AkPacket packet(this->d->m_caps); + packet.buffer() = this->d->m_buffer; + packet.pts() = this->d->m_pts; + packet.timeBase() = this->d->m_timeBase; + packet.index() = this->d->m_index; + packet.id() = this->d->m_id; + + return packet; +} + AkAudioPacket::operator bool() const { - return this->d->m_caps.isValid(); + return this->d->m_caps; } AkAudioCaps AkAudioPacket::caps() const @@ -125,56 +690,556 @@ return this->d->m_caps; } -QString AkAudioPacket::toString() const +QByteArray AkAudioPacket::buffer() const { - QString packetInfo; - QDebug debug(&packetInfo); + return this->d->m_buffer; +} - debug.nospace() << "Caps : " - << this->d->m_caps.toString().toStdString().c_str() - << "\n"; +QByteArray &AkAudioPacket::buffer() +{ + return this->d->m_buffer; +} - debug.nospace() << "Data : " - << this->data() - << "\n"; +qint64 AkAudioPacket::id() const +{ + return this->d->m_id; +} - debug.nospace() << "Buffer Size: " - << this->buffer().size() - << "\n"; +qint64 &AkAudioPacket::id() +{ + return this->d->m_id; +} - debug.nospace() << "Id : " - << this->id() - << "\n"; +qint64 AkAudioPacket::pts() const +{ + return this->d->m_pts; +} - debug.nospace() << "Pts : " - << this->pts() - << " (" - << this->pts() * this->timeBase().value() - << ")\n"; +qint64 &AkAudioPacket::pts() +{ + return this->d->m_pts; +} - debug.nospace() << "Time Base : " - << this->timeBase().toString().toStdString().c_str() - << "\n"; +AkFrac AkAudioPacket::timeBase() const +{ + return this->d->m_timeBase; +} - debug.nospace() << "Index : " - << this->index(); +AkFrac &AkAudioPacket::timeBase() +{ + return this->d->m_timeBase; +} - return packetInfo; +int AkAudioPacket::index() const +{ + return this->d->m_index; +} + +int &AkAudioPacket::index() +{ + return this->d->m_index; +} + +void AkAudioPacket::copyMetadata(const AkAudioPacket &other) +{ + this->d->m_pts = other.d->m_pts; + this->d->m_timeBase = other.d->m_timeBase; + this->d->m_index = other.d->m_index; + this->d->m_id = other.d->m_id; } -AkPacket AkAudioPacket::toPacket() const +const quint8 *AkAudioPacket::constPlaneData(int plane) const { - AkPacket packet; - packet.caps() = this->d->m_caps.toCaps(); - packet.buffer() = this->buffer(); - packet.pts() = this->pts(); - packet.timeBase() = this->timeBase(); - packet.index() = this->index(); - packet.id() = this->id(); + return reinterpret_cast(this->d->m_buffer.constData()) + + this->d->m_caps.planeOffset(plane); +} + +quint8 *AkAudioPacket::planeData(int plane) +{ + return reinterpret_cast(this->d->m_buffer.data()) + + this->d->m_caps.planeOffset(plane); +} + +const quint8 *AkAudioPacket::constSample(int channel, int i) const +{ + auto bps = this->d->m_caps.bps(); + + if (this->d->m_caps.planar()) + return this->constPlaneData(channel) + i * bps / 8; + + auto channels = this->d->m_caps.channels(); + + return this->constPlaneData(0) + (i * channels + channel) * bps / 8; +} + +quint8 *AkAudioPacket::sample(int channel, int i) +{ + auto bps = this->d->m_caps.bps(); + + if (this->d->m_caps.planar()) + return this->planeData(channel) + i * bps / 8; + + auto channels = this->d->m_caps.channels(); + + return this->planeData(0) + (i * channels + channel) * bps / 8; +} + +void AkAudioPacket::setSample(int channel, int i, const quint8 *sample) +{ + memcpy(this->sample(channel, i), sample, size_t(this->d->m_caps.bps()) / 8); +} + +AkAudioPacket AkAudioPacket::convert(const AkAudioCaps &caps) const +{ + auto packet = this->convertFormat(caps.format()); + + if (!packet) + return {}; + + packet = packet.convertLayout(caps.layout()); + + if (!packet) + return {}; + + return packet.convertPlanar(caps.planar()); +} + +bool AkAudioPacket::canConvertFormat(AkAudioCaps::SampleFormat input, + AkAudioCaps::SampleFormat output) +{ + if (input == output) + return true; + + bool fromFormat = false; + bool toFormat = false; + + for (auto &convert: AkAudioPacketPrivate::sampleFormatConvert()) { + if (convert.from == input) + fromFormat = true; + + if (convert.to == output) + toFormat = true; + + if (fromFormat && toFormat) + return true; + } + + return false; +} + +bool AkAudioPacket::canConvertFormat(AkAudioCaps::SampleFormat output) const +{ + return AkAudioPacket::canConvertFormat(this->d->m_caps.format(), output); +} + +AkAudioPacket AkAudioPacket::convertFormat(AkAudioCaps::SampleFormat format) const +{ + if (this->d->m_caps.format() == format) + return *this; + + AudioConvertFuntion convertFrom; + AudioConvertFuntion convertTo; + + for (auto &convert: AkAudioPacketPrivate::sampleFormatConvert()) { + if (convert.from == this->d->m_caps.format()) + convertFrom = convert.convert; + + if (convert.to == format) + convertTo = convert.convert; + + if (convert.from == this->d->m_caps.format() + && convert.to == format) { + return convert.convert(*this); + } + } + + if (convertFrom && convertTo) + return convertTo(convertFrom(*this)); + + return {}; +} + +AkAudioPacket AkAudioPacket::convertLayout(AkAudioCaps::ChannelLayout layout) const +{ + if (this->d->m_caps.layout() == layout) + return *this; + + return AkAudioPacketPrivate::convertChannels(layout, *this); +} + +AkAudioPacket AkAudioPacket::convertSampleRate(int rate, + qreal &sampleCorrection, + ResampleMethod method) const +{ + if (rate == this->d->m_caps.rate()) + return *this; + + auto rSamples = qreal(this->d->m_caps.samples()) + * rate + / this->d->m_caps.rate() + + sampleCorrection; + auto oSamples = qRound(rSamples); + + if (oSamples < 1) + return {}; + + auto caps = this->d->m_caps; + caps.setSamples(oSamples); + caps.setRate(rate); + AkAudioPacket packet(caps); + + if (oSamples < this->d->m_caps.samples()) + method = ResampleMethod_Fast; + + switch (method) { + case ResampleMethod_Fast: + for (int channel = 0; channel < packet.caps().channels(); channel++) { + for (int sample = 0; sample < packet.caps().samples(); sample++) { + auto iSample = sample + * (this->d->m_caps.samples() - 1) + / (oSamples - 1); + auto iValue = this->constSample(channel, iSample); + packet.setSample(channel, sample, iValue); + } + } + + break; + + case ResampleMethod_Linear: { + auto sif = + AkAudioPacketPrivate::bySamplesInterpolationFormat(caps.format()); + auto interpolation = sif->linear; + + for (int channel = 0; channel < packet.caps().channels(); channel++) { + for (int sample = 0; sample < packet.caps().samples(); sample++) { + auto iSample = qreal(sample) + * (this->d->m_caps.samples() - 1) + / (oSamples - 1); + auto minSample = qFloor(iSample); + auto maxSample = qCeil(iSample); + + if (minSample == maxSample) { + auto iValue = this->constSample(channel, minSample); + packet.setSample(channel, sample, iValue); + } else { + quint64 data; + interpolation(*this, + channel, + iSample, + minSample, + maxSample, + reinterpret_cast(&data)); + packet.setSample(channel, + sample, + reinterpret_cast(&data)); + } + } + } + + break; + } + + case ResampleMethod_Quadratic: + auto sif = + AkAudioPacketPrivate::bySamplesInterpolationFormat(caps.format()); + auto interpolationL = sif->linear; + auto interpolationQ = sif->quadratic; + + for (int channel = 0; channel < packet.caps().channels(); channel++) { + for (int sample = 0; sample < packet.caps().samples(); sample++) { + auto iSample = qreal(sample) + * (this->d->m_caps.samples() - 1) + / (oSamples - 1); + auto minSample = qFloor(iSample); + auto maxSample = qCeil(iSample); + + if (minSample == maxSample) { + auto iValue = this->constSample(channel, minSample); + packet.setSample(channel, sample, iValue); + } else { + auto diffMinSample = minSample - iSample; + auto diffMaxSample = maxSample - iSample; + diffMinSample *= diffMinSample; + diffMaxSample *= diffMaxSample; + auto midSample = diffMinSample < diffMaxSample? + qMax(minSample - 1, 0): + qMin(maxSample + 1, this->d->m_caps.samples() - 1); + + if (midSample < minSample) + std::swap(midSample, minSample); + + if (midSample > maxSample) + std::swap(midSample, maxSample); + + if (midSample == minSample + || midSample == maxSample) { + quint64 data; + interpolationL(*this, + channel, + iSample, + minSample, + maxSample, + reinterpret_cast(&data)); + packet.setSample(channel, + sample, + reinterpret_cast(&data)); + } else { + quint64 data; + interpolationQ(*this, + channel, + iSample, + minSample, + midSample, + maxSample, + reinterpret_cast(&data)); + packet.setSample(channel, + sample, + reinterpret_cast(&data)); + } + } + } + } + + break; + } + + sampleCorrection = rSamples - oSamples; + + return packet; +} + +AkAudioPacket AkAudioPacket::scale(int samples, + AkAudioPacket::ResampleMethod method) const +{ + if (samples == this->d->m_caps.samples()) + return *this; + + if (samples < 1) + return {}; + + auto caps = this->d->m_caps; + caps.setSamples(samples); + AkAudioPacket packet(caps); + + if (samples < this->d->m_caps.samples()) + method = ResampleMethod_Fast; + + switch (method) { + case ResampleMethod_Fast: + for (int channel = 0; channel < packet.caps().channels(); channel++) { + for (int sample = 0; sample < packet.caps().samples(); sample++) { + auto iSample = sample + * (this->d->m_caps.samples() - 1) + / (samples - 1); + auto iValue = this->constSample(channel, iSample); + packet.setSample(channel, sample, iValue); + } + } + + break; + + case ResampleMethod_Linear: { + auto sif = + AkAudioPacketPrivate::bySamplesInterpolationFormat(caps.format()); + auto interpolation = sif->linear; + + for (int channel = 0; channel < packet.caps().channels(); channel++) { + for (int sample = 0; sample < packet.caps().samples(); sample++) { + auto iSample = qreal(sample) + * (this->d->m_caps.samples() - 1) + / (samples - 1); + auto minSample = qFloor(iSample); + auto maxSample = qCeil(iSample); + + if (minSample == maxSample) { + auto iValue = this->constSample(channel, minSample); + packet.setSample(channel, sample, iValue); + } else { + quint64 data; + interpolation(*this, + channel, + iSample, + minSample, + maxSample, + reinterpret_cast(&data)); + packet.setSample(channel, + sample, + reinterpret_cast(&data)); + } + } + } + + break; + } + + case ResampleMethod_Quadratic: + auto sif = + AkAudioPacketPrivate::bySamplesInterpolationFormat(caps.format()); + auto interpolationL = sif->linear; + auto interpolationQ = sif->quadratic; + + for (int channel = 0; channel < packet.caps().channels(); channel++) { + for (int sample = 0; sample < packet.caps().samples(); sample++) { + auto iSample = qreal(sample) + * (this->d->m_caps.samples() - 1) + / (samples - 1); + auto minSample = qFloor(iSample); + auto maxSample = qCeil(iSample); + + if (minSample == maxSample) { + auto iValue = this->constSample(channel, minSample); + packet.setSample(channel, sample, iValue); + } else { + auto diffMinSample = minSample - iSample; + auto diffMaxSample = maxSample - iSample; + diffMinSample *= diffMinSample; + diffMaxSample *= diffMaxSample; + auto midSample = diffMinSample < diffMaxSample? + qMax(minSample - 1, 0): + qMin(maxSample + 1, this->d->m_caps.samples() - 1); + + if (midSample < minSample) + std::swap(midSample, minSample); + + if (midSample > maxSample) + std::swap(midSample, maxSample); + + if (midSample == minSample + || midSample == maxSample) { + quint64 data; + interpolationL(*this, + channel, + iSample, + minSample, + maxSample, + reinterpret_cast(&data)); + packet.setSample(channel, + sample, + reinterpret_cast(&data)); + } else { + quint64 data; + interpolationQ(*this, + channel, + iSample, + minSample, + midSample, + maxSample, + reinterpret_cast(&data)); + packet.setSample(channel, + sample, + reinterpret_cast(&data)); + } + } + } + } + + break; + } return packet; } +AkAudioPacket AkAudioPacket::convertPlanar(bool planar) const +{ + if ((this->d->m_caps.planar()) == planar) + return *this; + + auto caps = this->d->m_caps; + caps.updatePlaneSize(planar); + AkAudioPacket dst(caps); + dst.copyMetadata(*this); + auto byps = caps.bps() / 8; + auto channels = caps.channels(); + + if (planar) { + auto src_line = this->constPlaneData(0); + + for (int plane = 0; plane < caps.planes(); plane++) { + auto dst_line = dst.planeData(plane); + + for (int i = 0; i < caps.samples(); i++) + memcpy(dst_line + byps * i, + src_line + byps * (i * channels + plane), + size_t(byps)); + } + } else { + auto dst_line = dst.planeData(0); + + for (int plane = 0; plane < this->d->m_caps.planes(); plane++) { + auto src_line = this->constPlaneData(plane); + + for (int i = 0; i < caps.samples(); i++) + memcpy(dst_line + byps * (i * channels + plane), + src_line + byps * i, + size_t(byps)); + } + } + + return dst; +} + +AkAudioPacket AkAudioPacket::realign(int align) const +{ + auto caps = this->d->m_caps; + caps.realign(align); + + if (caps == this->d->m_caps) + return *this; + + AkAudioPacket dst(caps); + dst.copyMetadata(*this); + + for (int plane = 0; plane < caps.planes(); plane++) { + auto planeSize = qMin(caps.planeSize()[plane], + this->d->m_caps.planeSize()[plane]); + auto src_line = this->constPlaneData(plane); + auto dst_line = dst.planeData(plane); + memcpy(dst_line, src_line, planeSize); + } + + return dst; +} + +AkAudioPacket AkAudioPacket::pop(int samples) +{ + auto caps = this->d->m_caps; + samples = qMin(caps.samples(), samples); + + if (samples < 1) + return {}; + + caps.setSamples(samples); + AkAudioPacket dst(caps); + dst.copyMetadata(*this); + + caps.setSamples(this->d->m_caps.samples() - samples); + AkAudioPacket tmpPacket(caps); + tmpPacket.copyMetadata(*this); + auto pts = this->d->m_pts + + samples + * this->d->m_timeBase.invert().value() + / this->d->m_caps.rate(); + tmpPacket.setPts(qRound64(pts)); + + for (int plane = 0; plane < dst.caps().planes(); plane++) { + auto src_line = this->constPlaneData(plane); + auto dst_line = dst.planeData(plane); + auto dataSize = dst.caps().planeSize()[plane]; + memcpy(dst_line, src_line, dataSize); + + src_line = this->constPlaneData(plane) + dataSize; + dst_line = tmpPacket.planeData(plane); + dataSize = tmpPacket.caps().planeSize()[plane]; + + if (dataSize > 0) + memcpy(dst_line, src_line, dataSize); + } + + *this = tmpPacket; + + return dst; +} + void AkAudioPacket::setCaps(const AkAudioCaps &caps) { if (this->d->m_caps == caps) @@ -184,16 +1249,116 @@ emit this->capsChanged(caps); } +void AkAudioPacket::setBuffer(const QByteArray &buffer) +{ + if (this->d->m_buffer == buffer) + return; + + this->d->m_buffer = buffer; + emit this->bufferChanged(buffer); +} + +void AkAudioPacket::setId(qint64 id) +{ + if (this->d->m_id == id) + return; + + this->d->m_id = id; + emit this->idChanged(id); +} + +void AkAudioPacket::setPts(qint64 pts) +{ + if (this->d->m_pts == pts) + return; + + this->d->m_pts = pts; + emit this->ptsChanged(pts); +} + +void AkAudioPacket::setTimeBase(const AkFrac &timeBase) +{ + if (this->d->m_timeBase == timeBase) + return; + + this->d->m_timeBase = timeBase; + emit this->timeBaseChanged(timeBase); +} + +void AkAudioPacket::setIndex(int index) +{ + if (this->d->m_index == index) + return; + + this->d->m_index = index; + emit this->indexChanged(index); +} + void AkAudioPacket::resetCaps() { - this->setCaps(AkAudioCaps()); + this->setCaps({}); +} + +void AkAudioPacket::resetBuffer() +{ + this->setBuffer({}); +} + +void AkAudioPacket::resetId() +{ + this->setId(-1); +} + +void AkAudioPacket::resetPts() +{ + this->setPts(0); +} + +void AkAudioPacket::resetTimeBase() +{ + this->setTimeBase({}); +} + +void AkAudioPacket::resetIndex() +{ + this->setIndex(-1); } QDebug operator <<(QDebug debug, const AkAudioPacket &packet) { - debug.nospace() << packet.toString().toStdString().c_str(); + QDebugStateSaver saver(debug); + debug.nospace() << "AkAudioPacket(" + << "caps=" + << packet.caps() + << ",bufferSize=" + << packet.buffer().size() + << ",id=" + << packet.id() + << ",pts=" + << packet.pts() + << "(" + << packet.pts() * packet.timeBase().value() + << ")" + << ",timeBase=" + << packet.timeBase() + << ",index=" + << packet.index() + << ")"; + + return debug; +} + +QDebug operator <<(QDebug debug, AkAudioPacket::ResampleMethod method) +{ + AkAudioPacket packet; + int resampleMethodIndex = packet.metaObject()->indexOfEnumerator("ResampleMethod"); + QMetaEnum resampleMethodEnum = packet.metaObject()->enumerator(resampleMethodIndex); + QString resampleMethodStr(resampleMethodEnum.valueToKey(method)); + resampleMethodStr.remove("ResampleMethod_"); + QDebugStateSaver saver(debug); + debug.nospace() << resampleMethodStr.toStdString().c_str(); - return debug.space(); + return debug; } #include "moc_akaudiopacket.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akaudiopacket.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akaudiopacket.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akaudiopacket.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akaudiopacket.h 2021-02-15 15:25:23.000000000 +0000 @@ -20,56 +20,131 @@ #ifndef AKAUDIOPACKET_H #define AKAUDIOPACKET_H -#include "akpacket.h" +#include "akaudiocaps.h" class AkAudioPacketPrivate; -class AkAudioCaps; +class AkPacket; +class AkFrac; -class AKCOMMONS_EXPORT AkAudioPacket: public AkPacket +class AKCOMMONS_EXPORT AkAudioPacket: public QObject { Q_OBJECT + Q_ENUMS(ResampleMethod) Q_PROPERTY(AkAudioCaps caps READ caps WRITE setCaps RESET resetCaps NOTIFY capsChanged) + Q_PROPERTY(QByteArray buffer + READ buffer + WRITE setBuffer + RESET resetBuffer + NOTIFY bufferChanged) + Q_PROPERTY(qint64 id + READ id + WRITE setId + RESET resetId + NOTIFY idChanged) + Q_PROPERTY(qint64 pts + READ pts + WRITE setPts + RESET resetPts + NOTIFY ptsChanged) + Q_PROPERTY(AkFrac timeBase + READ timeBase + WRITE setTimeBase + RESET resetTimeBase + NOTIFY timeBaseChanged) + Q_PROPERTY(int index + READ index + WRITE setIndex + RESET resetIndex + NOTIFY indexChanged) public: + enum ResampleMethod + { + ResampleMethod_Fast, + ResampleMethod_Linear, + ResampleMethod_Quadratic + }; + AkAudioPacket(QObject *parent=nullptr); - AkAudioPacket(const AkAudioCaps &caps, - const QByteArray &buffer=QByteArray(), - qint64 pts=0, - const AkFrac &timeBase=AkFrac(), - int index=-1, - qint64 id=-1); + AkAudioPacket(const AkAudioCaps &caps); AkAudioPacket(const AkPacket &other); AkAudioPacket(const AkAudioPacket &other); ~AkAudioPacket(); AkAudioPacket &operator =(const AkPacket &other); AkAudioPacket &operator =(const AkAudioPacket &other); + AkAudioPacket operator +(const AkAudioPacket &other); + AkAudioPacket& operator +=(const AkAudioPacket &other); operator bool() const; + operator AkPacket() const; Q_INVOKABLE AkAudioCaps caps() const; Q_INVOKABLE AkAudioCaps &caps(); - - Q_INVOKABLE QString toString() const; - Q_INVOKABLE AkPacket toPacket() const; + Q_INVOKABLE QByteArray buffer() const; + Q_INVOKABLE QByteArray &buffer(); + Q_INVOKABLE qint64 id() const; + Q_INVOKABLE qint64 &id(); + Q_INVOKABLE qint64 pts() const; + Q_INVOKABLE qint64 &pts(); + Q_INVOKABLE AkFrac timeBase() const; + Q_INVOKABLE AkFrac &timeBase(); + Q_INVOKABLE int index() const; + Q_INVOKABLE int &index(); + Q_INVOKABLE void copyMetadata(const AkAudioPacket &other); + + Q_INVOKABLE const quint8 *constPlaneData(int plane) const; + Q_INVOKABLE quint8 *planeData(int plane); + Q_INVOKABLE const quint8 *constSample(int channel, int i) const; + Q_INVOKABLE quint8 *sample(int channel, int i); + Q_INVOKABLE void setSample(int channel, int i, const quint8 *sample); + Q_INVOKABLE AkAudioPacket convert(const AkAudioCaps &caps) const; + Q_INVOKABLE static bool canConvertFormat(AkAudioCaps::SampleFormat input, + AkAudioCaps::SampleFormat output); + Q_INVOKABLE bool canConvertFormat(AkAudioCaps::SampleFormat output) const; + Q_INVOKABLE AkAudioPacket convertFormat(AkAudioCaps::SampleFormat format) const; + Q_INVOKABLE AkAudioPacket convertLayout(AkAudioCaps::ChannelLayout layout) const; + Q_INVOKABLE AkAudioPacket convertSampleRate(int rate, + qreal &sampleCorrection, + ResampleMethod method=ResampleMethod_Fast) const; + Q_INVOKABLE AkAudioPacket scale(int samples, + ResampleMethod method=ResampleMethod_Fast) const; + Q_INVOKABLE AkAudioPacket convertPlanar(bool planar) const; + Q_INVOKABLE AkAudioPacket realign(int align) const; + Q_INVOKABLE AkAudioPacket pop(int samples); private: AkAudioPacketPrivate *d; Q_SIGNALS: void capsChanged(const AkAudioCaps &caps); + void bufferChanged(const QByteArray &buffer); + void idChanged(qint64 id); + void ptsChanged(qint64 pts); + void timeBaseChanged(const AkFrac &timeBase); + void indexChanged(int index); public Q_SLOTS: void setCaps(const AkAudioCaps &caps); + void setBuffer(const QByteArray &buffer); + void setId(qint64 id); + void setPts(qint64 pts); + void setTimeBase(const AkFrac &timeBase); + void setIndex(int index); void resetCaps(); - - friend QDebug operator <<(QDebug debug, const AkAudioPacket &packet); + void resetBuffer(); + void resetId(); + void resetPts(); + void resetTimeBase(); + void resetIndex(); }; -QDebug operator <<(QDebug debug, const AkAudioPacket &packet); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, const AkAudioPacket &packet); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, AkAudioPacket::ResampleMethod method); Q_DECLARE_METATYPE(AkAudioPacket) +Q_DECLARE_METATYPE(AkAudioPacket::ResampleMethod) #endif // AKAUDIOPACKET_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akcaps.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akcaps.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akcaps.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akcaps.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -29,31 +28,19 @@ { public: QString m_mimeType; - bool m_isValid {false}; }; -AkCaps::AkCaps(QObject *parent): QObject(parent) +AkCaps::AkCaps(const QString &mimeType, QObject *parent): + QObject(parent) { this->d = new AkCapsPrivate(); -} - -AkCaps::AkCaps(const QVariantMap &caps) -{ - this->d = new AkCapsPrivate(); - this->fromMap(caps); -} - -AkCaps::AkCaps(const QString &caps) -{ - this->d = new AkCapsPrivate(); - this->fromString(caps); + this->d->m_mimeType = mimeType; } AkCaps::AkCaps(const AkCaps &other): QObject() { this->d = new AkCapsPrivate(); - this->d->m_isValid = other.d->m_isValid; this->d->m_mimeType = other.d->m_mimeType; this->update(other); } @@ -66,30 +53,24 @@ AkCaps &AkCaps::operator =(const AkCaps &other) { if (this != &other) { - this->clear(); - this->d->m_isValid = other.d->m_isValid; this->d->m_mimeType = other.d->m_mimeType; + this->clear(); this->update(other); } return *this; } -AkCaps &AkCaps::operator =(const QString &other) -{ - this->operator =(AkCaps(other)); - - return *this; -} - bool AkCaps::operator ==(const AkCaps &other) const { - return this->toString() == other.toString(); -} + if (this->dynamicPropertyNames() != other.dynamicPropertyNames()) + return false; -bool AkCaps::operator ==(const QString &caps) const -{ - return this->toString() == caps; + for (auto &property: this->dynamicPropertyNames()) + if (this->property(property) != other.property(property)) + return false; + + return this->d->m_mimeType == other.d->m_mimeType; } bool AkCaps::operator !=(const AkCaps &other) const @@ -97,24 +78,9 @@ return !(*this == other); } -bool AkCaps::operator !=(const QString &caps) const -{ - return !(*this == caps); -} - AkCaps::operator bool() const { - return this->d->m_isValid; -} - -bool AkCaps::isValid() const -{ - return this->d->m_isValid; -} - -bool &AkCaps::isValid() -{ - return this->d->m_isValid; + return !this->d->m_mimeType.isEmpty(); } QString AkCaps::mimeType() const @@ -122,96 +88,31 @@ return this->d->m_mimeType; } -AkCaps &AkCaps::fromMap(const QVariantMap &caps) +AkCaps AkCaps::fromMap(const QVariantMap &caps) { - QList properties = this->dynamicPropertyNames(); + AkCaps akCaps; - for (const QByteArray &property: properties) - this->setProperty(property, QVariant()); - - if (!caps.contains("mimeType")) { - this->d->m_isValid = false; - this->d->m_mimeType = ""; - - return *this; - } + if (!caps.contains("mimeType")) + return akCaps; for (auto it = caps.begin(); it != caps.end(); it++) - if (it.key() == "mimeType") { - this->d->m_isValid = QRegExp(R"(\s*[a-z]+/\w+(?:(?:-|\+|\.)\w+)*\s*)") - .exactMatch(it.value().toString()); - this->d->m_mimeType = it.value().toString().trimmed(); - } else - this->setProperty(it.key().trimmed().toStdString().c_str(), - it.value()); - - return *this; -} - -AkCaps &AkCaps::fromString(const QString &caps) -{ - this->d->m_isValid = QRegExp("\\s*[a-z]+/\\w+(?:(?:-|\\+|\\.)\\w+)*" - "(?:\\s*,\\s*[a-zA-Z_]\\w*\\s*=" - "\\s*[^,=]+)*\\s*").exactMatch(caps); + akCaps.setProperty(it.key().toStdString().c_str(), it.value()); - QList properties = this->dynamicPropertyNames(); - - for (const QByteArray &property: properties) - this->setProperty(property, QVariant()); - - QStringList capsChunks; - - if (this->d->m_isValid) - capsChunks = caps.split(QRegExp("\\s*,\\s*"), - QString::SkipEmptyParts); - - for (int i = 1; i < capsChunks.length(); i++) { - QStringList pair = capsChunks[i].split(QRegExp("\\s*=\\s*"), - QString::SkipEmptyParts); - - this->setProperty(pair[0].trimmed().toStdString().c_str(), - pair[1].trimmed()); - } - - this->setMimeType(this->d->m_isValid? capsChunks[0].trimmed(): QString("")); - - return *this; + return akCaps; } QVariantMap AkCaps::toMap() const { - if (!this->d->m_isValid) - return QVariantMap(); - - QVariantMap caps; - caps["mimeType"] = this->d->m_mimeType; + QVariantMap map { + {"mimeType", this->d->m_mimeType}, + }; for (auto &property: this->dynamicPropertyNames()) { auto key = QString::fromUtf8(property.constData()); - caps[key] = this->property(property.toStdString().c_str()); + map[key] = this->property(property); } - return caps; -} - -QString AkCaps::toString() const -{ - if (!this->d->m_isValid) - return QString(); - - QString caps = this->d->m_mimeType; - QStringList properties; - - for (auto &property: this->dynamicPropertyNames()) - properties << QString::fromUtf8(property.constData()); - - properties.sort(); - - for (auto &property: properties) - caps.append(QString(",%1=%2").arg(property, - this->property(property.toStdString().c_str()).toString())); - - return caps; + return map; } AkCaps &AkCaps::update(const AkCaps &other) @@ -246,8 +147,7 @@ void AkCaps::setMimeType(const QString &mimeType) { - this->d->m_isValid = QRegExp(R"(\s*[a-z]+/\w+(?:(?:-|\+|\.)\w+)*\s*)").exactMatch(mimeType); - QString _mimeType = this->d->m_isValid? mimeType.trimmed(): QString(""); + QString _mimeType = mimeType.trimmed(); if (this->d->m_mimeType == _mimeType) return; @@ -263,34 +163,65 @@ void AkCaps::clear() { - this->d->m_mimeType.clear(); - this->d->m_isValid = false; - - QList properties = this->dynamicPropertyNames(); - - for (const QByteArray &property: properties) + for (auto &property: this->dynamicPropertyNames()) this->setProperty(property.constData(), QVariant()); } QDebug operator <<(QDebug debug, const AkCaps &caps) { - debug.nospace() << caps.toString(); + debug.nospace() << "AkCaps(" + << "mimeType=" + << caps.mimeType(); + + QStringList properties; + + for (auto &property: caps.dynamicPropertyNames()) + properties << QString::fromUtf8(property.constData()); + + properties.sort(); + + for (auto &property: properties) + debug.nospace() << "," + << property.toStdString().c_str() + << "=" + << caps.property(property.toStdString().c_str()); + + debug.nospace() << ")"; return debug.space(); } QDataStream &operator >>(QDataStream &istream, AkCaps &caps) { - QString capsStr; - istream >> capsStr; - caps.fromString(capsStr); + int nProperties; + istream >> nProperties; + + for (int i = 0; i < nProperties; i++) { + QByteArray key; + QVariant value; + istream >> key; + istream >> value; + + caps.setProperty(key.toStdString().c_str(), value); + } return istream; } QDataStream &operator <<(QDataStream &ostream, const AkCaps &caps) { - ostream << caps.toString(); + QVariantMap staticProperties { + {"mimeType", caps.mimeType()}, + }; + + int nProperties = + staticProperties.size() + caps.dynamicPropertyNames().size(); + ostream << nProperties; + + for (auto &key: caps.dynamicPropertyNames()) { + ostream << key; + ostream << caps.property(key); + } return ostream; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akcaps.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akcaps.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akcaps.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akcaps.h 2021-02-15 15:25:23.000000000 +0000 @@ -31,8 +31,6 @@ { Q_OBJECT Q_ENUMS(CapsType) - Q_PROPERTY(bool isValid - READ isValid) Q_PROPERTY(QString mimeType READ mimeType WRITE setMimeType @@ -48,26 +46,17 @@ CapsSubtitle }; - AkCaps(QObject *parent=nullptr); - AkCaps(const QVariantMap &caps); - AkCaps(const QString &caps); + AkCaps(const QString &mimeType={}, QObject *parent=nullptr); AkCaps(const AkCaps &other); virtual ~AkCaps(); AkCaps &operator =(const AkCaps &other); - AkCaps &operator =(const QString &other); bool operator ==(const AkCaps &other) const; - bool operator ==(const QString &caps) const; bool operator !=(const AkCaps &other) const; - bool operator !=(const QString &caps) const; operator bool() const; - Q_INVOKABLE virtual bool isValid() const; - Q_INVOKABLE virtual bool &isValid(); Q_INVOKABLE virtual QString mimeType() const; - Q_INVOKABLE AkCaps &fromMap(const QVariantMap &caps); - Q_INVOKABLE AkCaps &fromString(const QString &caps); + Q_INVOKABLE static AkCaps fromMap(const QVariantMap &caps); Q_INVOKABLE QVariantMap toMap() const; - Q_INVOKABLE virtual QString toString() const; Q_INVOKABLE AkCaps &update(const AkCaps &other); Q_INVOKABLE bool isCompatible(const AkCaps &other) const; Q_INVOKABLE bool contains(const QString &property) const; @@ -82,15 +71,11 @@ virtual void setMimeType(const QString &mimeType); virtual void resetMimeType(); void clear(); - - friend QDebug operator <<(QDebug debug, const AkCaps &caps); - friend QDataStream &operator >>(QDataStream &istream, AkCaps &caps); - friend QDataStream &operator <<(QDataStream &ostream, const AkCaps &caps); }; -QDebug operator <<(QDebug debug, const AkCaps &caps); -QDataStream &operator >>(QDataStream &istream, AkCaps &caps); -QDataStream &operator <<(QDataStream &ostream, const AkCaps &caps); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, const AkCaps &caps); +AKCOMMONS_EXPORT QDataStream &operator >>(QDataStream &istream, AkCaps &caps); +AKCOMMONS_EXPORT QDataStream &operator <<(QDataStream &ostream, const AkCaps &caps); Q_DECLARE_METATYPE(AkCaps) Q_DECLARE_METATYPE(AkCaps::CapsType) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/ak.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/ak.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/ak.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/ak.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -30,9 +31,12 @@ #include "ak.h" #include "akcaps.h" #include "akelement.h" +#include "akfrac.h" #include "akaudiocaps.h" #include "akvideocaps.h" #include "akpacket.h" +#include "akaudiopacket.h" +#include "akvideopacket.h" class AkPrivate { @@ -129,6 +133,7 @@ { this->m_globalEngine = nullptr; + qRegisterMetaType("size_t"); qRegisterMetaType("QRgb"); qRegisterMetaType("QColor"); qRegisterMetaType("AkCaps"); @@ -139,20 +144,34 @@ qRegisterMetaTypeStreamOperators("AkAudioCaps"); qRegisterMetaType("AkAudioCaps::SampleFormat"); qRegisterMetaType("SampleFormat"); + QMetaType::registerDebugStreamOperator(); + qRegisterMetaType>("QList"); + qRegisterMetaType>("QList"); qRegisterMetaType("AkAudioCaps::SampleType"); qRegisterMetaType("SampleType"); + QMetaType::registerDebugStreamOperator(); + qRegisterMetaType("AkAudioCaps::Position"); + qRegisterMetaType("Position"); + QMetaType::registerDebugStreamOperator(); qRegisterMetaType("AkAudioCaps::ChannelLayout"); qRegisterMetaType("ChannelLayout"); + QMetaType::registerDebugStreamOperator(); + qRegisterMetaType>("QList"); + qRegisterMetaType>("QList"); qRegisterMetaType("AkVideoCaps"); qRegisterMetaTypeStreamOperators("AkVideoCaps"); qRegisterMetaType("AkVideoCaps::PixelFormat"); qRegisterMetaType("PixelFormat"); + QMetaType::registerDebugStreamOperator(); qRegisterMetaType("AkElement::ElementState"); qRegisterMetaType("ElementState"); qRegisterMetaTypeStreamOperators("AkElement::ElementState"); qRegisterMetaType("AkFrac"); qRegisterMetaTypeStreamOperators("AkFrac"); + QMetaType::registerDebugStreamOperator(); qRegisterMetaType("AkPacket"); + qRegisterMetaType("AkAudioPacket"); + qRegisterMetaType("AkVideoPacket"); qRegisterMetaType("AkElementPtr"); this->m_applicationDir.setPath(QCoreApplication::applicationDirPath()); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -53,8 +53,6 @@ class AkElementPrivate { public: - QString m_pluginId; - QString m_pluginPath; QString m_pluginFilePattern; QStringList m_pluginsSearchPaths; QStringList m_defaultPluginsSearchPaths; @@ -95,7 +93,10 @@ QString AkElement::pluginId() const { - return this->d->m_pluginId; + QString className(this->metaObject()->className()); + className.remove(QRegExp("Element$")); + + return className; } QString AkElement::pluginId(const QString &path) @@ -105,7 +106,7 @@ QString AkElement::pluginPath() const { - return this->d->m_pluginPath; + return AkElement::pluginPath(this->pluginId()); } AkElement::ElementState AkElement::state() const @@ -246,20 +247,14 @@ } AkElementPtr AkElement::create(const QString &pluginId, - const QString &elementName) + const QString &pluginSub) { - auto element = AkElement::createPtr(pluginId, elementName); - - if (!element) - return AkElementPtr(); - - return AkElementPtr(element); + return AkElement::create(pluginId, pluginSub); } -AkElement *AkElement::createPtr(const QString &pluginId, - const QString &elementName) +QObject *AkElement::createPtr(const QString &pluginId, const QString &pluginSub) { - QString filePath = AkElement::pluginPath(pluginId); + auto filePath = AkElement::pluginPath(pluginId); if (filePath.isEmpty()) return nullptr; @@ -280,21 +275,12 @@ if (!plugin) return nullptr; - auto element = - qobject_cast(plugin->create(AK_PLUGIN_TYPE_ELEMENT, - "")); + auto object = plugin->create(pluginSub.isEmpty()? + AK_PLUGIN_TYPE_ELEMENT: pluginSub, + ""); delete plugin; - if (!element) - return nullptr; - - if (!elementName.isEmpty()) - element->setObjectName(elementName); - - element->d->m_pluginId = pluginId; - element->d->m_pluginPath = filePath; - - return element; + return object; } QStringList AkElement::listSubModules(const QString &pluginId, @@ -327,11 +313,11 @@ { QString pluginId; - if (this->d->m_pluginId.isEmpty()) { + if (this->pluginId().isEmpty()) { pluginId = this->metaObject()->className(); - pluginId.replace(QRegExp("Element$"), ""); + pluginId.remove(QRegExp("Element$")); } else { - pluginId = this->d->m_pluginId; + pluginId = this->pluginId(); } if (types.isEmpty()) @@ -397,11 +383,11 @@ { QString pluginId; - if (this->d->m_pluginId.isEmpty()) { + if (this->pluginId().isEmpty()) { pluginId = this->metaObject()->className(); - pluginId.replace(QRegExp("Element$"), ""); + pluginId.remove(QRegExp("Element$")); } else { - pluginId = this->d->m_pluginId; + pluginId = this->pluginId(); } return AkElement::listSubModulesPaths(pluginId); @@ -445,11 +431,11 @@ { QString pluginId; - if (this->d->m_pluginId.isEmpty()) { + if (this->pluginId().isEmpty()) { pluginId = this->metaObject()->className(); - pluginId.replace(QRegExp("Element$"), ""); + pluginId.remove(QRegExp("Element$")); } else { - pluginId = this->d->m_pluginId; + pluginId = this->pluginId(); } return AkElement::loadSubModule(pluginId, subModule); @@ -662,16 +648,6 @@ return this->iStream(packet); } -AkPacket AkElement::operator ()(const AkAudioPacket &packet) -{ - return this->iStream(packet); -} - -AkPacket AkElement::operator ()(const AkVideoPacket &packet) -{ - return this->iStream(packet); -} - QString AkElement::controlInterfaceProvide(const QString &controlId) const { Q_UNUSED(controlId) @@ -692,27 +668,27 @@ Q_UNUSED(to) } -AkPacket AkElement::iStream(const AkPacket &packet) +AkPacket AkElement::iAudioStream(const AkAudioPacket &packet) { - if (packet.caps().mimeType() == "audio/x-raw") - return this->iStream(AkAudioPacket(packet)); - - if (packet.caps().mimeType() == "video/x-raw") - return this->iStream(AkVideoPacket(packet)); + Q_UNUSED(packet) return AkPacket(); } -AkPacket AkElement::iStream(const AkAudioPacket &packet) +AkPacket AkElement::iVideoStream(const AkVideoPacket &packet) { Q_UNUSED(packet) return AkPacket(); } -AkPacket AkElement::iStream(const AkVideoPacket &packet) +AkPacket AkElement::iStream(const AkPacket &packet) { - Q_UNUSED(packet) + if (packet.caps().mimeType() == "audio/x-raw") + return this->iAudioStream(packet); + + if (packet.caps().mimeType() == "video/x-raw") + return this->iVideoStream(packet); return AkPacket(); } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akelement.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -40,7 +40,7 @@ class QQmlEngine; class QQmlContext; -typedef QSharedPointer AkElementPtr; +using AkElementPtr = QSharedPointer; /// Plugin template. class AKCOMMONS_EXPORT AkElement: public QObject @@ -68,7 +68,7 @@ AkElement(QObject *parent=nullptr); virtual ~AkElement(); - Q_INVOKABLE QString pluginId() const; + Q_INVOKABLE virtual QString pluginId() const; Q_INVOKABLE static QString pluginId(const QString &path); Q_INVOKABLE QString pluginPath() const; Q_INVOKABLE virtual AkElement::ElementState state() const; @@ -99,12 +99,23 @@ const AkElementPtr &dstElement); Q_INVOKABLE static bool unlink(const QObject *srcElement, const QObject *dstElement); + template + static inline QSharedPointer create(const QString &pluginId, + const QString &pluginSub={}) + { + auto object = AkElement::createPtr(pluginId, pluginSub); + + if (!object) + return {}; + + return QSharedPointer(reinterpret_cast(object)); + } Q_INVOKABLE static AkElementPtr create(const QString &pluginId, - const QString &elementName=""); - Q_INVOKABLE static AkElement *createPtr(const QString &pluginId, - const QString &elementName=""); + const QString &pluginSub={}); + Q_INVOKABLE static QObject *createPtr(const QString &pluginId, + const QString &pluginSub={}); Q_INVOKABLE static QStringList listSubModules(const QString &pluginId, - const QString &type=""); + const QString &type={}); Q_INVOKABLE QStringList listSubModules(const QStringList &types={}); Q_INVOKABLE static QStringList listSubModulesPaths(const QString &pluginId); Q_INVOKABLE QStringList listSubModulesPaths(); @@ -133,8 +144,6 @@ Q_INVOKABLE static void clearCache(); virtual AkPacket operator ()(const AkPacket &packet); - virtual AkPacket operator ()(const AkAudioPacket &packet); - virtual AkPacket operator ()(const AkVideoPacket &packet); private: AkElementPrivate *d; @@ -144,6 +153,8 @@ virtual void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; virtual void stateChange(AkElement::ElementState from, AkElement::ElementState to); + virtual AkPacket iAudioStream(const AkAudioPacket &packet); + virtual AkPacket iVideoStream(const AkVideoPacket &packet); Q_SIGNALS: void stateChanged(AkElement::ElementState state); @@ -151,14 +162,13 @@ public Q_SLOTS: virtual AkPacket iStream(const AkPacket &packet); - virtual AkPacket iStream(const AkAudioPacket &packet); - virtual AkPacket iStream(const AkVideoPacket &packet); virtual bool setState(AkElement::ElementState state); virtual void resetState(); }; -QDataStream &operator >>(QDataStream &istream, AkElement::ElementState &state); -QDataStream &operator <<(QDataStream &ostream, AkElement::ElementState state); +AKCOMMONS_EXPORT QDataStream &operator >>(QDataStream &istream, AkElement::ElementState &state); +AKCOMMONS_EXPORT QDataStream &operator <<(QDataStream &ostream, AkElement::ElementState state); + Q_DECLARE_METATYPE(AkElement::ElementState) #endif // AKELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akfrac.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akfrac.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akfrac.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akfrac.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -24,38 +24,16 @@ #include "akfrac.h" -#define SIGN(n) (((n) < 0)? -1: 1) - class AkFracPrivate { public: qint64 m_num; qint64 m_den; - bool m_isValid; - - static inline qint64 gcd(qint64 num, qint64 den) - { - num = qAbs(num); - den = qAbs(den); - - while (num > 0) { - qint64 tmp = num; - num = den % num; - den = tmp; - } - return den; - } - - static inline void reduce(qint64 *num, qint64 *den) - { - qint64 gcd = AkFracPrivate::gcd(*num, *den); - - if (gcd) { - *num /= gcd; - *den /= gcd; - } - } + template + inline static T sign(T n); + inline static qint64 gcd(qint64 num, qint64 den); + inline static void reduce(qint64 *num, qint64 *den); }; AkFrac::AkFrac(QObject *parent): @@ -64,7 +42,6 @@ this->d = new AkFracPrivate(); this->d->m_num = 0; this->d->m_den = 0; - this->d->m_isValid = false; } AkFrac::AkFrac(qint64 num, qint64 den): @@ -73,7 +50,6 @@ this->d = new AkFracPrivate(); this->d->m_num = 0; this->d->m_den = 0; - this->d->m_isValid = false; this->setNumDen(num, den); } @@ -84,7 +60,6 @@ this->d = new AkFracPrivate(); this->d->m_num = 0; this->d->m_den = 0; - this->d->m_isValid = false; this->setNumDen(fracString); } @@ -95,7 +70,6 @@ this->d = new AkFracPrivate(); this->d->m_num = other.d->m_num; this->d->m_den = other.d->m_den; - this->d->m_isValid = other.d->m_isValid; } AkFrac::~AkFrac() @@ -108,7 +82,6 @@ if (this != &other) { this->d->m_num = other.d->m_num; this->d->m_den = other.d->m_den; - this->d->m_isValid = other.d->m_isValid; } return *this; @@ -136,6 +109,16 @@ this->d->m_den * other.d->m_den); } +AkFrac::operator bool() const +{ + return this->d->m_den != 0; +} + +AkFrac::operator QString() const +{ + return QString("%1/%2").arg(this->d->m_num).arg(this->d->m_den); +} + qint64 AkFrac::num() const { return this->d->m_num; @@ -148,22 +131,28 @@ qreal AkFrac::value() const { - return this->d->m_num / qreal(this->d->m_den); + if (!this->d->m_den) + return qQNaN(); + + return qreal(this->d->m_num) / this->d->m_den; } qint64 AkFrac::fastValue() const { + if (!this->d->m_den) + return 0; + return this->d->m_num / this->d->m_den; } bool AkFrac::isValid() const { - return this->d->m_isValid; + return *this; } QString AkFrac::toString() const { - return QString("%1/%2").arg(this->d->m_num).arg(this->d->m_den); + return *this; } AkFrac AkFrac::invert() const @@ -179,60 +168,46 @@ if (this->d->m_num != 0) { this->d->m_num = 0; changed = true; - - emit this->numChanged(); + emit this->numChanged(0); } if (this->d->m_den != 0) { this->d->m_den = 0; changed = true; - - emit this->denChanged(); - } - - if (this->d->m_isValid) { - this->d->m_isValid = false; - changed = true; - - emit this->isValidChanged(); + emit this->denChanged(0); + emit this->isValidChanged(false); } if (changed) { - emit this->valueChanged(); - emit this->stringChanged(); + emit this->valueChanged(qQNaN()); + emit this->stringChanged("0/0"); } return; } - num = SIGN(den) * num; + num = AkFracPrivate::sign(den) * num; den = qAbs(den); AkFracPrivate::reduce(&num, &den); if (this->d->m_num != num) { this->d->m_num = num; changed = true; - - emit this->numChanged(); + emit this->numChanged(num); } if (this->d->m_den != den) { - this->d->m_den = den; - changed = true; - - emit this->denChanged(); - } + if (!this->d->m_den) + emit this->isValidChanged(true); - if (!this->d->m_isValid) { - this->d->m_isValid = true; + this->d->m_den = den; changed = true; - - emit this->isValidChanged(); + emit this->denChanged(den); } if (changed) { - emit this->valueChanged(); - emit this->stringChanged(); + emit this->valueChanged(this->value()); + emit this->stringChanged(*this); } } @@ -293,32 +268,38 @@ QDebug operator <<(QDebug debug, const AkFrac &frac) { - debug.nospace() << frac.toString(); + debug.nospace() << "AkFrac(" + << frac.num() + << "," + << frac.den() + << ")"; return debug.space(); } QDataStream &operator >>(QDataStream &istream, AkFrac &frac) { - istream >> frac.d->m_num; - istream >> frac.d->m_den; - istream >> frac.d->m_isValid; + qint64 num; + qint64 den; + istream >> num; + istream >> den; + frac.setNum(num); + frac.setDen(den); return istream; } QDataStream &operator <<(QDataStream &ostream, const AkFrac &frac) { - ostream << frac.d->m_num; - ostream << frac.d->m_den; - ostream << frac.d->m_isValid; + ostream << frac.num(); + ostream << frac.den(); return ostream; } AkFrac operator *(int number, const AkFrac &frac) { - return AkFrac(number * frac.d->m_num, frac.d->m_den); + return {number * frac.num(), frac.den()}; } AkFrac operator /(int number, const AkFrac &frac) @@ -326,25 +307,52 @@ return number * frac.invert(); } - AkFrac operator /(const AkFrac &fracNum, const AkFrac &fracDen) { - return AkFrac(fracNum.d->m_num * fracDen.d->m_den, - fracNum.d->m_den * fracDen.d->m_num); + return {fracNum.num() * fracDen.den(), + fracNum.den() * fracDen.num()}; } AkFrac operator +(const AkFrac &frac1, const AkFrac &frac2) { - return AkFrac(frac1.d->m_num * frac2.d->m_den - + frac2.d->m_num * frac1.d->m_den, - frac1.d->m_den * frac2.d->m_den); + return {frac1.num() * frac2.den() + frac2.num() * frac1.den(), + frac1.den() * frac2.den()}; } AkFrac operator -(const AkFrac &frac1, const AkFrac &frac2) { - return AkFrac(frac1.d->m_num * frac2.d->m_den - - frac2.d->m_num * frac1.d->m_den, - frac1.d->m_den * frac2.d->m_den); + return {frac1.num() * frac2.den() - frac2.num() * frac1.den(), + frac1.den() * frac2.den()}; +} + +template +T AkFracPrivate::sign(T n) +{ + return (n < 0)? -1: 1; +} + +qint64 AkFracPrivate::gcd(qint64 num, qint64 den) +{ + num = qAbs(num); + den = qAbs(den); + + while (num > 0) { + qint64 tmp = num; + num = den % num; + den = tmp; + } + + return den; +} + +void AkFracPrivate::reduce(qint64 *num, qint64 *den) +{ + qint64 gcd = AkFracPrivate::gcd(*num, *den); + + if (gcd) { + *num /= gcd; + *den /= gcd; + } } #include "moc_akfrac.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akfrac.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akfrac.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akfrac.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akfrac.h 2021-02-15 15:25:23.000000000 +0000 @@ -30,12 +30,12 @@ class AKCOMMONS_EXPORT AkFrac: public QObject { Q_OBJECT - Q_PROPERTY(int num + Q_PROPERTY(qint64 num READ num WRITE setNum RESET resetNum NOTIFY numChanged) - Q_PROPERTY(int den + Q_PROPERTY(qint64 den READ den WRITE setDen RESET resetDen @@ -60,6 +60,8 @@ bool operator ==(const AkFrac &other) const; bool operator !=(const AkFrac &other) const; AkFrac operator *(const AkFrac &other) const; + operator bool() const; + operator QString() const; Q_INVOKABLE qint64 num() const; Q_INVOKABLE qint64 den() const; @@ -73,11 +75,11 @@ AkFracPrivate *d; Q_SIGNALS: - void numChanged(); - void denChanged(); - void isValidChanged(); - void valueChanged(); - void stringChanged(); + void numChanged(qint64 num); + void denChanged(qint64 den); + void isValidChanged(bool valid); + void valueChanged(qreal value); + void stringChanged(const QString &string); public Q_SLOTS: void setNumDen(qint64 num, qint64 den); @@ -86,24 +88,16 @@ void setDen(qint64 den); void resetNum(); void resetDen(); - - friend QDebug operator <<(QDebug debug, const AkFrac &frac); - friend QDataStream &operator >>(QDataStream &istream, AkFrac &frac); - friend QDataStream &operator <<(QDataStream &ostream, const AkFrac &frac); - friend AkFrac operator *(int number, const AkFrac &frac); - friend AkFrac operator /(const AkFrac &fracNum, const AkFrac &fracDen); - friend AkFrac operator +(const AkFrac &frac1, const AkFrac &frac2); - friend AkFrac operator -(const AkFrac &frac1, const AkFrac &frac2); }; -QDebug operator <<(QDebug debug, const AkFrac &frac); -QDataStream &operator >>(QDataStream &istream, AkFrac &frac); -QDataStream &operator <<(QDataStream &ostream, const AkFrac &frac); -AkFrac operator *(int number, const AkFrac &frac); -AkFrac operator /(int number, const AkFrac &frac); -AkFrac operator /(const AkFrac &fracNum, const AkFrac &fracDen); -AkFrac operator +(const AkFrac &frac1, const AkFrac &frac2); -AkFrac operator -(const AkFrac &frac1, const AkFrac &frac2); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, const AkFrac &frac); +AKCOMMONS_EXPORT QDataStream &operator >>(QDataStream &istream, AkFrac &frac); +AKCOMMONS_EXPORT QDataStream &operator <<(QDataStream &ostream, const AkFrac &frac); +AKCOMMONS_EXPORT AkFrac operator *(int number, const AkFrac &frac); +AKCOMMONS_EXPORT AkFrac operator /(int number, const AkFrac &frac); +AKCOMMONS_EXPORT AkFrac operator /(const AkFrac &fracNum, const AkFrac &fracDen); +AKCOMMONS_EXPORT AkFrac operator +(const AkFrac &frac1, const AkFrac &frac2); +AKCOMMONS_EXPORT AkFrac operator -(const AkFrac &frac1, const AkFrac &frac2); Q_DECLARE_METATYPE(AkFrac) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akmultimediasourceelement.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akmultimediasourceelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akmultimediasourceelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akmultimediasourceelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -26,7 +26,7 @@ class AkMultimediaSourceElementPrivate; class AkCaps; -typedef QSharedPointer AkMultimediaSourceElementPtr; +using AkMultimediaSourceElementPtr = QSharedPointer; class AKCOMMONS_EXPORT AkMultimediaSourceElement: public AkElement { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akpacket.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akpacket.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akpacket.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akpacket.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -22,17 +22,17 @@ #include "akpacket.h" #include "akcaps.h" +#include "akfrac.h" class AkPacketPrivate { public: AkCaps m_caps; - QVariant m_data; QByteArray m_buffer; qint64 m_pts {0}; AkFrac m_timeBase; - int m_index {-1}; qint64 m_id {-1}; + int m_index {-1}; }; AkPacket::AkPacket(QObject *parent): @@ -41,21 +41,10 @@ this->d = new AkPacketPrivate(); } -AkPacket::AkPacket(const AkCaps &caps, - const QByteArray &buffer, - qint64 pts, - const AkFrac &timeBase, - int index, - qint64 id) +AkPacket::AkPacket(const AkCaps &caps) { this->d = new AkPacketPrivate(); this->d->m_caps = caps; - bool isValid = this->d->m_caps.isValid(); - this->d->m_buffer = isValid? buffer: QByteArray(); - this->d->m_pts = isValid? pts: 0; - this->d->m_timeBase = isValid? timeBase: AkFrac(); - this->d->m_index = isValid? index: -1; - this->d->m_id = isValid? id: -1; } AkPacket::AkPacket(const AkPacket &other): @@ -63,7 +52,6 @@ { this->d = new AkPacketPrivate(); this->d->m_caps = other.d->m_caps; - this->d->m_data = other.d->m_data; this->d->m_buffer = other.d->m_buffer; this->d->m_pts = other.d->m_pts; this->d->m_timeBase = other.d->m_timeBase; @@ -80,7 +68,6 @@ { if (this != &other) { this->d->m_caps = other.d->m_caps; - this->d->m_data = other.d->m_data; this->d->m_buffer = other.d->m_buffer; this->d->m_pts = other.d->m_pts; this->d->m_timeBase = other.d->m_timeBase; @@ -93,44 +80,7 @@ AkPacket::operator bool() const { - return this->d->m_caps.isValid(); -} - -QString AkPacket::toString() const -{ - QString packetInfo; - QDebug debug(&packetInfo); - - debug.nospace() << "Caps : " - << this->d->m_caps.toString().toStdString().c_str() - << "\n"; - - debug.nospace() << "Data : " - << this->d->m_data - << "\n"; - - debug.nospace() << "Buffer Size: " - << this->d->m_buffer.size() - << "\n"; - - debug.nospace() << "Id : " - << this->d->m_id - << "\n"; - - debug.nospace() << "Pts : " - << this->d->m_pts - << " (" - << this->d->m_pts * this->d->m_timeBase.value() - << ")\n"; - - debug.nospace() << "Time Base : " - << this->d->m_timeBase.toString().toStdString().c_str() - << "\n"; - - debug.nospace() << "Index : " - << this->d->m_index; - - return packetInfo; + return this->d->m_caps && !this->d->m_buffer.isEmpty(); } AkCaps AkPacket::caps() const @@ -143,16 +93,6 @@ return this->d->m_caps; } -QVariant AkPacket::data() const -{ - return this->d->m_data; -} - -QVariant &AkPacket::data() -{ - return this->d->m_data; -} - QByteArray AkPacket::buffer() const { return this->d->m_buffer; @@ -203,6 +143,14 @@ return this->d->m_index; } +void AkPacket::copyMetadata(const AkPacket &other) +{ + this->d->m_pts = other.d->m_pts; + this->d->m_timeBase = other.d->m_timeBase; + this->d->m_index = other.d->m_index; + this->d->m_id = other.d->m_id; +} + void AkPacket::setCaps(const AkCaps &caps) { if (this->d->m_caps == caps) @@ -212,15 +160,6 @@ emit this->capsChanged(caps); } -void AkPacket::setData(const QVariant &data) -{ - if (this->d->m_data == data) - return; - - this->d->m_data = data; - emit this->dataChanged(data); -} - void AkPacket::setBuffer(const QByteArray &buffer) { if (this->d->m_buffer == buffer) @@ -271,14 +210,9 @@ this->setCaps(AkCaps()); } -void AkPacket::resetData() -{ - this->setData(QVariant()); -} - void AkPacket::resetBuffer() { - this->setBuffer(QByteArray()); + this->setBuffer({}); } void AkPacket::resetId() @@ -293,7 +227,7 @@ void AkPacket::resetTimeBase() { - this->setTimeBase(AkFrac()); + this->setTimeBase({}); } void AkPacket::resetIndex() @@ -303,7 +237,23 @@ QDebug operator <<(QDebug debug, const AkPacket &packet) { - debug.nospace() << packet.toString().toStdString().c_str(); + debug.nospace() << "AkPacket(" + << "caps=" + << packet.caps() + << ",bufferSize=" + << packet.buffer().size() + << ",id=" + << packet.id() + << ",pts=" + << packet.pts() + << "(" + << packet.pts() * packet.timeBase().value() + << ")" + << ",timeBase=" + << packet.timeBase() + << ",index=" + << packet.index() + << ")"; return debug.space(); } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akpacket.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akpacket.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akpacket.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akpacket.h 2021-02-15 15:25:23.000000000 +0000 @@ -20,10 +20,13 @@ #ifndef AKPACKET_H #define AKPACKET_H -#include "akfrac.h" +#include + +#include "akcommons.h" class AkPacketPrivate; class AkCaps; +class AkFrac; template inline T AkNoPts() @@ -39,11 +42,6 @@ WRITE setCaps RESET resetCaps NOTIFY capsChanged) - Q_PROPERTY(QVariant data - READ data - WRITE setData - RESET resetData - NOTIFY dataChanged) Q_PROPERTY(QByteArray buffer READ buffer WRITE setBuffer @@ -72,22 +70,14 @@ public: AkPacket(QObject *parent=nullptr); - AkPacket(const AkCaps &caps, - const QByteArray &buffer=QByteArray(), - qint64 pts=0, - const AkFrac &timeBase=AkFrac(), - int index=-1, - qint64 id=-1); + AkPacket(const AkCaps &caps); AkPacket(const AkPacket &other); virtual ~AkPacket(); AkPacket &operator =(const AkPacket &other); operator bool() const; - Q_INVOKABLE QString toString() const; Q_INVOKABLE AkCaps caps() const; Q_INVOKABLE AkCaps &caps(); - Q_INVOKABLE QVariant data() const; - Q_INVOKABLE QVariant &data(); Q_INVOKABLE QByteArray buffer() const; Q_INVOKABLE QByteArray &buffer(); Q_INVOKABLE qint64 id() const; @@ -98,13 +88,13 @@ Q_INVOKABLE AkFrac &timeBase(); Q_INVOKABLE int index() const; Q_INVOKABLE int &index(); + Q_INVOKABLE void copyMetadata(const AkPacket &other); private: AkPacketPrivate *d; Q_SIGNALS: void capsChanged(const AkCaps &caps); - void dataChanged(const QVariant &data); void bufferChanged(const QByteArray &buffer); void idChanged(qint64 id); void ptsChanged(qint64 pts); @@ -113,24 +103,20 @@ public Q_SLOTS: void setCaps(const AkCaps &caps); - void setData(const QVariant &data); void setBuffer(const QByteArray &buffer); void setId(qint64 id); void setPts(qint64 pts); void setTimeBase(const AkFrac &timeBase); void setIndex(int index); void resetCaps(); - void resetData(); void resetBuffer(); void resetId(); void resetPts(); void resetTimeBase(); void resetIndex(); - - friend QDebug operator <<(QDebug debug, const AkPacket &packet); }; -QDebug operator <<(QDebug debug, const AkPacket &packet); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, const AkPacket &packet); Q_DECLARE_METATYPE(AkPacket) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akplugin.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akplugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akplugin.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akplugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -24,8 +24,9 @@ #include "akcommons.h" -#define AK_PLUGIN_TYPE_ELEMENT "Ak.Element" -#define AK_PLUGIN_TYPE_SUBMODULE "Ak.SubModule" +#define AK_PLUGIN_TYPE_ELEMENT "Ak.Element" +#define AK_PLUGIN_TYPE_ELEMENT_SETTINGS "Ak.Element.Settings" +#define AK_PLUGIN_TYPE_SUBMODULE "Ak.SubModule" class AKCOMMONS_EXPORT AkPlugin { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akvideocaps.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akvideocaps.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akvideocaps.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akvideocaps.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -33,179 +33,205 @@ AkVideoCaps::PixelFormat format; int bpp; quint32 fourCC; + QVector planes; + QVector planes_div; static inline const QVector &formats() { static const QVector videoFormats = { - {AkVideoCaps::Format_none, 0, AK_FOURCC_NULL}, - {AkVideoCaps::Format_yuv420p, 12, AkFourCC('I', '4', '2', '0')}, - {AkVideoCaps::Format_yuyv422, 16, AkFourCC('Y', 'U', 'Y', '2')}, - {AkVideoCaps::Format_rgb24, 24, AkFourCC('R', 'G', 'B', 24)}, - {AkVideoCaps::Format_bgr24, 24, AkFourCC('B', 'G', 'R', 24)}, - {AkVideoCaps::Format_yuv422p, 16, AkFourCC('Y', '4', '2', 'B')}, - {AkVideoCaps::Format_yuv444p, 24, AkFourCC('4', '4', '4', 'P')}, - {AkVideoCaps::Format_yuv410p, 9, AkFourCC('Y', 'U', 'V', '9')}, - {AkVideoCaps::Format_yuv411p, 12, AkFourCC('Y', '4', '1', 'B')}, - {AkVideoCaps::Format_gray, 8, AkFourCC('Y', '8', '0', '0')}, - {AkVideoCaps::Format_monow, 1, AkFourCC('B', '1', 'W', '0')}, - {AkVideoCaps::Format_monob, 1, AkFourCC('B', '0', 'W', '1')}, - {AkVideoCaps::Format_pal8, 8, AkFourCC('P', 'A', 'L', 8)}, - {AkVideoCaps::Format_yuvj420p, 12, AkFourCC('I', '4', '2', '0')}, - {AkVideoCaps::Format_yuvj422p, 16, AkFourCC('Y', '4', '2', 'B')}, - {AkVideoCaps::Format_yuvj444p, 24, AkFourCC('4', '4', '4', 'P')}, - {AkVideoCaps::Format_uyvy422, 16, AkFourCC('U', 'Y', 'V', 'Y')}, - {AkVideoCaps::Format_uyyvyy411, 12, AkFourCC('Y', '4', '1', '1')}, - {AkVideoCaps::Format_bgr8, 8, AkFourCC('B', 'G', 'R', 8)}, - {AkVideoCaps::Format_bgr4, 4, AkFourCC('B', 'G', 'R', 4)}, - {AkVideoCaps::Format_bgr4_byte, 4, AkFourCC('R', '4', 'B', 'Y')}, - {AkVideoCaps::Format_rgb8, 8, AkFourCC('R', 'G', 'B', 8)}, - {AkVideoCaps::Format_rgb4, 4, AkFourCC('R', 'G', 'B', 4)}, - {AkVideoCaps::Format_rgb4_byte, 4, AkFourCC('B', '4', 'B', 'Y')}, - {AkVideoCaps::Format_nv12, 12, AkFourCC('N', 'V', '1', '2')}, - {AkVideoCaps::Format_nv21, 12, AkFourCC('N', 'V', '2', '1')}, - {AkVideoCaps::Format_argb, 32, AkFourCC('A', 'R', 'G', 'B')}, - {AkVideoCaps::Format_rgba, 32, AkFourCC('R', 'G', 'B', 'A')}, - {AkVideoCaps::Format_abgr, 32, AkFourCC('A', 'B', 'G', 'R')}, - {AkVideoCaps::Format_bgra, 32, AkFourCC('B', 'G', 'R', 'A')}, - {AkVideoCaps::Format_gray16be, 16, AkFourCC(16, 0, '1', 'Y')}, - {AkVideoCaps::Format_gray16le, 16, AkFourCC('Y', '1', 0, 16)}, - {AkVideoCaps::Format_yuv440p, 16, AkFourCC('4', '4', '0', 'P')}, - {AkVideoCaps::Format_yuvj440p, 16, AkFourCC('4', '4', '0', 'P')}, - {AkVideoCaps::Format_yuva420p, 20, AkFourCC('Y', '4', 11, 8)}, - {AkVideoCaps::Format_rgb48be, 48, AkFourCC('0', 'R', 'G', 'B')}, - {AkVideoCaps::Format_rgb48le, 48, AkFourCC('R', 'G', 'B', '0')}, - {AkVideoCaps::Format_rgb565be, 16, AkFourCC(16, 'B', 'G', 'R')}, - {AkVideoCaps::Format_rgb565le, 16, AkFourCC('R', 'G', 'B', 16)}, - {AkVideoCaps::Format_rgb555be, 15, AkFourCC(15, 'B', 'G', 'R')}, - {AkVideoCaps::Format_rgb555le, 15, AkFourCC('R', 'G', 'B', 15)}, - {AkVideoCaps::Format_bgr565be, 16, AkFourCC(16, 'R', 'G', 'B')}, - {AkVideoCaps::Format_bgr565le, 16, AkFourCC('B', 'G', 'R', 16)}, - {AkVideoCaps::Format_bgr555be, 15, AkFourCC(15, 'R', 'G', 'B')}, - {AkVideoCaps::Format_bgr555le, 15, AkFourCC('B', 'G', 'R', 15)}, - {AkVideoCaps::Format_yuv420p16le, 24, AkFourCC('Y', '3', 11, 16)}, - {AkVideoCaps::Format_yuv420p16be, 24, AkFourCC(16, 11, '3', 'Y')}, - {AkVideoCaps::Format_yuv422p16le, 32, AkFourCC('Y', '3', 10, 16)}, - {AkVideoCaps::Format_yuv422p16be, 32, AkFourCC(16, 10, '3', 'Y')}, - {AkVideoCaps::Format_yuv444p16le, 48, AkFourCC('Y', '3', 0, 16)}, - {AkVideoCaps::Format_yuv444p16be, 48, AkFourCC(16, 0, '3', 'Y')}, - {AkVideoCaps::Format_rgb444le, 12, AkFourCC('R', 'G', 'B', 12)}, - {AkVideoCaps::Format_rgb444be, 12, AkFourCC(12, 'B', 'G', 'R')}, - {AkVideoCaps::Format_bgr444le, 12, AkFourCC('B', 'G', 'R', 12)}, - {AkVideoCaps::Format_bgr444be, 12, AkFourCC(12, 'R', 'G', 'B')}, - {AkVideoCaps::Format_ya8, 16, AkFourCC('Y', '2', 0, 8)}, - {AkVideoCaps::Format_bgr48be, 48, AkFourCC('0', 'B', 'G', 'R')}, - {AkVideoCaps::Format_bgr48le, 48, AkFourCC('B', 'G', 'R', '0')}, - {AkVideoCaps::Format_yuv420p9be, 13, AkFourCC(9, 11, '3', 'Y')}, - {AkVideoCaps::Format_yuv420p9le, 13, AkFourCC('Y', '3', 11, 9)}, - {AkVideoCaps::Format_yuv420p10be, 15, AkFourCC(10, 11, '3', 'Y')}, - {AkVideoCaps::Format_yuv420p10le, 15, AkFourCC('Y', '3', 11, 10)}, - {AkVideoCaps::Format_yuv422p10be, 20, AkFourCC(10, 10, '3', 'Y')}, - {AkVideoCaps::Format_yuv422p10le, 20, AkFourCC('Y', '3', 10, 10)}, - {AkVideoCaps::Format_yuv444p9be, 27, AkFourCC(9, 0, '3', 'Y')}, - {AkVideoCaps::Format_yuv444p9le, 27, AkFourCC('Y', '3', 0, 9)}, - {AkVideoCaps::Format_yuv444p10be, 30, AkFourCC(10, 0, '3', 'Y')}, - {AkVideoCaps::Format_yuv444p10le, 30, AkFourCC('Y', '3', 0, 10)}, - {AkVideoCaps::Format_yuv422p9be, 18, AkFourCC(9, 10, '3', 'Y')}, - {AkVideoCaps::Format_yuv422p9le, 18, AkFourCC('Y', '3', 10, 9)}, - {AkVideoCaps::Format_gbrp, 24, AkFourCC('G', '3', 0, 8)}, - {AkVideoCaps::Format_gbrp9be, 27, AkFourCC(9, 0, '3', 'G')}, - {AkVideoCaps::Format_gbrp9le, 27, AkFourCC('G', '3', 0, 9)}, - {AkVideoCaps::Format_gbrp10be, 30, AkFourCC(10, 0, '3', 'G')}, - {AkVideoCaps::Format_gbrp10le, 30, AkFourCC('G', '3', 0, 10)}, - {AkVideoCaps::Format_gbrp16be, 48, AkFourCC(16, 0, '3', 'G')}, - {AkVideoCaps::Format_gbrp16le, 48, AkFourCC('G', '3', 0, 16)}, - {AkVideoCaps::Format_yuva422p, 24, AkFourCC('Y', '4', 10, 8)}, - {AkVideoCaps::Format_yuva444p, 32, AkFourCC('Y', '4', 0, 8)}, - {AkVideoCaps::Format_yuva420p9be, 22, AkFourCC(9, 11, '4', 'Y')}, - {AkVideoCaps::Format_yuva420p9le, 22, AkFourCC('Y', '4', 11, 9)}, - {AkVideoCaps::Format_yuva422p9be, 27, AkFourCC(9, 10, '4', 'Y')}, - {AkVideoCaps::Format_yuva422p9le, 27, AkFourCC('Y', '4', 10, 9)}, - {AkVideoCaps::Format_yuva444p9be, 36, AkFourCC(9, 0, '4', 'Y')}, - {AkVideoCaps::Format_yuva444p9le, 36, AkFourCC('Y', '4', 0, 9)}, - {AkVideoCaps::Format_yuva420p10be, 25, AkFourCC(10, 11, '4', 'Y')}, - {AkVideoCaps::Format_yuva420p10le, 25, AkFourCC('Y', '4', 11, 10)}, - {AkVideoCaps::Format_yuva422p10be, 30, AkFourCC(10, 10, '4', 'Y')}, - {AkVideoCaps::Format_yuva422p10le, 30, AkFourCC('Y', '4', 10, 10)}, - {AkVideoCaps::Format_yuva444p10be, 40, AkFourCC(10, 0, '4', 'Y')}, - {AkVideoCaps::Format_yuva444p10le, 40, AkFourCC('Y', '4', 0, 10)}, - {AkVideoCaps::Format_yuva420p16be, 40, AkFourCC(16, 11, '4', 'Y')}, - {AkVideoCaps::Format_yuva420p16le, 40, AkFourCC('Y', '4', 11, 16)}, - {AkVideoCaps::Format_yuva422p16be, 48, AkFourCC(16, 10, '4', 'Y')}, - {AkVideoCaps::Format_yuva422p16le, 48, AkFourCC('Y', '4', 10, 16)}, - {AkVideoCaps::Format_yuva444p16be, 64, AkFourCC(16, 0, '4', 'Y')}, - {AkVideoCaps::Format_yuva444p16le, 64, AkFourCC('Y', '4', 0, 16)}, - {AkVideoCaps::Format_xyz12le, 36, AkFourCC('X', 'Y', 'Z', '$')}, - {AkVideoCaps::Format_xyz12be, 36, AkFourCC('$', 'Z', 'Y', 'X')}, - {AkVideoCaps::Format_nv16, 16, AK_FOURCC_NULL}, - {AkVideoCaps::Format_nv20le, 20, AK_FOURCC_NULL}, - {AkVideoCaps::Format_nv20be, 20, AK_FOURCC_NULL}, - {AkVideoCaps::Format_rgba64be, 64, AkFourCC('@', 'R', 'B', 'A')}, - {AkVideoCaps::Format_rgba64le, 64, AkFourCC('R', 'B', 'A', '@')}, - {AkVideoCaps::Format_bgra64be, 64, AkFourCC('@', 'B', 'R', 'A')}, - {AkVideoCaps::Format_bgra64le, 64, AkFourCC('B', 'R', 'A', '@')}, - {AkVideoCaps::Format_yvyu422, 16, AkFourCC('Y', 'V', 'Y', 'U')}, - {AkVideoCaps::Format_ya16be, 32, AK_FOURCC_NULL}, - {AkVideoCaps::Format_ya16le, 32, AK_FOURCC_NULL}, - {AkVideoCaps::Format_gbrap, 32, AkFourCC('G', '4', 0, 8)}, - {AkVideoCaps::Format_gbrap16be, 64, AkFourCC(16, 0, '4', 'G')}, - {AkVideoCaps::Format_gbrap16le, 64, AkFourCC('G', '4', 0, 16)}, - {AkVideoCaps::Format_0rgb, 24, AkFourCC(0, 'R', 'G', 'B')}, - {AkVideoCaps::Format_rgb0, 24, AkFourCC('R', 'G', 'B', 0)}, - {AkVideoCaps::Format_0bgr, 24, AkFourCC(0, 'B', 'G', 'R')}, - {AkVideoCaps::Format_bgr0, 24, AkFourCC('B', 'G', 'R', 0)}, - {AkVideoCaps::Format_yuv420p12be, 18, AkFourCC(12, 11, '3', 'Y')}, - {AkVideoCaps::Format_yuv420p12le, 18, AkFourCC('Y', '3', 11, 12)}, - {AkVideoCaps::Format_yuv420p14be, 21, AkFourCC(14, 11, '3', 'Y')}, - {AkVideoCaps::Format_yuv420p14le, 21, AkFourCC('Y', '3', 11, 14)}, - {AkVideoCaps::Format_yuv422p12be, 24, AkFourCC(12, 10, '3', 'Y')}, - {AkVideoCaps::Format_yuv422p12le, 24, AkFourCC('Y', '3', 10, 12)}, - {AkVideoCaps::Format_yuv422p14be, 28, AkFourCC(14, 10, '3', 'Y')}, - {AkVideoCaps::Format_yuv422p14le, 28, AkFourCC('Y', '3', 10, 14)}, - {AkVideoCaps::Format_yuv444p12be, 36, AkFourCC(12, 0, '3', 'Y')}, - {AkVideoCaps::Format_yuv444p12le, 36, AkFourCC('Y', '3', 0, 12)}, - {AkVideoCaps::Format_yuv444p14be, 42, AkFourCC(14, 0, '3', 'Y')}, - {AkVideoCaps::Format_yuv444p14le, 42, AkFourCC('Y', '3', 0, 14)}, - {AkVideoCaps::Format_gbrp12be, 36, AkFourCC(12, 0, '3', 'G')}, - {AkVideoCaps::Format_gbrp12le, 36, AkFourCC('G', '3', 0, 12)}, - {AkVideoCaps::Format_gbrp14be, 42, AkFourCC(14, 0, '3', 'G')}, - {AkVideoCaps::Format_gbrp14le, 42, AkFourCC('G', '3', 0, 14)}, - {AkVideoCaps::Format_yuvj411p, 12, AK_FOURCC_NULL}, - {AkVideoCaps::Format_bayer_bggr8, 8, AkFourCC(0xBA, 'B', 'G', 8)}, - {AkVideoCaps::Format_bayer_rggb8, 8, AkFourCC(0xBA, 'R', 'G', 8)}, - {AkVideoCaps::Format_bayer_gbrg8, 8, AkFourCC(0xBA, 'G', 'B', 8)}, - {AkVideoCaps::Format_bayer_grbg8, 8, AkFourCC(0xBA, 'G', 'R', 8)}, - {AkVideoCaps::Format_bayer_bggr16le, 16, AkFourCC(0xBA, 'B', 'G', 16)}, - {AkVideoCaps::Format_bayer_bggr16be, 16, AkFourCC( 16, 'G', 'B', 0xBA)}, - {AkVideoCaps::Format_bayer_rggb16le, 16, AkFourCC(0xBA, 'R', 'G', 16)}, - {AkVideoCaps::Format_bayer_rggb16be, 16, AkFourCC( 16, 'G', 'R', 0xBA)}, - {AkVideoCaps::Format_bayer_gbrg16le, 16, AkFourCC(0xBA, 'G', 'B', 16)}, - {AkVideoCaps::Format_bayer_gbrg16be, 16, AkFourCC( 16, 'B', 'G', 0xBA)}, - {AkVideoCaps::Format_bayer_grbg16le, 16, AkFourCC(0xBA, 'G', 'R', 16)}, - {AkVideoCaps::Format_bayer_grbg16be, 16, AkFourCC( 16, 'R', 'G', 0xBA)}, - {AkVideoCaps::Format_yuv440p10le, 20, AK_FOURCC_NULL}, - {AkVideoCaps::Format_yuv440p10be, 20, AK_FOURCC_NULL}, - {AkVideoCaps::Format_yuv440p12le, 24, AK_FOURCC_NULL}, - {AkVideoCaps::Format_yuv440p12be, 24, AK_FOURCC_NULL}, - {AkVideoCaps::Format_ayuv64le, 64, AK_FOURCC_NULL}, - {AkVideoCaps::Format_ayuv64be, 64, AK_FOURCC_NULL}, - {AkVideoCaps::Format_p010le, 15, AK_FOURCC_NULL}, - {AkVideoCaps::Format_p010be, 15, AK_FOURCC_NULL}, - {AkVideoCaps::Format_gbrap12be, 48, AkFourCC(12, 0, '4', 'G')}, - {AkVideoCaps::Format_gbrap12le, 48, AkFourCC('G', '4', 0, 12)}, - {AkVideoCaps::Format_gbrap10be, 40, AkFourCC(10, 0, '4', 'G')}, - {AkVideoCaps::Format_gbrap10le, 40, AkFourCC('G', '4', 0, 10)}, - {AkVideoCaps::Format_gray12be, 12, AkFourCC(12, 0, '1', 'Y')}, - {AkVideoCaps::Format_gray12le, 12, AkFourCC('Y', '1', 0, 12)}, - {AkVideoCaps::Format_gray10be, 10, AkFourCC(10, 0, '1', 'Y')}, - {AkVideoCaps::Format_gray10le, 10, AkFourCC('Y', '1', 0, 10)}, - {AkVideoCaps::Format_p016le, 24, AK_FOURCC_NULL}, - {AkVideoCaps::Format_p016be, 24, AK_FOURCC_NULL}, - {AkVideoCaps::Format_gray9be, 9, AkFourCC(9, 0, '1', 'Y')}, - {AkVideoCaps::Format_gray9le, 9, AkFourCC('Y', '1', 0, 9)}, - {AkVideoCaps::Format_gbrpf32be, 96, AK_FOURCC_NULL}, - {AkVideoCaps::Format_gbrpf32le, 96, AK_FOURCC_NULL}, - {AkVideoCaps::Format_gbrapf32be, 128, AK_FOURCC_NULL}, - {AkVideoCaps::Format_gbrapf32le, 128, AK_FOURCC_NULL}, + {AkVideoCaps::Format_none , 0, AK_FOURCC_NULL , {} , {} }, + {AkVideoCaps::Format_rgb444be , 12, AkFourCCS("\xcBGR") , {16} , {1} }, + {AkVideoCaps::Format_rgb444le , 12, AkFourCCS("RGB\xc") , {16} , {1} }, + {AkVideoCaps::Format_argb444be , 16, AK_FOURCC_NULL , {16} , {1} }, + {AkVideoCaps::Format_argb444le , 16, AK_FOURCC_NULL , {16} , {1} }, + {AkVideoCaps::Format_rgb555be , 15, AkFourCCS("\xfBGR") , {16} , {1} }, + {AkVideoCaps::Format_rgb555le , 15, AkFourCCS("RGB\xf") , {16} , {1} }, + {AkVideoCaps::Format_argb555be , 16, AK_FOURCC_NULL , {16} , {1} }, + {AkVideoCaps::Format_argb555le , 16, AK_FOURCC_NULL , {16} , {1} }, + {AkVideoCaps::Format_rgb565be , 16, AkFourCCS("\x10""BGR") , {16} , {1} }, + {AkVideoCaps::Format_rgb565le , 16, AkFourCCS("RGB\x10") , {16} , {1} }, + {AkVideoCaps::Format_rgb0 , 24, AkFourCCS("RGB\x0") , {32} , {1} }, + {AkVideoCaps::Format_rgb24 , 24, AkFourCCS("RGB\x18") , {24} , {1} }, + {AkVideoCaps::Format_rgb48be , 48, AkFourCCS("0RGB") , {48} , {1} }, + {AkVideoCaps::Format_rgb48le , 48, AkFourCCS("RGB0") , {48} , {1} }, + {AkVideoCaps::Format_bgr444be , 12, AkFourCCS("\xcRGB") , {16} , {1} }, + {AkVideoCaps::Format_bgr444le , 12, AkFourCCS("BGR\xc") , {16} , {1} }, + {AkVideoCaps::Format_bgr555be , 15, AkFourCCS("\xfRGB") , {16} , {1} }, + {AkVideoCaps::Format_bgr555le , 15, AkFourCCS("BGR\xf") , {16} , {1} }, + {AkVideoCaps::Format_bgr565be , 16, AkFourCCS("\x10RGB") , {16} , {1} }, + {AkVideoCaps::Format_bgr565le , 16, AkFourCCS("BGR\x10") , {16} , {1} }, + {AkVideoCaps::Format_rgb666 , 18, AK_FOURCC_NULL , {24} , {1} }, + {AkVideoCaps::Format_argb1665 , 18, AK_FOURCC_NULL , {24} , {1} }, + {AkVideoCaps::Format_argb1666 , 19, AK_FOURCC_NULL , {24} , {1} }, + {AkVideoCaps::Format_bgr666 , 18, AK_FOURCC_NULL , {24} , {1} }, + {AkVideoCaps::Format_argb6666 , 24, AK_FOURCC_NULL , {24} , {1} }, + {AkVideoCaps::Format_abgr6666 , 24, AK_FOURCC_NULL , {24} , {1} }, + {AkVideoCaps::Format_0bgr , 32, AkFourCCS("\x0BGR") , {32} , {1} }, + {AkVideoCaps::Format_0rgb , 32, AkFourCCS("\x0RGB") , {32} , {1} }, + {AkVideoCaps::Format_abgr , 32, AkFourCCS("ABGR") , {32} , {1} }, + {AkVideoCaps::Format_argb , 32, AkFourCCS("ARGB") , {32} , {1} }, + {AkVideoCaps::Format_bgr0 , 32, AkFourCCS("BGR\x0") , {32} , {1} }, + {AkVideoCaps::Format_bgr24 , 32, AkFourCCS("BGR\x18") , {24} , {1} }, + {AkVideoCaps::Format_bgr48be , 48, AkFourCCS("0BGR") , {48} , {1} }, + {AkVideoCaps::Format_bgr48le , 48, AkFourCCS("BGR0") , {48} , {1} }, + {AkVideoCaps::Format_rgba , 32, AkFourCCS("RGBA") , {32} , {1} }, + {AkVideoCaps::Format_rgba64be , 64, AkFourCCS("\x40RBA") , {64} , {1} }, + {AkVideoCaps::Format_rgba64le , 64, AkFourCCS("RBA\x40") , {64} , {1} }, + {AkVideoCaps::Format_bgra , 32, AkFourCCS("BGRA") , {32} , {1} }, + {AkVideoCaps::Format_bgra64be , 64, AkFourCCS("\x40""BRA") , {64} , {1} }, + {AkVideoCaps::Format_bgra64le , 64, AkFourCCS("BRA\x40") , {64} , {1} }, + {AkVideoCaps::Format_argb1887 , 24, AK_FOURCC_NULL , {24} , {1} }, + {AkVideoCaps::Format_bgra1888 , 25, AK_FOURCC_NULL , {32} , {1} }, + {AkVideoCaps::Format_monob , 1, AkFourCCS("B0W1") , { 1} , {1} }, + {AkVideoCaps::Format_monow , 1, AkFourCCS("B1W0") , { 1} , {1} }, + {AkVideoCaps::Format_rgb4 , 4, AkFourCCS("RGB\x4") , { 4} , {1} }, + {AkVideoCaps::Format_rgb4_byte , 4, AkFourCCS("B4BY") , { 8} , {1} }, + {AkVideoCaps::Format_rgb8 , 8, AkFourCCS("RGB\x8") , { 8} , {1} }, + {AkVideoCaps::Format_bgr4 , 4, AkFourCCS("BGR\x4") , { 4} , {1} }, + {AkVideoCaps::Format_bgr4_byte , 4, AkFourCCS("R4BY") , { 8} , {1} }, + {AkVideoCaps::Format_bgr8 , 8, AkFourCCS("BGR\x8") , { 8} , {1} }, + {AkVideoCaps::Format_gray2 , 2, AK_FOURCC_NULL , { 8} , {1} }, + {AkVideoCaps::Format_gray4 , 4, AK_FOURCC_NULL , { 8} , {1} }, + {AkVideoCaps::Format_gray24 , 24, AK_FOURCC_NULL , {32} , {1} }, + {AkVideoCaps::Format_gray32 , 32, AK_FOURCC_NULL , {32} , {1} }, + {AkVideoCaps::Format_gray , 8, AkFourCCS("Y800") , { 8} , {1} }, + {AkVideoCaps::Format_gray9be , 9, AkFourCCS("\x9\x01Y") , {16} , {1} }, + {AkVideoCaps::Format_gray9le , 9, AkFourCCS("Y1\x0\x9") , {16} , {1} }, + {AkVideoCaps::Format_gray10be , 10, AkFourCCS("\xa\x01Y") , {16} , {1} }, + {AkVideoCaps::Format_gray10le , 10, AkFourCCS("Y1\x0\xa") , {16} , {1} }, + {AkVideoCaps::Format_gray12be , 12, AkFourCCS("\xc\x01Y") , {16} , {1} }, + {AkVideoCaps::Format_gray12le , 12, AkFourCCS("Y1\x0\xc") , {16} , {1} }, + {AkVideoCaps::Format_gray14be , 14, AkFourCCS("\xe\x01Y") , {16} , {1} }, + {AkVideoCaps::Format_gray14le , 14, AkFourCCS("Y1\x0\xe") , {16} , {1} }, + {AkVideoCaps::Format_gray16be , 16, AkFourCCS("\x10\x01Y") , {16} , {1} }, + {AkVideoCaps::Format_gray16le , 16, AkFourCCS("Y1\x0\x10") , {16} , {1} }, + {AkVideoCaps::Format_grayf32be , 32, AK_FOURCC_NULL , {32} , {1} }, + {AkVideoCaps::Format_grayf32le , 32, AK_FOURCC_NULL , {32} , {1} }, + {AkVideoCaps::Format_bayer_bggr8 , 8, AkFourCCS("\xba""BG\x8") , { 8} , {1} }, + {AkVideoCaps::Format_bayer_gbrg8 , 8, AkFourCCS("\xbaGB\x8") , { 8} , {1} }, + {AkVideoCaps::Format_bayer_grbg8 , 8, AkFourCCS("\xbaGR\x8") , { 8} , {1} }, + {AkVideoCaps::Format_bayer_rggb8 , 8, AkFourCCS("\xbaRG\x8") , { 8} , {1} }, + {AkVideoCaps::Format_bayer_bggr16be, 16, AkFourCCS("\x10GB\xba") , {16} , {1} }, + {AkVideoCaps::Format_bayer_bggr16le, 16, AkFourCCS("\xba""BG\x10"), {16} , {1} }, + {AkVideoCaps::Format_bayer_gbrg16be, 16, AkFourCCS("\x10""BG\xba"), {16} , {1} }, + {AkVideoCaps::Format_bayer_gbrg16le, 16, AkFourCCS("\xbaGB\x10") , {16} , {1} }, + {AkVideoCaps::Format_bayer_grbg16be, 16, AkFourCCS("\x10RG\xba") , {16} , {1} }, + {AkVideoCaps::Format_bayer_grbg16le, 16, AkFourCCS("\xbaGR\x10") , {16} , {1} }, + {AkVideoCaps::Format_bayer_rggb16be, 16, AkFourCCS("\x10GR\xba") , {16} , {1} }, + {AkVideoCaps::Format_bayer_rggb16le, 16, AkFourCCS("\xbaRG\x10") , {16} , {1} }, + {AkVideoCaps::Format_ayuv64be , 64, AK_FOURCC_NULL , {64} , {1} }, + {AkVideoCaps::Format_ayuv64le , 64, AK_FOURCC_NULL , {64} , {1} }, + {AkVideoCaps::Format_uyvy422 , 16, AkFourCCS("UYVY") , {16} , {1} }, + {AkVideoCaps::Format_vyuy422 , 16, AK_FOURCC_NULL , {16} , {1} }, + {AkVideoCaps::Format_uyyvyy411 , 12, AkFourCCS("Y411") , {12} , {1} }, + {AkVideoCaps::Format_ya16be , 32, AK_FOURCC_NULL , {32} , {1} }, + {AkVideoCaps::Format_ya16le , 32, AK_FOURCC_NULL , {32} , {1} }, + {AkVideoCaps::Format_ya8 , 16, AkFourCCS("Y2\x0\x8") , {16} , {1} }, + {AkVideoCaps::Format_yuyv422 , 16, AkFourCCS("YUY2") , {16} , {1} }, + {AkVideoCaps::Format_yvyu422 , 16, AkFourCCS("YVYU") , {16} , {1} }, + {AkVideoCaps::Format_xyz12be , 36, AkFourCCS("\x24ZYX") , {48} , {1} }, + {AkVideoCaps::Format_xyz12le , 36, AkFourCCS("XYZ\x24") , {48} , {1} }, + {AkVideoCaps::Format_nv12 , 12, AkFourCCS("NV12") , { 8, 8} , {1, 2} }, + {AkVideoCaps::Format_nv16 , 16, AK_FOURCC_NULL , { 8, 8} , {1, 1} }, + {AkVideoCaps::Format_nv20be , 20, AK_FOURCC_NULL , {16, 16} , {1, 1} }, + {AkVideoCaps::Format_nv20le , 20, AK_FOURCC_NULL , {16, 16} , {1, 1} }, + {AkVideoCaps::Format_nv21 , 12, AkFourCCS("NV21") , { 8, 8} , {1, 2} }, + {AkVideoCaps::Format_p010be , 15, AK_FOURCC_NULL , {16, 16} , {1, 2} }, + {AkVideoCaps::Format_p010le , 15, AK_FOURCC_NULL , {16, 16} , {1, 2} }, + {AkVideoCaps::Format_p016be , 24, AK_FOURCC_NULL , {16, 16} , {1, 2} }, + {AkVideoCaps::Format_p016le , 24, AK_FOURCC_NULL , {16, 16} , {1, 2} }, + {AkVideoCaps::Format_yuv410p , 9, AkFourCCS("YUV9") , { 8, 2, 2} , {1, 4, 4} }, + {AkVideoCaps::Format_yuv411p , 12, AkFourCCS("Y41B") , { 8, 2, 2} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv420p , 12, AkFourCCS("I420") , { 8, 4, 4} , {1, 2, 2} }, + {AkVideoCaps::Format_yvu420p , 12, AK_FOURCC_NULL , { 8, 4, 4} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv422p , 16, AkFourCCS("Y42B") , { 8, 4, 4} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv440p , 16, AkFourCCS("440P") , { 8, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv444p , 24, AkFourCCS("444P") , { 8, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuvj411p , 12, AK_FOURCC_NULL , { 8, 2, 2} , {1, 1, 1} }, + {AkVideoCaps::Format_yuvj420p , 12, AkFourCCS("I420") , { 8, 4, 4} , {1, 2, 2} }, + {AkVideoCaps::Format_yuvj422p , 16, AkFourCCS("Y42B") , { 8, 4, 4} , {1, 1, 1} }, + {AkVideoCaps::Format_yuvj440p , 16, AkFourCCS("440P") , { 8, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuvj444p , 24, AkFourCCS("444P") , { 8, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv420p9be , 13, AkFourCCS("\x9\xb3Y") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p9le , 13, AkFourCCS("Y3\xb\x9") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p10be , 15, AkFourCCS("\xa\xb3Y") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p10le , 15, AkFourCCS("Y3\xb\xa") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p12be , 18, AkFourCCS("\xc\xb3Y") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p12le , 18, AkFourCCS("Y3\xb\xc") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p14be , 21, AkFourCCS("\xe\xb3Y") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p14le , 21, AkFourCCS("Y3\xb\xe") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p16be , 24, AkFourCCS("\x10\xb3Y") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv420p16le , 24, AkFourCCS("Y3\xb\x10") , {16, 8, 8} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv422p9be , 18, AkFourCCS("\x9\xa3Y") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p9le , 18, AkFourCCS("Y3\xa\x9") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p10be , 20, AkFourCCS("\xa\xa3Y") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p10le , 20, AkFourCCS("Y3\xa\xa") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p12be , 24, AkFourCCS("\xc\xa3Y") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p12le , 24, AkFourCCS("Y3\xa\xc") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p14be , 28, AkFourCCS("\xe\xa3Y") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p14le , 28, AkFourCCS("Y3\xa\xe") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p16be , 32, AkFourCCS("\x10\xa3Y") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv422p16le , 32, AkFourCCS("Y3\xa\x10") , {16, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv440p10be , 20, AK_FOURCC_NULL , {16, 16, 16} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv440p10le , 20, AK_FOURCC_NULL , {16, 16, 16} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv440p12be , 24, AK_FOURCC_NULL , {16, 16, 16} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv440p12le , 24, AK_FOURCC_NULL , {16, 16, 16} , {1, 2, 2} }, + {AkVideoCaps::Format_yuv444p9be , 27, AkFourCCS("\x9\x03Y") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p9le , 27, AkFourCCS("Y3\x0\x9") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p10be , 30, AkFourCCS("\xa\x03Y") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p10le , 30, AkFourCCS("Y3\x0\xa") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p12be , 36, AkFourCCS("\xc\x03Y") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p12le , 36, AkFourCCS("Y3\x0\xc") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p14be , 42, AkFourCCS("\xe\x03Y") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p14le , 42, AkFourCCS("Y3\x0\xe") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p16be , 48, AkFourCCS("\x10\x03Y") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuv444p16le , 48, AkFourCCS("Y3\x0\x10") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_yuva420p , 20, AkFourCCS("Y4\xb\x8") , { 8, 4, 4, 8}, {1, 2, 2, 1}}, + {AkVideoCaps::Format_yuva422p , 24, AkFourCCS("Y4\xa\x8") , { 8, 4, 4, 8}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuv444 , 24, AK_FOURCC_NULL , {24} , {1} }, + {AkVideoCaps::Format_yuva444p , 32, AkFourCCS("Y4\x0\x8") , { 8, 8, 8, 8}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva420p9be , 22, AkFourCCS("\x9\xb4Y") , {16, 8, 8, 16}, {1, 2, 2, 1}}, + {AkVideoCaps::Format_yuva420p9le , 22, AkFourCCS("Y4\xb\x9") , {16, 8, 8, 16}, {1, 2, 2, 1}}, + {AkVideoCaps::Format_yuva420p10be , 25, AkFourCCS("\xa\xb4Y") , {16, 8, 8, 16}, {1, 2, 2, 1}}, + {AkVideoCaps::Format_yuva420p10le , 25, AkFourCCS("Y4\xb\xa") , {16, 8, 8, 16}, {1, 2, 2, 1}}, + {AkVideoCaps::Format_yuva420p16be , 40, AkFourCCS("\x10\xb4Y") , {16, 8, 8, 16}, {1, 2, 2, 1}}, + {AkVideoCaps::Format_yuva420p16le , 40, AkFourCCS("Y4\xb\x10") , {16, 8, 8, 16}, {1, 2, 2, 1}}, + {AkVideoCaps::Format_yuva422p9be , 27, AkFourCCS("\x9\xa4Y") , {16, 8, 8, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva422p9le , 27, AkFourCCS("Y4\xa\x9") , {16, 8, 8, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva422p10be , 30, AkFourCCS("\xa\xa4Y") , {16, 8, 8, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva422p10le , 30, AkFourCCS("Y4\xa\xa") , {16, 8, 8, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva422p16be , 48, AkFourCCS("\x10\xa4Y") , {16, 8, 8, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva422p16le , 48, AkFourCCS("Y4\xa\x10") , {16, 8, 8, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva444p9be , 36, AkFourCCS("\x9\x04Y") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva444p9le , 36, AkFourCCS("Y4\x0\x9") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva444p10be , 40, AkFourCCS("\xa\x04Y") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva444p10le , 40, AkFourCCS("Y4\x0\xa") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva444p16be , 64, AkFourCCS("\x10\x04Y") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_yuva444p16le , 64, AkFourCCS("Y4\x0\x10") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrp , 24, AkFourCCS("G3\x0\x8") , { 8, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp9be , 27, AkFourCCS("\x9\x03G") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp9le , 27, AkFourCCS("G3\x0\x9") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp10be , 30, AkFourCCS("\xa\x03G") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp10le , 30, AkFourCCS("G3\x0\xa") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp12be , 36, AkFourCCS("\xc\x03G") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp12le , 36, AkFourCCS("G3\x0\xc") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp14be , 42, AkFourCCS("\xe\x03G") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp14le , 42, AkFourCCS("G3\x0\xe") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp16be , 48, AkFourCCS("\x10\x03G") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrp16le , 48, AkFourCCS("G3\x0\x10") , {16, 16, 16} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrpf32be , 96, AK_FOURCC_NULL , {32, 32, 32} , {1, 1, 1} }, + {AkVideoCaps::Format_gbrpf32le , 96, AK_FOURCC_NULL , {32, 32, 32} , {1, 1, 1} }, + {AkVideoCaps::Format_rgbp , 24, AK_FOURCC_NULL , { 8, 8, 8} , {1, 1, 1} }, + {AkVideoCaps::Format_rgbap , 32, AK_FOURCC_NULL , { 8, 8, 8, 8}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrap , 32, AkFourCCS("G4\x0\x8") , { 8, 8, 8, 8}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrap10be , 40, AkFourCCS("\xa\x04G") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrap10le , 40, AkFourCCS("G4\x0\xa") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrap12be , 48, AkFourCCS("\xc\x04G") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrap12le , 48, AkFourCCS("G4\x0\xc") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrap16be , 64, AkFourCCS("\x10\x04G") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrap16le , 64, AkFourCCS("G4\x0\x10") , {16, 16, 16, 16}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrapf32be , 128, AK_FOURCC_NULL , {32, 32, 32, 32}, {1, 1, 1, 1}}, + {AkVideoCaps::Format_gbrapf32le , 128, AK_FOURCC_NULL , {32, 32, 32, 32}, {1, 1, 1, 1}}, }; return videoFormats; @@ -237,17 +263,27 @@ return &formats().front(); } + + template + static inline T alignUp(const T &value, const T &align) + { + return (value + align - 1) & ~(align - 1); + } }; class AkVideoCapsPrivate { public: - bool m_isValid {false}; AkVideoCaps::PixelFormat m_format {AkVideoCaps::Format_none}; - int m_bpp {0}; int m_width {0}; int m_height {0}; + int m_align {1}; AkFrac m_fps; + const QVector *m_planes_div; + QVector m_bypl; + QVector m_offset; + + void updateParams(); }; AkVideoCaps::AkVideoCaps(QObject *parent): @@ -256,51 +292,53 @@ this->d = new AkVideoCapsPrivate(); } -AkVideoCaps::AkVideoCaps(const QVariantMap &caps) +AkVideoCaps::AkVideoCaps(AkVideoCaps::PixelFormat format, + int width, + int height, + const AkFrac &fps, + int align) { this->d = new AkVideoCapsPrivate(); - this->d->m_isValid = true; - - this->fromMap(caps); + this->d->m_format = format; + this->d->m_width = width; + this->d->m_height = height; + this->d->m_fps = fps; + this->d->m_align = align; + this->d->updateParams(); } -AkVideoCaps::AkVideoCaps(const QString &caps) +AkVideoCaps::AkVideoCaps(AkVideoCaps::PixelFormat format, + const QSize &size, + const AkFrac &fps, + int align) { - this->d = new AkVideoCapsPrivate(); - - this->fromString(caps); + AkVideoCaps(format, size.width(), size.height(), fps, align); } + AkVideoCaps::AkVideoCaps(const AkCaps &caps) { this->d = new AkVideoCapsPrivate(); - if (caps.mimeType() == "video/x-raw") { - this->d->m_isValid = caps.isValid(); + if (caps.mimeType() == "video/x-raw") this->update(caps); - } else { - this->d->m_isValid = false; - this->d->m_format = AkVideoCaps::Format_none; - this->d->m_bpp = 0; - this->d->m_width = 0; - this->d->m_height = 0; - } } AkVideoCaps::AkVideoCaps(const AkVideoCaps &other): QObject() { this->d = new AkVideoCapsPrivate(); - this->d->m_isValid = other.d->m_isValid; this->d->m_format = other.d->m_format; - this->d->m_bpp = other.d->m_bpp; this->d->m_width = other.d->m_width; this->d->m_height = other.d->m_height; this->d->m_fps = other.d->m_fps; + this->d->m_align = other.d->m_align; + this->d->m_planes_div = other.d->m_planes_div; + this->d->m_bypl = other.d->m_bypl; + this->d->m_offset = other.d->m_offset; + auto properties = other.dynamicPropertyNames(); - QList properties = other.dynamicPropertyNames(); - - for (const QByteArray &property: properties) + for (auto &property: properties) this->setProperty(property, other.property(property)); } @@ -312,19 +350,22 @@ AkVideoCaps &AkVideoCaps::operator =(const AkVideoCaps &other) { if (this != &other) { - this->d->m_isValid = other.d->m_isValid; this->d->m_format = other.d->m_format; - this->d->m_bpp = other.d->m_bpp; this->d->m_width = other.d->m_width; this->d->m_height = other.d->m_height; this->d->m_fps = other.d->m_fps; + this->d->m_align = other.d->m_align; + this->d->m_planes_div = other.d->m_planes_div; + this->d->m_bypl = other.d->m_bypl; + this->d->m_offset = other.d->m_offset; this->clear(); + auto properties = other.dynamicPropertyNames(); - QList properties = other.dynamicPropertyNames(); - - for (const QByteArray &property: properties) + for (auto &property: properties) this->setProperty(property, other.property(property)); + + this->d->updateParams(); } return *this; @@ -333,30 +374,32 @@ AkVideoCaps &AkVideoCaps::operator =(const AkCaps &caps) { if (caps.mimeType() == "video/x-raw") { - this->d->m_isValid = caps.isValid(); this->update(caps); } else { - this->d->m_isValid = false; this->d->m_format = AkVideoCaps::Format_none; - this->d->m_bpp = 0; this->d->m_width = 0; this->d->m_height = 0; this->d->m_fps = AkFrac(); + this->d->m_align = 1; } return *this; } -AkVideoCaps &AkVideoCaps::operator =(const QString &caps) +bool AkVideoCaps::operator ==(const AkVideoCaps &other) const { - this->operator =(AkCaps(caps)); + if (this->dynamicPropertyNames() != other.dynamicPropertyNames()) + return false; - return *this; -} + for (auto &property: this->dynamicPropertyNames()) + if (this->property(property) != other.property(property)) + return false; -bool AkVideoCaps::operator ==(const AkVideoCaps &other) const -{ - return this->toString() == other.toString(); + return this->d->m_format == other.d->m_format + && this->d->m_width == other.d->m_width + && this->d->m_height == other.d->m_height + && this->d->m_fps == other.d->m_fps + && this->d->m_align == other.d->m_align; } bool AkVideoCaps::operator !=(const AkVideoCaps &other) const @@ -364,24 +407,21 @@ return !(*this == other); } -AkVideoCaps::operator bool() const -{ - return this->d->m_isValid; -} - AkVideoCaps::operator AkCaps() const { - return this->toCaps(); -} + AkCaps caps("video/x-raw"); + caps.setProperty("format", this->d->m_format); + caps.setProperty("width" , this->d->m_width); + caps.setProperty("height", this->d->m_height); + caps.setProperty("fps" , QVariant::fromValue(this->d->m_fps)); + caps.setProperty("align" , this->d->m_align); -bool AkVideoCaps::isValid() const -{ - return this->d->m_isValid; + return caps; } -bool &AkVideoCaps::isValid() +AkVideoCaps::operator bool() const { - return this->d->m_isValid; + return this->pictureSize() > 0; } AkVideoCaps::PixelFormat AkVideoCaps::format() const @@ -389,11 +429,6 @@ return this->d->m_format; } -AkVideoCaps::PixelFormat &AkVideoCaps::format() -{ - return this->d->m_format; -} - quint32 AkVideoCaps::fourCC() const { return AkVideoCaps::fourCC(this->d->m_format); @@ -401,12 +436,7 @@ int AkVideoCaps::bpp() const { - return this->d->m_bpp; -} - -int &AkVideoCaps::bpp() -{ - return this->d->m_bpp; + return VideoFormat::byFormat(this->d->m_format)->bpp; } QSize AkVideoCaps::size() const @@ -419,21 +449,11 @@ return this->d->m_width; } -int &AkVideoCaps::width() -{ - return this->d->m_width; -} - int AkVideoCaps::height() const { return this->d->m_height; } -int &AkVideoCaps::height() -{ - return this->d->m_height; -} - AkFrac AkVideoCaps::fps() const { return this->d->m_fps; @@ -444,51 +464,54 @@ return this->d->m_fps; } -int AkVideoCaps::pictureSize() const +int AkVideoCaps::align() const { - return this->d->m_bpp * this->d->m_width * this->d->m_height / 8; + return this->d->m_align; } -AkVideoCaps &AkVideoCaps::fromMap(const QVariantMap &caps) +size_t AkVideoCaps::pictureSize() const { - QList properties = this->dynamicPropertyNames(); + auto vf = VideoFormat::byFormat(this->d->m_format); - for (const QByteArray &property: properties) - this->setProperty(property, QVariant()); + if (!vf) + return 0; - if (!caps.contains("mimeType")) { - this->d->m_isValid = false; + size_t size = 0; - return *this; - } + for (int i = 0; i < vf->planes.size(); i++) + size += this->planeSize(i); - for (auto it = caps.begin(); it != caps.end(); it++) - if (it.key() == "mimeType") { - this->d->m_isValid = it.value().toString() == "video/x-raw"; - - if (!this->d->m_isValid) - return *this; - } else { - this->setProperty(it.key().trimmed().toStdString().c_str(), - it.value()); - } - - return *this; + return size; } -AkVideoCaps &AkVideoCaps::fromString(const QString &caps) +AkVideoCaps AkVideoCaps::fromMap(const QVariantMap &caps) { - return *this = caps; + AkVideoCaps videoCaps; + + if (!caps.contains("mimeType") || caps["mimeType"] != "video/x-raw") + return videoCaps; + + for (auto it = caps.begin(); it != caps.end(); it++) { + auto value = it.value(); + + if (it.key() == "mimeType") + continue; + + videoCaps.setProperty(it.key().toStdString().c_str(), value); + } + + return videoCaps; } QVariantMap AkVideoCaps::toMap() const { - QVariantMap map = { - {"format", AkVideoCaps::pixelFormatToString(this->d->m_format)}, - {"bpp" , this->d->m_bpp }, - {"width" , this->d->m_width }, - {"height", this->d->m_height }, - {"fps" , QVariant::fromValue(this->d->m_fps) } + QVariantMap map { + {"mimeType", "video/x-raw" }, + {"format" , this->d->m_format }, + {"width" , this->d->m_width }, + {"height" , this->d->m_height }, + {"fps" , QVariant::fromValue(this->d->m_fps)}, + {"align" , this->d->m_align }, }; for (auto &property: this->dynamicPropertyNames()) { @@ -499,66 +522,61 @@ return map; } -QString AkVideoCaps::toString() const +AkVideoCaps &AkVideoCaps::update(const AkCaps &caps) { - if (!this->d->m_isValid) - return {}; - - QString format = AkVideoCaps::pixelFormatToString(this->d->m_format); + if (caps.mimeType() != "video/x-raw") + return *this; - QString caps = QString("video/x-raw," - "format=%1," - "bpp=%2," - "width=%3," - "height=%4," - "fps=%5").arg(format) - .arg(this->d->m_bpp) - .arg(this->d->m_width) - .arg(this->d->m_height) - .arg(this->d->m_fps.toString()); + this->clear(); - QStringList properties; + for (auto &property: caps.dynamicPropertyNames()) { + int i = this->metaObject()->indexOfProperty(property); - for (auto &property: this->dynamicPropertyNames()) - properties << QString::fromUtf8(property.constData()); + if (this->metaObject()->property(i).isWritable()) + this->setProperty(property, caps.property(property)); + } - properties.sort(); + this->d->updateParams(); - for (auto &property: properties) - caps.append(QString(",%1=%2").arg(property, - this->property(property.toStdString().c_str()).toString())); + return *this; +} - return caps; +size_t AkVideoCaps::planeOffset(int plane) const +{ + return this->d->m_offset[plane]; } -AkVideoCaps &AkVideoCaps::update(const AkCaps &caps) +size_t AkVideoCaps::lineOffset(int plane, int y) const { - if (caps.mimeType() != "video/x-raw") - return *this; + y /= (*this->d->m_planes_div)[plane]; - this->clear(); - auto properties = caps.dynamicPropertyNames(); + return this->planeOffset(plane) + this->bytesPerLine(plane) * size_t(y); +} - for (auto &property: properties) - if (property == "format") - this->d->m_format = AkVideoCaps::pixelFormatFromString(caps.property(property).toString()); - else if (property == "bpp") - this->d->m_bpp = caps.property(property).toInt(); - else if (property == "width") - this->d->m_width = caps.property(property).toInt(); - else if (property == "height") - this->d->m_height = caps.property(property).toInt(); - else if (property == "fps") - this->d->m_fps = caps.property("fps").toString(); - else - this->setProperty(property, caps.property(property)); +size_t AkVideoCaps::bytesPerLine(int plane) const +{ + return this->d->m_bypl.value(plane, 0); +} - return *this; +int AkVideoCaps::planes() const +{ + auto vf = VideoFormat::byFormat(this->d->m_format); + + return vf? vf->planes.size(): 0; } -AkCaps AkVideoCaps::toCaps() const +size_t AkVideoCaps::planeSize(int plane) const { - return AkCaps(this->toString()); + auto bypl = this->bytesPerLine(plane); + + if (bypl < 1) + return 0; + + auto vf = VideoFormat::byFormat(this->d->m_format); + + return bypl + * size_t(this->d->m_height) + / size_t(vf->planes_div[plane]); } int AkVideoCaps::bitsPerPixel(AkVideoCaps::PixelFormat pixelFormat) @@ -609,18 +627,10 @@ return; this->d->m_format = format; + this->d->updateParams(); emit this->formatChanged(format); } -void AkVideoCaps::setBpp(int bpp) -{ - if (this->d->m_bpp == bpp) - return; - - this->d->m_bpp = bpp; - emit this->bppChanged(bpp); -} - void AkVideoCaps::setSize(const QSize &size) { QSize curSize(this->d->m_width, this->d->m_height); @@ -628,8 +638,11 @@ if (curSize == size) return; - this->setWidth(size.width()); - this->setHeight(size.height()); + this->d->m_width = size.width(); + this->d->m_height = size.height(); + this->d->updateParams(); + emit this->widthChanged(size.width()); + emit this->heightChanged(size.height()); emit sizeChanged(size); } @@ -639,6 +652,7 @@ return; this->d->m_width = width; + this->d->updateParams(); emit this->widthChanged(width); } @@ -648,6 +662,7 @@ return; this->d->m_height = height; + this->d->updateParams(); emit this->heightChanged(height); } @@ -660,14 +675,19 @@ emit this->fpsChanged(fps); } -void AkVideoCaps::resetFormat() +void AkVideoCaps::setAlign(int align) { - this->setFormat(AkVideoCaps::Format_none); + if (this->d->m_align == align) + return; + + this->d->m_align = align; + this->d->updateParams(); + emit this->alignChanged(align); } -void AkVideoCaps::resetBpp() +void AkVideoCaps::resetFormat() { - this->setBpp(0); + this->setFormat(AkVideoCaps::Format_none); } void AkVideoCaps::resetSize() @@ -690,33 +710,119 @@ this->setFps(AkFrac()); } +void AkVideoCaps::resetAlign() +{ + this->setAlign(1); +} + void AkVideoCaps::clear() { - QList properties = this->dynamicPropertyNames(); + for (auto &property: this->dynamicPropertyNames()) + this->setProperty(property.constData(), {}); +} + +void AkVideoCapsPrivate::updateParams() +{ + auto vf = VideoFormat::byFormat(this->m_format); - for (const QByteArray &property: properties) - this->setProperty(property.constData(), QVariant()); + if (!vf) { + this->m_planes_div = nullptr; + this->m_offset.clear(); + this->m_bypl.clear(); + + return; + } + + this->m_planes_div = &vf->planes_div; + this->m_offset.clear(); + this->m_bypl.clear(); + size_t offset = 0; + + for (int i = 0; i < vf->planes_div.size(); i++) { + this->m_offset << offset; + auto bypl = VideoFormat::alignUp(size_t(vf->planes[i] + * this->m_width + / 8), + size_t(this->m_align)); + this->m_bypl << bypl; + offset += bypl * size_t(this->m_height) / size_t(vf->planes_div[i]); + } } QDebug operator <<(QDebug debug, const AkVideoCaps &caps) { - debug.nospace() << caps.toString(); + debug.nospace() << "AkVideoCaps(" + << "format=" + << caps.format() + << ",width=" + << caps.width() + << ",height=" + << caps.height() + << ",fps=" + << caps.fps() + << ",align=" + << caps.align(); + + QStringList properties; + + for (auto &property: caps.dynamicPropertyNames()) + properties << QString::fromUtf8(property.constData()); + + properties.sort(); + + for (auto &property: properties) + debug.nospace() << "," + << property.toStdString().c_str() + << "=" + << caps.property(property.toStdString().c_str()); + + debug.nospace() << ")"; + + return debug.space(); +} + +QDebug operator <<(QDebug debug, AkVideoCaps::PixelFormat format) +{ + debug.nospace() << AkVideoCaps::pixelFormatToString(format).toStdString().c_str(); return debug.space(); } QDataStream &operator >>(QDataStream &istream, AkVideoCaps &caps) { - QString capsStr; - istream >> capsStr; - caps.fromString(capsStr); + int nProperties; + istream >> nProperties; + + for (int i = 0; i < nProperties; i++) { + QByteArray key; + QVariant value; + istream >> key; + istream >> value; + + caps.setProperty(key.toStdString().c_str(), value); + } return istream; } QDataStream &operator <<(QDataStream &ostream, const AkVideoCaps &caps) { - ostream << caps.toString(); + QVariantMap staticProperties { + {"format", caps.format() }, + {"width" , caps.width() }, + {"height", caps.height() }, + {"fps" , QVariant::fromValue(caps.fps())}, + {"align" , caps.align() }, + }; + + int nProperties = + staticProperties.size() + caps.dynamicPropertyNames().size(); + ostream << nProperties; + + for (auto &key: caps.dynamicPropertyNames()) { + ostream << key; + ostream << caps.property(key); + } return ostream; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akvideocaps.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akvideocaps.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akvideocaps.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akvideocaps.h 2021-02-15 15:25:23.000000000 +0000 @@ -30,29 +30,51 @@ | ((quint32(c) & 0xff) << 8) \ | (quint32(d) & 0xff)) -#define AK_FOURCC_NULL AkFourCC('\x0', '\x0', '\x0', '\x0') +inline quint32 AkFourCCS(const QString &fourcc) +{ + if (fourcc.size() != 4) + return 0; + + return AkFourCC(fourcc[0].toLatin1(), + fourcc[1].toLatin1(), + fourcc[2].toLatin1(), + fourcc[3].toLatin1()); +} + +#define AkFourCCR(a, b, c, d) \ + (((quint32(d) & 0xff) << 24) \ + | ((quint32(c) & 0xff) << 16) \ + | ((quint32(b) & 0xff) << 8) \ + | (quint32(a) & 0xff)) + +inline quint32 AkFourCCRS(const QString &fourcc) +{ + if (fourcc.size() != 4) + return 0; + + return AkFourCCR(fourcc[0].toLatin1(), + fourcc[1].toLatin1(), + fourcc[2].toLatin1(), + fourcc[3].toLatin1()); +} + +#define AK_FOURCC_NULL AkFourCC(0, 0, 0, 0) class AkVideoCapsPrivate; class AkCaps; class AkFrac; -class QDataStream; class AKCOMMONS_EXPORT AkVideoCaps: public QObject { Q_OBJECT Q_ENUMS(PixelFormat) - Q_PROPERTY(bool isValid - READ isValid) Q_PROPERTY(PixelFormat format READ format WRITE setFormat RESET resetFormat NOTIFY formatChanged) Q_PROPERTY(int bpp - READ bpp - WRITE setBpp - RESET resetBpp - NOTIFY bppChanged) + READ bpp) Q_PROPERTY(QSize size READ size WRITE setSize @@ -73,14 +95,22 @@ WRITE setFps RESET resetFps NOTIFY fpsChanged) - Q_PROPERTY(int pictureSize + Q_PROPERTY(int align + READ align + WRITE setAlign + RESET resetAlign + NOTIFY alignChanged) + Q_PROPERTY(size_t pictureSize READ pictureSize) + Q_PROPERTY(int planes + READ planes) public: enum PixelFormat { Format_none = -1, Format_yuv420p, + Format_yvu420p, Format_yuyv422, Format_rgb24, Format_bgr24, @@ -95,9 +125,8 @@ Format_yuvj420p, Format_yuvj422p, Format_yuvj444p, - Format_xvmcmc, - Format_xvmcidct, Format_uyvy422, + Format_vyuy422, Format_uyyvyy411, Format_bgr8, Format_bgr4, @@ -116,34 +145,34 @@ Format_yuv440p, Format_yuvj440p, Format_yuva420p, - Format_vdpau_h264, - Format_vdpau_mpeg1, - Format_vdpau_mpeg2, - Format_vdpau_wmv3, - Format_vdpau_vc1, Format_rgb48be, Format_rgb48le, Format_rgb565be, Format_rgb565le, Format_rgb555be, Format_rgb555le, + Format_argb555be, + Format_argb555le, Format_bgr565be, Format_bgr565le, Format_bgr555be, Format_bgr555le, - Format_vaapi_moco, - Format_vaapi_idct, - Format_vaapi_vld, + Format_rgb666, + Format_argb1665, + Format_argb1666, + Format_bgr666, + Format_argb6666, + Format_abgr6666, Format_yuv420p16le, Format_yuv420p16be, Format_yuv422p16le, Format_yuv422p16be, Format_yuv444p16le, Format_yuv444p16be, - Format_vdpau_mpeg4, - Format_dxva2_vld, Format_rgb444le, Format_rgb444be, + Format_argb444be, + Format_argb444le, Format_bgr444le, Format_bgr444be, Format_ya8, @@ -161,7 +190,6 @@ Format_yuv444p10le, Format_yuv422p9be, Format_yuv422p9le, - Format_vda_vld, Format_gbrp, Format_gbrp9be, Format_gbrp9le, @@ -169,6 +197,8 @@ Format_gbrp10le, Format_gbrp16be, Format_gbrp16le, + Format_yuva422p, + Format_yuva444p, Format_yuva420p9be, Format_yuva420p9le, Format_yuva422p9be, @@ -187,29 +217,25 @@ Format_yuva422p16le, Format_yuva444p16be, Format_yuva444p16le, - Format_vdpau, Format_xyz12le, Format_xyz12be, Format_nv16, Format_nv20le, Format_nv20be, - Format_yvyu422, - Format_vda, - Format_ya16be, - Format_ya16le, - Format_qsv, - Format_mmal, - Format_d3d11va_vld, Format_rgba64be, Format_rgba64le, Format_bgra64be, Format_bgra64le, + Format_yvyu422, + Format_ya16be, + Format_ya16le, + Format_gbrap, + Format_gbrap16be, + Format_gbrap16le, Format_0rgb, Format_rgb0, Format_0bgr, Format_bgr0, - Format_yuva444p, - Format_yuva422p, Format_yuv420p12be, Format_yuv420p12le, Format_yuv420p14be, @@ -226,9 +252,6 @@ Format_gbrp12le, Format_gbrp14be, Format_gbrp14le, - Format_gbrap, - Format_gbrap16be, - Format_gbrap16le, Format_yuvj411p, Format_bayer_bggr8, Format_bayer_rggb8, @@ -266,47 +289,60 @@ Format_gbrpf32le, Format_gbrapf32be, Format_gbrapf32le, - Format_v210, - Format_v216, - Format_v308 + Format_gray14be, + Format_gray14le, + Format_grayf32be, + Format_grayf32le, + Format_rgbp, + Format_rgbap, + Format_argb1887, + Format_bgra1888, + Format_yuv444, + Format_gray2, + Format_gray4, + Format_gray24, + Format_gray32, }; AkVideoCaps(QObject *parent=nullptr); - AkVideoCaps(const QVariantMap &caps); - AkVideoCaps(const QString &caps); + AkVideoCaps(PixelFormat format, + int width, + int height, + const AkFrac &fps, + int align=1); + AkVideoCaps(PixelFormat format, + const QSize &size, + const AkFrac &fps, + int align=1); AkVideoCaps(const AkCaps &caps); AkVideoCaps(const AkVideoCaps &other); ~AkVideoCaps(); AkVideoCaps &operator =(const AkVideoCaps &other); AkVideoCaps &operator =(const AkCaps &caps); - AkVideoCaps &operator =(const QString &caps); bool operator ==(const AkVideoCaps &other) const; bool operator !=(const AkVideoCaps &other) const; operator bool() const; operator AkCaps() const; - Q_INVOKABLE bool isValid() const; - Q_INVOKABLE bool &isValid(); Q_INVOKABLE PixelFormat format() const; - Q_INVOKABLE PixelFormat &format(); Q_INVOKABLE quint32 fourCC() const; Q_INVOKABLE int bpp() const; - Q_INVOKABLE int &bpp(); Q_INVOKABLE QSize size() const; Q_INVOKABLE int width() const; - Q_INVOKABLE int &width(); Q_INVOKABLE int height() const; - Q_INVOKABLE int &height(); Q_INVOKABLE AkFrac fps() const; Q_INVOKABLE AkFrac &fps(); - Q_INVOKABLE int pictureSize() const; + Q_INVOKABLE int align() const; + Q_INVOKABLE size_t pictureSize() const; - Q_INVOKABLE AkVideoCaps &fromMap(const QVariantMap &caps); - Q_INVOKABLE AkVideoCaps &fromString(const QString &caps); + Q_INVOKABLE static AkVideoCaps fromMap(const QVariantMap &caps); Q_INVOKABLE QVariantMap toMap() const; - Q_INVOKABLE QString toString() const; Q_INVOKABLE AkVideoCaps &update(const AkCaps &caps); - Q_INVOKABLE AkCaps toCaps() const; + Q_INVOKABLE size_t planeOffset(int plane) const; + Q_INVOKABLE size_t lineOffset(int plane, int y) const; + Q_INVOKABLE size_t bytesPerLine(int plane) const; + Q_INVOKABLE int planes() const; + Q_INVOKABLE size_t planeSize(int plane) const; Q_INVOKABLE static int bitsPerPixel(PixelFormat pixelFormat); Q_INVOKABLE static int bitsPerPixel(const QString &pixelFormat); @@ -320,35 +356,32 @@ Q_SIGNALS: void formatChanged(PixelFormat format); - void bppChanged(int bpp); void sizeChanged(const QSize &size); void widthChanged(int width); void heightChanged(int height); void fpsChanged(const AkFrac &fps); + void alignChanged(int height); public Q_SLOTS: void setFormat(PixelFormat format); - void setBpp(int bpp); void setSize(const QSize &size); void setWidth(int width); void setHeight(int height); void setFps(const AkFrac &fps); + void setAlign(int align); void resetFormat(); - void resetBpp(); void resetSize(); void resetWidth(); void resetHeight(); void resetFps(); + void resetAlign(); void clear(); - - friend QDebug operator <<(QDebug debug, const AkVideoCaps &caps); - friend QDataStream &operator >>(QDataStream &istream, AkVideoCaps &caps); - friend QDataStream &operator <<(QDataStream &ostream, const AkVideoCaps &caps); }; -QDebug operator <<(QDebug debug, const AkVideoCaps &caps); -QDataStream &operator >>(QDataStream &istream, AkVideoCaps &caps); -QDataStream &operator <<(QDataStream &ostream, const AkVideoCaps &caps); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, const AkVideoCaps &caps); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, AkVideoCaps::PixelFormat format); +AKCOMMONS_EXPORT QDataStream &operator >>(QDataStream &istream, AkVideoCaps &caps); +AKCOMMONS_EXPORT QDataStream &operator <<(QDataStream &ostream, const AkVideoCaps &caps); Q_DECLARE_METATYPE(AkVideoCaps) Q_DECLARE_METATYPE(AkVideoCaps::PixelFormat) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akvideopacket.cpp webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akvideopacket.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akvideopacket.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akvideopacket.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -18,12 +18,127 @@ */ #include -#include #include +#include #include "akvideopacket.h" +#include "akpacket.h" #include "akcaps.h" -#include "akvideocaps.h" +#include "akfrac.h" + +struct RGBX +{ + uint8_t x; + uint8_t b; + uint8_t g; + uint8_t r; +}; + +struct XRGB +{ + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t x; +}; + +struct RGB24 +{ + uint8_t b; + uint8_t g; + uint8_t r; +}; + +struct RGB16 +{ + uint16_t b: 5; + uint16_t g: 6; + uint16_t r: 5; +}; + +struct RGB15 +{ + uint16_t b: 5; + uint16_t g: 5; + uint16_t r: 5; + uint16_t x: 1; +}; + +struct XBGR +{ + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t x; +}; + +struct BGRX +{ + uint8_t x; + uint8_t r; + uint8_t g; + uint8_t b; +}; + +struct BGR24 +{ + uint8_t r; + uint8_t g; + uint8_t b; +}; + +struct BGR16 +{ + uint16_t r: 5; + uint16_t g: 6; + uint16_t b: 5; +}; + +struct BGR15 +{ + uint16_t r: 5; + uint16_t g: 5; + uint16_t b: 5; + uint16_t x: 1; +}; + +struct UYVY +{ + uint8_t v0; + uint8_t y0; + uint8_t u0; + uint8_t y1; +}; + +struct YUY2 +{ + uint8_t y0; + uint8_t v0; + uint8_t y1; + uint8_t u0; +}; + +struct UV +{ + uint8_t u; + uint8_t v; +}; + +struct VU +{ + uint8_t v; + uint8_t u; +}; + +using VideoConvertFuntion = AkVideoPacket (*)(const AkVideoPacket *src, + int align); + +struct VideoConvert +{ + AkVideoCaps::PixelFormat from; + AkVideoCaps::PixelFormat to; + VideoConvertFuntion convert; +}; using ImageToPixelFormatMap = QMap; @@ -49,53 +164,138 @@ { public: AkVideoCaps m_caps; + QByteArray m_buffer; + qint64 m_pts {0}; + AkFrac m_timeBase; + qint64 m_id {-1}; + int m_index {-1}; + + // YUV utility functions + inline static uint8_t rgb_y(int r, int g, int b); + inline static uint8_t rgb_u(int r, int g, int b); + inline static uint8_t rgb_v(int r, int g, int b); + inline static uint8_t yuv_r(int y, int u, int v); + inline static uint8_t yuv_g(int y, int u, int v); + inline static uint8_t yuv_b(int y, int u, int v); + + static AkVideoPacket bgr24_to_0rgb(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_rgb565le(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_rgb555le(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_0bgr(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_bgr565le(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_bgr555le(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_uyvy422(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_yuyv422(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_nv12(const AkVideoPacket *src, int align); + static AkVideoPacket bgr24_to_nv21(const AkVideoPacket *src, int align); + + static AkVideoPacket rgb24_to_0rgb(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_rgb565le(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_rgb555le(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_0bgr(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_bgr24(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_bgr565le(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_bgr555le(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_uyvy422(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_yuyv422(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_nv12(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_nv21(const AkVideoPacket *src, int align); + static AkVideoPacket rgb24_to_yuv420p(const AkVideoPacket *src, int align); + + static AkVideoPacket rgba_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket rgb0_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket yuyv422_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket yuv420p_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket yvu420p_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket nv12_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket nv21_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket rgbap_to_rgb24(const AkVideoPacket *src, int align); + static AkVideoPacket _0bgr_to_rgb24(const AkVideoPacket *src, int align); }; +using VideoConvertFuncs = QVector; + +VideoConvertFuncs initVideoConvertFuncs() +{ + VideoConvertFuncs convert { + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_0rgb , AkVideoPacketPrivate::bgr24_to_0rgb }, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::bgr24_to_rgb24 }, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_rgb565le, AkVideoPacketPrivate::bgr24_to_rgb565le}, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_rgb555le, AkVideoPacketPrivate::bgr24_to_rgb555le}, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_0bgr , AkVideoPacketPrivate::bgr24_to_0bgr }, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_bgr565le, AkVideoPacketPrivate::bgr24_to_bgr565le}, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_bgr555le, AkVideoPacketPrivate::bgr24_to_bgr555le}, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_uyvy422 , AkVideoPacketPrivate::bgr24_to_uyvy422 }, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_yuyv422 , AkVideoPacketPrivate::bgr24_to_yuyv422 }, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_nv12 , AkVideoPacketPrivate::bgr24_to_nv12 }, + {AkVideoCaps::Format_bgr24 , AkVideoCaps::Format_nv21 , AkVideoPacketPrivate::bgr24_to_nv21 }, + + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_0rgb , AkVideoPacketPrivate::rgb24_to_0rgb }, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_rgb565le, AkVideoPacketPrivate::rgb24_to_rgb565le}, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_rgb555le, AkVideoPacketPrivate::rgb24_to_rgb555le}, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_0bgr , AkVideoPacketPrivate::rgb24_to_0bgr }, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_bgr24 , AkVideoPacketPrivate::rgb24_to_bgr24 }, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_bgr565le, AkVideoPacketPrivate::rgb24_to_bgr565le}, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_bgr555le, AkVideoPacketPrivate::rgb24_to_bgr555le}, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_uyvy422 , AkVideoPacketPrivate::rgb24_to_uyvy422 }, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_yuyv422 , AkVideoPacketPrivate::rgb24_to_yuyv422 }, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_nv12 , AkVideoPacketPrivate::rgb24_to_nv12 }, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_nv21 , AkVideoPacketPrivate::rgb24_to_nv21 }, + {AkVideoCaps::Format_rgb24 , AkVideoCaps::Format_yuv420p , AkVideoPacketPrivate::rgb24_to_yuv420p }, + + {AkVideoCaps::Format_rgba , AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::rgba_to_rgb24 }, + {AkVideoCaps::Format_rgb0 , AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::rgba_to_rgb24 }, + {AkVideoCaps::Format_yuyv422, AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::yuyv422_to_rgb24 }, + {AkVideoCaps::Format_yuv420p, AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::yuv420p_to_rgb24 }, + {AkVideoCaps::Format_yvu420p, AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::yvu420p_to_rgb24 }, + {AkVideoCaps::Format_yuv422p, AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::yuv420p_to_rgb24 }, + {AkVideoCaps::Format_nv12 , AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::nv12_to_rgb24 }, + {AkVideoCaps::Format_nv16 , AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::nv12_to_rgb24 }, + {AkVideoCaps::Format_nv21 , AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::nv21_to_rgb24 }, + {AkVideoCaps::Format_rgbap , AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::rgbap_to_rgb24 }, + {AkVideoCaps::Format_0bgr , AkVideoCaps::Format_rgb24 , AkVideoPacketPrivate::_0bgr_to_rgb24 }, + }; + + return convert; +} + +Q_GLOBAL_STATIC_WITH_ARGS(VideoConvertFuncs, videoConvert, (initVideoConvertFuncs())) + AkVideoPacket::AkVideoPacket(QObject *parent): - AkPacket(parent) + QObject(parent) { this->d = new AkVideoPacketPrivate(); } -AkVideoPacket::AkVideoPacket(const AkVideoCaps &caps, - const QByteArray &buffer, - qint64 pts, - const AkFrac &timeBase, - int index, - qint64 id) +AkVideoPacket::AkVideoPacket(const AkVideoCaps &caps) { this->d = new AkVideoPacketPrivate(); this->d->m_caps = caps; - this->buffer() = buffer; - this->pts() = pts; - this->timeBase() = timeBase; - this->index() = index; - this->id() = id; + this->d->m_buffer = QByteArray(int(caps.pictureSize()), Qt::Uninitialized); } AkVideoPacket::AkVideoPacket(const AkPacket &other) { this->d = new AkVideoPacketPrivate(); this->d->m_caps = other.caps(); - this->data() = other.data(); - this->buffer() = other.buffer(); - this->pts() = other.pts(); - this->timeBase() = other.timeBase(); - this->index() = other.index(); - this->id() = other.id(); + this->d->m_buffer = other.buffer(); + this->d->m_pts = other.pts(); + this->d->m_timeBase = other.timeBase(); + this->d->m_index = other.index(); + this->d->m_id = other.id(); } AkVideoPacket::AkVideoPacket(const AkVideoPacket &other): - AkPacket() + QObject() { this->d = new AkVideoPacketPrivate(); this->d->m_caps = other.d->m_caps; - this->data() = other.data(); - this->buffer() = other.buffer(); - this->pts() = other.pts(); - this->timeBase() = other.timeBase(); - this->index() = other.index(); - this->id() = other.id(); + this->d->m_buffer = other.d->m_buffer; + this->d->m_pts = other.d->m_pts; + this->d->m_timeBase = other.d->m_timeBase; + this->d->m_index = other.d->m_index; + this->d->m_id = other.d->m_id; } AkVideoPacket::~AkVideoPacket() @@ -106,12 +306,11 @@ AkVideoPacket &AkVideoPacket::operator =(const AkPacket &other) { this->d->m_caps = other.caps(); - this->data() = other.data(); - this->buffer() = other.buffer(); - this->pts() = other.pts(); - this->timeBase() = other.timeBase(); - this->index() = other.index(); - this->id() = other.id(); + this->d->m_buffer = other.buffer(); + this->d->m_pts = other.pts(); + this->d->m_timeBase = other.timeBase(); + this->d->m_index = other.index(); + this->d->m_id = other.id(); return *this; } @@ -120,20 +319,31 @@ { if (this != &other) { this->d->m_caps = other.d->m_caps; - this->data() = other.data(); - this->buffer() = other.buffer(); - this->pts() = other.pts(); - this->timeBase() = other.timeBase(); - this->index() = other.index(); - this->id() = other.id(); + this->d->m_buffer = other.d->m_buffer; + this->d->m_pts = other.d->m_pts; + this->d->m_timeBase = other.d->m_timeBase; + this->d->m_index = other.d->m_index; + this->d->m_id = other.d->m_id; } return *this; } +AkVideoPacket::operator AkPacket() const +{ + AkPacket packet(this->d->m_caps); + packet.buffer() = this->d->m_buffer; + packet.pts() = this->d->m_pts; + packet.timeBase() = this->d->m_timeBase; + packet.index() = this->d->m_index; + packet.id() = this->d->m_id; + + return packet; +} + AkVideoPacket::operator bool() const { - return this->d->m_caps.isValid(); + return this->d->m_caps && !this->d->m_buffer.isEmpty(); } AkVideoCaps AkVideoPacket::caps() const @@ -146,48 +356,74 @@ return this->d->m_caps; } -QString AkVideoPacket::toString() const +QByteArray AkVideoPacket::buffer() const { - QString packetInfo; - QDebug debug(&packetInfo); + return this->d->m_buffer; +} - debug.nospace() << "Caps : " - << this->d->m_caps.toString().toStdString().c_str() - << "\n" - << "Data : " - << this->data() - << "\n" - << "Buffer Size: " - << this->buffer().size() - << "\n" - << "Id : " - << this->id() - << "\n" - << "Pts : " - << this->pts() - << " (" - << this->pts() * this->timeBase().value() - << ")\n" - << "Time Base : " - << this->timeBase().toString().toStdString().c_str() - << "\n" - << "Index : " - << this->index(); - - return packetInfo; -} - -AkPacket AkVideoPacket::toPacket() const -{ - AkPacket packet; - packet.caps() = this->d->m_caps.toCaps(); - packet.buffer() = this->buffer(); - packet.pts() = this->pts(); - packet.timeBase() = this->timeBase(); - packet.index() = this->index(); - packet.id() = this->id(); +QByteArray &AkVideoPacket::buffer() +{ + return this->d->m_buffer; +} - return packet; +qint64 AkVideoPacket::id() const +{ + return this->d->m_id; +} + +qint64 &AkVideoPacket::id() +{ + return this->d->m_id; +} + +qint64 AkVideoPacket::pts() const +{ + return this->d->m_pts; +} + +qint64 &AkVideoPacket::pts() +{ + return this->d->m_pts; +} + +AkFrac AkVideoPacket::timeBase() const +{ + return this->d->m_timeBase; +} + +AkFrac &AkVideoPacket::timeBase() +{ + return this->d->m_timeBase; +} + +int AkVideoPacket::index() const +{ + return this->d->m_index; +} + +int &AkVideoPacket::index() +{ + return this->d->m_index; +} + +void AkVideoPacket::copyMetadata(const AkVideoPacket &other) +{ + this->d->m_pts = other.d->m_pts; + this->d->m_timeBase = other.d->m_timeBase; + this->d->m_index = other.d->m_index; + this->d->m_id = other.d->m_id; +} + +const quint8 *AkVideoPacket::constLine(int plane, int y) const +{ + return reinterpret_cast(this->d->m_buffer.constData()) + + this->d->m_caps.lineOffset(plane, y); +} + +quint8 *AkVideoPacket::line(int plane, int y) +{ + return reinterpret_cast(this->d->m_buffer.data()) + + this->d->m_caps.lineOffset(plane, y); } QImage AkVideoPacket::toImage() const @@ -201,11 +437,11 @@ QImage image(this->d->m_caps.width(), this->d->m_caps.height(), AkImageToFormat->key(this->d->m_caps.format())); - auto size = qMin(size_t(this->buffer().size()), + auto size = qMin(size_t(this->d->m_buffer.size()), size_t(image.bytesPerLine()) * size_t(image.height())); if (size > 0) - memcpy(image.bits(), this->buffer().constData(), size); + memcpy(image.bits(), this->d->m_buffer.constData(), size); if (this->d->m_caps.format() == AkVideoCaps::Format_gray) for (int i = 0; i < 256; i++) @@ -220,85 +456,111 @@ if (!AkImageToFormat->contains(image.format())) return AkVideoPacket(); - size_t imageSize = size_t(image.bytesPerLine()) * size_t(image.height()); - QByteArray oBuffer(int(imageSize), 0); - memcpy(oBuffer.data(), image.constBits(), imageSize); - - AkVideoPacket packet = defaultPacket; - packet.caps().format() = AkImageToFormat->value(image.format()); - packet.caps().bpp() = AkVideoCaps::bitsPerPixel(packet.caps().format()); - packet.caps().width() = image.width(); - packet.caps().height() = image.height(); - packet.setBuffer(oBuffer); + auto imageSize = image.bytesPerLine() * image.height(); + QByteArray oBuffer(imageSize, Qt::Uninitialized); + memcpy(oBuffer.data(), image.constBits(), size_t(imageSize)); + + AkVideoPacket packet; + packet.d->m_caps = {AkImageToFormat->value(image.format()), + image.width(), + image.height(), + defaultPacket.caps().fps()}; + packet.d->m_buffer = oBuffer; + packet.copyMetadata(defaultPacket); return packet; } -AkVideoPacket AkVideoPacket::roundSizeTo(int align) const +bool AkVideoPacket::canConvert(AkVideoCaps::PixelFormat input, + AkVideoCaps::PixelFormat output) { - /* Explanation: - * - * When 'align' is a power of 2, the left most bit will be 1 (the pivot), - * while all other bits be 0, if destination width is multiple of 'align' - * all bits after pivot position will be 0, then we create a mask - * substracting 1 to the align, so all bits after pivot position in the - * mask will 1. - * Then we negate all bits in the mask so all bits from pivot to the left - * will be 1, and then we use that mask to get a width multiple of align. - * This give us the lower (floor) width nearest to the original 'width' and - * multiple of align. To get the rounded nearest value we add align / 2 to - * 'width'. - * This is the equivalent of: - * - * align * round(width / align) - */ - int width = (this->d->m_caps.width() + (align >> 1)) & ~(align - 1); - - /* Find the nearest width: - * - * round(height * owidth / width) - */ - int height = (2 * this->d->m_caps.height() * width - + this->d->m_caps.width()) - / (2 * this->d->m_caps.width()); + if (input == output) + return true; - if (this->d->m_caps.width() == width - && this->d->m_caps.height() == height) - return *this; + for (auto &convert: *videoConvert) + if (convert.from == input + && convert.to == output) { + return true; + } - auto frame = this->toImage(); + auto values = AkImageToFormat->values(); - if (frame.isNull()) - return *this; + if (values.contains(input) && values.contains(output)) + return true; + + return false; +} - return AkVideoPacket::fromImage(frame.scaled(width, height), *this); +bool AkVideoPacket::canConvert(AkVideoCaps::PixelFormat output) const +{ + return AkVideoPacket::canConvert(this->d->m_caps.format(), output); +} + +AkVideoPacket AkVideoPacket::convert(AkVideoCaps::PixelFormat format) const +{ + return this->convert(format, this->d->m_caps.align()); } AkVideoPacket AkVideoPacket::convert(AkVideoCaps::PixelFormat format, - const QSize &size) const + int align) const { - if (!AkImageToFormat->values().contains(format)) - return AkVideoPacket(); + if (this->d->m_caps.format() == format) { + if (this->d->m_caps.align() != align) + return this->realign(align); - if (this->d->m_caps.format() == format - && (size.isEmpty() || this->d->m_caps.size() == size)) return *this; + } + + for (auto &convert: *videoConvert) + if (convert.from == this->d->m_caps.format() + && convert.to == format) { + return convert.convert(this, align); + } + + if (!AkImageToFormat->values().contains(format)) + return {}; auto frame = this->toImage(); if (frame.isNull()) return *this; - QImage convertedFrame; - - if (size.isEmpty()) - convertedFrame = frame.convertToFormat(AkImageToFormat->key(format)); - else - convertedFrame = frame.convertToFormat(AkImageToFormat->key(format)).scaled(size); + auto convertedFrame = frame.convertToFormat(AkImageToFormat->key(format)); return AkVideoPacket::fromImage(convertedFrame, *this); } +AkVideoPacket AkVideoPacket::scaled(int width, int height) const +{ + return AkVideoPacket::fromImage(this->toImage().scaled(width, height), + *this); +} + +AkVideoPacket AkVideoPacket::realign(int align) const +{ + if (this->d->m_caps.align() == align) + return *this; + + auto caps = this->d->m_caps; + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*this); + auto height = caps.height(); + + for (int plane = 0; plane < caps.planes(); plane++) { + auto bypl = qMin(caps.bytesPerLine(plane), + this->d->m_caps.bytesPerLine(plane)); + + for (int y = 0; y < height; y++) { + auto src_line = this->constLine(plane, y); + auto dst_line = dst.line(plane, y); + memcpy(dst_line, src_line, bypl); + } + } + + return dst; +} + void AkVideoPacket::setCaps(const AkVideoCaps &caps) { if (this->d->m_caps == caps) @@ -308,16 +570,1081 @@ emit this->capsChanged(caps); } +void AkVideoPacket::setBuffer(const QByteArray &buffer) +{ + if (this->d->m_buffer == buffer) + return; + + this->d->m_buffer = buffer; + emit this->bufferChanged(buffer); +} + +void AkVideoPacket::setId(qint64 id) +{ + if (this->d->m_id == id) + return; + + this->d->m_id = id; + emit this->idChanged(id); +} + +void AkVideoPacket::setPts(qint64 pts) +{ + if (this->d->m_pts == pts) + return; + + this->d->m_pts = pts; + emit this->ptsChanged(pts); +} + +void AkVideoPacket::setTimeBase(const AkFrac &timeBase) +{ + if (this->d->m_timeBase == timeBase) + return; + + this->d->m_timeBase = timeBase; + emit this->timeBaseChanged(timeBase); +} + +void AkVideoPacket::setIndex(int index) +{ + if (this->d->m_index == index) + return; + + this->d->m_index = index; + emit this->indexChanged(index); +} + void AkVideoPacket::resetCaps() { this->setCaps(AkVideoCaps()); } +void AkVideoPacket::resetBuffer() +{ + this->setBuffer({}); +} + +void AkVideoPacket::resetId() +{ + this->setId(-1); +} + +void AkVideoPacket::resetPts() +{ + this->setPts(0); +} + +void AkVideoPacket::resetTimeBase() +{ + this->setTimeBase({}); +} + +void AkVideoPacket::resetIndex() +{ + this->setIndex(-1); +} + QDebug operator <<(QDebug debug, const AkVideoPacket &packet) { - debug.nospace() << packet.toString().toStdString().c_str(); + debug.nospace() << "AkVideoPacket(" + << "caps=" + << packet.caps() + << ",bufferSize=" + << packet.buffer().size() + << ",id=" + << packet.id() + << ",pts=" + << packet.pts() + << "(" + << packet.pts() * packet.timeBase().value() + << ")" + << ",timeBase=" + << packet.timeBase() + << ",index=" + << packet.index() + << ")"; return debug.space(); } +uint8_t AkVideoPacketPrivate::rgb_y(int r, int g, int b) +{ + return uint8_t(((66 * r + 129 * g + 25 * b + 128) >> 8) + 16); +} + +uint8_t AkVideoPacketPrivate::rgb_u(int r, int g, int b) +{ + return uint8_t(((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128); +} + +uint8_t AkVideoPacketPrivate::rgb_v(int r, int g, int b) +{ + return uint8_t(((112 * r - 94 * g - 18 * b + 128) >> 8) + 128); +} + +uint8_t AkVideoPacketPrivate::yuv_r(int y, int u, int v) +{ + Q_UNUSED(u) + int r = (298 * (y - 16) + 409 * (v - 128) + 128) >> 8; + + return uint8_t(qBound(0, r, 255)); +} + +uint8_t AkVideoPacketPrivate::yuv_g(int y, int u, int v) +{ + int g = (298 * (y - 16) - 100 * (u - 128) - 208 * (v - 128) + 128) >> 8; + + return uint8_t(qBound(0, g, 255)); +} + +uint8_t AkVideoPacketPrivate::yuv_b(int y, int u, int v) +{ + Q_UNUSED(v) + int b = (298 * (y - 16) + 516 * (u - 128) + 128) >> 8; + + return uint8_t(qBound(0, b, 255)); +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_0rgb(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_0rgb); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].x = 255; + dst_line[x].r = src_line[x].r; + dst_line[x].g = src_line[x].g; + dst_line[x].b = src_line[x].b; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].r; + dst_line[x].g = src_line[x].g; + dst_line[x].b = src_line[x].b; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_rgb565le(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb565le); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].r >> 3; + dst_line[x].g = src_line[x].g >> 2; + dst_line[x].b = src_line[x].b >> 3; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_rgb555le(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb555le); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].x = 1; + dst_line[x].r = src_line[x].r >> 3; + dst_line[x].g = src_line[x].g >> 3; + dst_line[x].b = src_line[x].b >> 3; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_0bgr(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_0bgr); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].x = 255; + dst_line[x].r = src_line[x].r; + dst_line[x].g = src_line[x].g; + dst_line[x].b = src_line[x].b; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_bgr565le(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_bgr565le); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].r >> 3; + dst_line[x].g = src_line[x].g >> 2; + dst_line[x].b = src_line[x].b >> 3; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_bgr555le(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_bgr555le); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].x = 1; + dst_line[x].r = src_line[x].r >> 3; + dst_line[x].g = src_line[x].g >> 3; + dst_line[x].b = src_line[x].b >> 3; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_uyvy422(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_uyvy422); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r0 = src_line[x].r; + auto g0 = src_line[x].g; + auto b0 = src_line[x].b; + + x++; + + int r1 = src_line[x].r; + int g1 = src_line[x].g; + int b1 = src_line[x].b; + + dst_line[x_yuv].u0 = rgb_u(r0, g0, b0); + dst_line[x_yuv].y0 = rgb_y(r0, g0, b0); + dst_line[x_yuv].v0 = rgb_v(r0, g0, b0); + dst_line[x_yuv].y1 = rgb_y(r1, g1, b1); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_yuyv422(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_yuyv422); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r0 = src_line[x].r; + auto g0 = src_line[x].g; + auto b0 = src_line[x].b; + + x++; + + auto r1 = src_line[x].r; + auto g1 = src_line[x].g; + auto b1 = src_line[x].b; + + dst_line[x_yuv].y0 = rgb_y(r0, g0, b0); + dst_line[x_yuv].u0 = rgb_u(r0, g0, b0); + dst_line[x_yuv].y1 = rgb_y(r1, g1, b1); + dst_line[x_yuv].v0 = rgb_v(r0, g0, b0); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_nv12(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_nv12); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line_y = dst.line(0, y); + auto dst_line_vu = reinterpret_cast(dst.line(1, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r = src_line[x].r; + auto g = src_line[x].g; + auto b = src_line[x].b; + + dst_line_y[y] = rgb_y(r, g, b); + dst_line_vu[x_yuv].v = rgb_v(r, g, b); + dst_line_vu[x_yuv].u = rgb_u(r, g, b); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::bgr24_to_nv21(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_nv21); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line_y = dst.line(0, y); + auto dst_line_uv = reinterpret_cast(dst.line(1, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r = src_line[x].r; + auto g = src_line[x].g; + auto b = src_line[x].b; + + dst_line_y[y] = rgb_y(r, g, b); + dst_line_uv[x_yuv].v = rgb_v(r, g, b); + dst_line_uv[x_yuv].u = rgb_u(r, g, b); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_0rgb(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_0rgb); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].x = 255; + dst_line[x].r = src_line[x].r; + dst_line[x].g = src_line[x].g; + dst_line[x].b = src_line[x].b; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_rgb565le(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb565le); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].r >> 3; + dst_line[x].g = src_line[x].g >> 2; + dst_line[x].b = src_line[x].b >> 3; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_rgb555le(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb555le); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].x = 1; + dst_line[x].r = src_line[x].r >> 3; + dst_line[x].g = src_line[x].g >> 3; + dst_line[x].b = src_line[x].b >> 3; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_0bgr(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_0bgr); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].x = 255; + dst_line[x].r = src_line[x].r; + dst_line[x].g = src_line[x].g; + dst_line[x].b = src_line[x].b; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_bgr24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_bgr24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].r; + dst_line[x].g = src_line[x].g; + dst_line[x].b = src_line[x].b; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_bgr565le(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_bgr565le); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].r >> 3; + dst_line[x].g = src_line[x].g >> 2; + dst_line[x].b = src_line[x].b >> 3; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_bgr555le(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_bgr555le); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].x = 1; + dst_line[x].r = src_line[x].r >> 3; + dst_line[x].g = src_line[x].g >> 3; + dst_line[x].b = src_line[x].b >> 3; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_uyvy422(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_uyvy422); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r0 = src_line[x].r; + auto g0 = src_line[x].g; + auto b0 = src_line[x].b; + + x++; + + int r1 = src_line[x].r; + int g1 = src_line[x].g; + int b1 = src_line[x].b; + + dst_line[x_yuv].u0 = rgb_u(r0, g0, b0); + dst_line[x_yuv].y0 = rgb_y(r0, g0, b0); + dst_line[x_yuv].v0 = rgb_v(r0, g0, b0); + dst_line[x_yuv].y1 = rgb_y(r1, g1, b1); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_yuyv422(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_yuyv422); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r0 = src_line[x].r; + auto g0 = src_line[x].g; + auto b0 = src_line[x].b; + + x++; + + auto r1 = src_line[x].r; + auto g1 = src_line[x].g; + auto b1 = src_line[x].b; + + dst_line[x_yuv].y0 = rgb_y(r0, g0, b0); + dst_line[x_yuv].u0 = rgb_u(r0, g0, b0); + dst_line[x_yuv].y1 = rgb_y(r1, g1, b1); + dst_line[x_yuv].v0 = rgb_v(r0, g0, b0); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_nv12(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_nv12); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line_y = dst.line(0, y); + auto dst_line_vu = reinterpret_cast(dst.line(1, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r = src_line[x].r; + auto g = src_line[x].g; + auto b = src_line[x].b; + + dst_line_y[y] = rgb_y(r, g, b); + dst_line_vu[x_yuv].v = rgb_v(r, g, b); + dst_line_vu[x_yuv].u = rgb_u(r, g, b); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_nv21(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_nv21); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line_y = dst.line(0, y); + auto dst_line_uv = reinterpret_cast(dst.line(1, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r = src_line[x].r; + auto g = src_line[x].g; + auto b = src_line[x].b; + + dst_line_y[y] = rgb_y(r, g, b); + dst_line_uv[x_yuv].v = rgb_v(r, g, b); + dst_line_uv[x_yuv].u = rgb_u(r, g, b); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb24_to_yuv420p(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_yuv420p); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line_y = reinterpret_cast(dst.line(0, y)); + auto dst_line_v = reinterpret_cast(dst.line(1, y)); + auto dst_line_u = reinterpret_cast(dst.line(2, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto r = src_line[x].r; + auto g = src_line[x].g; + auto b = src_line[x].b; + + dst_line_y[x] = rgb_y(r, g, b); + dst_line_u[x_yuv] = rgb_u(r, g, b); + dst_line_v[x_yuv] = rgb_v(r, g, b); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgba_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].x * src_line[x].r / 255; + dst_line[x].g = src_line[x].x * src_line[x].g / 255; + dst_line[x].b = src_line[x].x * src_line[x].b / 255; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgb0_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].r; + dst_line[x].g = src_line[x].g; + dst_line[x].b = src_line[x].b; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::yuyv422_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto y0 = src_line[x_yuv].y0; + auto u0 = src_line[x_yuv].u0; + auto y1 = src_line[x_yuv].y1; + auto v0 = src_line[x_yuv].v0; + + dst_line[x].r = yuv_r(y0, u0, v0); + dst_line[x].g = yuv_g(y0, u0, v0); + dst_line[x].b = yuv_b(y0, u0, v0); + + x++; + + dst_line[x].r = yuv_r(y1, u0, v0); + dst_line[x].g = yuv_g(y1, u0, v0); + dst_line[x].b = yuv_b(y1, u0, v0); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::yuv420p_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line_y = reinterpret_cast(src->constLine(0, y)); + auto src_line_v = reinterpret_cast(src->constLine(1, y)); + auto src_line_u = reinterpret_cast(src->constLine(2, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto y = src_line_y[x]; + auto u = src_line_u[x_yuv]; + auto v = src_line_v[x_yuv]; + + dst_line[x].r = yuv_r(y, u, v); + dst_line[x].g = yuv_g(y, u, v); + dst_line[x].b = yuv_b(y, u, v); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::yvu420p_to_rgb24(const AkVideoPacket *src, int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line_y = reinterpret_cast(src->constLine(0, y)); + auto src_line_u = reinterpret_cast(src->constLine(1, y)); + auto src_line_v = reinterpret_cast(src->constLine(2, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto y = src_line_y[x]; + auto u = src_line_u[x_yuv]; + auto v = src_line_v[x_yuv]; + + dst_line[x].r = yuv_r(y, u, v); + dst_line[x].g = yuv_g(y, u, v); + dst_line[x].b = yuv_b(y, u, v); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::nv12_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line_y = src->constLine(0, y); + auto src_line_vu = reinterpret_cast(src->constLine(1, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto y = src_line_y[x]; + auto u = src_line_vu[x_yuv].u; + auto v = src_line_vu[x_yuv].v; + + dst_line[x].r = yuv_r(y, u, v); + dst_line[x].g = yuv_g(y, u, v); + dst_line[x].b = yuv_b(y, u, v); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::nv21_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line_y = src->constLine(0, y); + auto src_line_uv = reinterpret_cast(src->constLine(1, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + auto x_yuv = x / 2; + + auto y = src_line_y[x]; + auto u = src_line_uv[x_yuv].u; + auto v = src_line_uv[x_yuv].v; + + dst_line[x].r = yuv_r(y, u, v); + dst_line[x].g = yuv_g(y, u, v); + dst_line[x].b = yuv_b(y, u, v); + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::rgbap_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line_r = reinterpret_cast(src->constLine(0, y)); + auto src_line_g = reinterpret_cast(src->constLine(1, y)); + auto src_line_b = reinterpret_cast(src->constLine(2, y)); + auto src_line_a = reinterpret_cast(src->constLine(3, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line_a[x] * src_line_r[x] / 255; + dst_line[x].g = src_line_a[x] * src_line_g[x] / 255; + dst_line[x].b = src_line_a[x] * src_line_b[x] / 255; + } + } + + return dst; +} + +AkVideoPacket AkVideoPacketPrivate::_0bgr_to_rgb24(const AkVideoPacket *src, + int align) +{ + auto caps = src->caps(); + caps.setFormat(AkVideoCaps::Format_rgb24); + caps.setAlign(align); + AkVideoPacket dst(caps); + dst.copyMetadata(*src); + auto width = src->caps().width(); + auto height = src->caps().height(); + + for (int y = 0; y < height; y++) { + auto src_line = reinterpret_cast(src->constLine(0, y)); + auto dst_line = reinterpret_cast(dst.line(0, y)); + + for (int x = 0; x < width; x++) { + dst_line[x].r = src_line[x].x * src_line[x].r / 255; + dst_line[x].g = src_line[x].x * src_line[x].g / 255; + dst_line[x].b = src_line[x].x * src_line[x].b / 255; + } + } + + return dst; +} + #include "moc_akvideopacket.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akvideopacket.h webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akvideopacket.h --- webcamoid-8.6.1+dfsg/libAvKys/Lib/src/akvideopacket.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Lib/src/akvideopacket.h 2021-02-15 15:25:23.000000000 +0000 @@ -20,15 +20,12 @@ #ifndef AKVIDEOPACKET_H #define AKVIDEOPACKET_H -#include - -#include "akpacket.h" #include "akvideocaps.h" class AkVideoPacketPrivate; -class AkVideoCaps; +class AkPacket; -class AKCOMMONS_EXPORT AkVideoPacket: public AkPacket +class AKCOMMONS_EXPORT AkVideoPacket: public QObject { Q_OBJECT Q_PROPERTY(AkVideoCaps caps @@ -36,47 +33,98 @@ WRITE setCaps RESET resetCaps NOTIFY capsChanged) + Q_PROPERTY(QByteArray buffer + READ buffer + WRITE setBuffer + RESET resetBuffer + NOTIFY bufferChanged) + Q_PROPERTY(qint64 id + READ id + WRITE setId + RESET resetId + NOTIFY idChanged) + Q_PROPERTY(qint64 pts + READ pts + WRITE setPts + RESET resetPts + NOTIFY ptsChanged) + Q_PROPERTY(AkFrac timeBase + READ timeBase + WRITE setTimeBase + RESET resetTimeBase + NOTIFY timeBaseChanged) + Q_PROPERTY(int index + READ index + WRITE setIndex + RESET resetIndex + NOTIFY indexChanged) public: AkVideoPacket(QObject *parent=nullptr); - AkVideoPacket(const AkVideoCaps &caps, - const QByteArray &buffer=QByteArray(), - qint64 pts=0, - const AkFrac &timeBase=AkFrac(), - int index=-1, - qint64 id=-1); + AkVideoPacket(const AkVideoCaps &caps); AkVideoPacket(const AkPacket &other); AkVideoPacket(const AkVideoPacket &other); ~AkVideoPacket(); AkVideoPacket &operator =(const AkPacket &other); AkVideoPacket &operator =(const AkVideoPacket &other); operator bool() const; + operator AkPacket() const; Q_INVOKABLE AkVideoCaps caps() const; Q_INVOKABLE AkVideoCaps &caps(); - Q_INVOKABLE QString toString() const; - Q_INVOKABLE AkPacket toPacket() const; + Q_INVOKABLE QByteArray buffer() const; + Q_INVOKABLE QByteArray &buffer(); + Q_INVOKABLE qint64 id() const; + Q_INVOKABLE qint64 &id(); + Q_INVOKABLE qint64 pts() const; + Q_INVOKABLE qint64 &pts(); + Q_INVOKABLE AkFrac timeBase() const; + Q_INVOKABLE AkFrac &timeBase(); + Q_INVOKABLE int index() const; + Q_INVOKABLE int &index(); + Q_INVOKABLE void copyMetadata(const AkVideoPacket &other); + + Q_INVOKABLE const quint8 *constLine(int plane, int y) const; + Q_INVOKABLE quint8 *line(int plane, int y); Q_INVOKABLE QImage toImage() const; Q_INVOKABLE static AkVideoPacket fromImage(const QImage &image, const AkVideoPacket &defaultPacket); - Q_INVOKABLE AkVideoPacket roundSizeTo(int align) const; + Q_INVOKABLE static bool canConvert(AkVideoCaps::PixelFormat input, + AkVideoCaps::PixelFormat output); + Q_INVOKABLE bool canConvert(AkVideoCaps::PixelFormat output) const; + Q_INVOKABLE AkVideoPacket convert(AkVideoCaps::PixelFormat format) const; Q_INVOKABLE AkVideoPacket convert(AkVideoCaps::PixelFormat format, - const QSize &size={}) const; + int align) const; + Q_INVOKABLE AkVideoPacket scaled(int width, int height) const; + Q_INVOKABLE AkVideoPacket realign(int align) const; private: AkVideoPacketPrivate *d; Q_SIGNALS: void capsChanged(const AkVideoCaps &caps); + void bufferChanged(const QByteArray &buffer); + void idChanged(qint64 id); + void ptsChanged(qint64 pts); + void timeBaseChanged(const AkFrac &timeBase); + void indexChanged(int index); public Q_SLOTS: void setCaps(const AkVideoCaps &caps); + void setBuffer(const QByteArray &buffer); + void setId(qint64 id); + void setPts(qint64 pts); + void setTimeBase(const AkFrac &timeBase); + void setIndex(int index); void resetCaps(); - - friend QDebug operator <<(QDebug debug, const AkVideoPacket &packet); + void resetBuffer(); + void resetId(); + void resetPts(); + void resetTimeBase(); + void resetIndex(); }; -QDebug operator <<(QDebug debug, const AkVideoPacket &packet); +AKCOMMONS_EXPORT QDebug operator <<(QDebug debug, const AkVideoPacket &packet); Q_DECLARE_METATYPE(AkVideoPacket) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/libAvKys.pro webcamoid-8.8.0+dfsg/libAvKys/libAvKys.pro --- webcamoid-8.6.1+dfsg/libAvKys/libAvKys.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/libAvKys.pro 2021-02-15 15:25:23.000000000 +0000 @@ -77,18 +77,16 @@ } isEmpty(NOMEDIAFOUNDATION): qtCompileTest(mediafoundation) - -isEmpty(NOOSS) { - cache(INCLUDEDIR) - qtCompileTest(oss) -} - +isEmpty(NONDKAUDIO): qtCompileTest(ndk_audio) +isEmpty(NONDKCAMERA): qtCompileTest(ndk_camera) +isEmpty(NONDKMEDIA): qtCompileTest(ndk_media) +isEmpty(NOOPENSL): qtCompileTest(opensl) isEmpty(NOPULSEAUDIO): qtCompileTest(pulseaudio) -isEmpty(NOQTAUDIO): qtCompileTest(qtaudio) -isEmpty(NOV4L2) { +isEmpty(NOV4L2): !android { qtCompileTest(v4l2) CONFIG(config_v4l2): qtCompileTest(v4l2_extendedcontrols) + CONFIG(config_v4l2): qtCompileTest(v4l2_extraformats) isEmpty(NOV4LUTILS): CONFIG(config_v4l2): qtCompileTest(v4lutils) } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/ACapsConvert.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/ACapsConvert.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/ACapsConvert.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/ACapsConvert.pro 2021-02-15 15:25:23.000000000 +0000 @@ -20,7 +20,7 @@ CONFIG(debug, debug|release): CONFIG += ordered -SUBDIRS = src +SUBDIRS = src src/generic CONFIG(config_ffmpeg_avresample): SUBDIRS += src/ffmpegav CONFIG(config_ffmpeg_swresample): SUBDIRS += src/ffmpegsw CONFIG(config_gstreamer): SUBDIRS += src/gstreamer diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvert.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvert.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvert.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvert.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include "acapsconvert.h" #include "acapsconvertelement.h" +#include "acapsconvertelementsettings.h" QObject *ACapsConvert::create(const QString &key, const QString &specification) { @@ -26,13 +27,16 @@ if (key == AK_PLUGIN_TYPE_ELEMENT) return new ACapsConvertElement(); + else if (key == AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + return new ACapsConvertElementSettings(); return nullptr; } QStringList ACapsConvert::keys() const { - return QStringList(); + return {AK_PLUGIN_TYPE_ELEMENT, + AK_PLUGIN_TYPE_ELEMENT_SETTINGS}; } #include "moc_acapsconvert.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -24,11 +24,9 @@ #include #include "acapsconvertelement.h" -#include "acapsconvertglobals.h" +#include "acapsconvertelementsettings.h" #include "convertaudio.h" -Q_GLOBAL_STATIC(ACapsConvertGlobals, globalACapsConvert) - template inline QSharedPointer ptr_cast(QObject *obj=nullptr) { @@ -40,26 +38,27 @@ class ACapsConvertElementPrivate { public: - AkCaps m_caps; + ACapsConvertElement *self; + ACapsConvertElementSettings m_settings; + AkAudioCaps m_caps; ConvertAudioPtr m_convertAudio; QMutex m_mutex; + + explicit ACapsConvertElementPrivate(ACapsConvertElement *self); + void convertLibUpdated(const QString &convertLib); }; ACapsConvertElement::ACapsConvertElement(): AkElement() { - this->d = new ACapsConvertElementPrivate; - - QObject::connect(globalACapsConvert, - SIGNAL(convertLibChanged(const QString &)), - this, - SIGNAL(convertLibChanged(const QString &))); - QObject::connect(globalACapsConvert, - SIGNAL(convertLibChanged(const QString &)), - this, - SLOT(convertLibUpdated(const QString &))); + this->d = new ACapsConvertElementPrivate(this); + QObject::connect(&this->d->m_settings, + &ACapsConvertElementSettings::convertLibChanged, + [this] (const QString &convertLib) { + this->d->convertLibUpdated(convertLib); + }); - this->convertLibUpdated(globalACapsConvert->convertLib()); + this->d->convertLibUpdated(this->d->m_settings.convertLib()); } ACapsConvertElement::~ACapsConvertElement() @@ -67,17 +66,26 @@ delete this->d; } -QString ACapsConvertElement::caps() const +AkAudioCaps ACapsConvertElement::caps() const { - return this->d->m_caps.toString(); + return this->d->m_caps; } -QString ACapsConvertElement::convertLib() const +AkPacket ACapsConvertElement::iAudioStream(const AkAudioPacket &packet) { - return globalACapsConvert->convertLib(); + AkPacket oPacket; + + this->d->m_mutex.lock(); + + if (this->d->m_convertAudio) + oPacket = this->d->m_convertAudio->convert(packet); + + this->d->m_mutex.unlock(); + + akSend(oPacket) } -void ACapsConvertElement::setCaps(const QString &caps) +void ACapsConvertElement::setCaps(const AkAudioCaps &caps) { if (this->d->m_caps == caps) return; @@ -86,33 +94,9 @@ emit this->capsChanged(caps); } -void ACapsConvertElement::setConvertLib(const QString &convertLib) -{ - globalACapsConvert->setConvertLib(convertLib); -} - void ACapsConvertElement::resetCaps() { - this->setCaps(""); -} - -void ACapsConvertElement::resetConvertLib() -{ - globalACapsConvert->resetConvertLib(); -} - -AkPacket ACapsConvertElement::iStream(const AkAudioPacket &packet) -{ - AkPacket oPacket; - - this->d->m_mutex.lock(); - - if (this->d->m_convertAudio) - oPacket = this->d->m_convertAudio->convert(packet); - - this->d->m_mutex.unlock(); - - akSend(oPacket) + this->setCaps({}); } bool ACapsConvertElement::setState(AkElement::ElementState state) @@ -171,19 +155,24 @@ return false; } -void ACapsConvertElement::convertLibUpdated(const QString &convertLib) +ACapsConvertElementPrivate::ACapsConvertElementPrivate(ACapsConvertElement *self): + self(self) { - auto state = this->state(); - this->setState(AkElement::ElementStateNull); - this->d->m_mutex.lock(); +} + +void ACapsConvertElementPrivate::convertLibUpdated(const QString &convertLib) +{ + auto state = self->state(); + self->setState(AkElement::ElementStateNull); - this->d->m_convertAudio = + this->m_mutex.lock(); + this->m_convertAudio = ptr_cast(ACapsConvertElement::loadSubModule("ACapsConvert", convertLib)); - this->d->m_mutex.unlock(); + this->m_mutex.unlock(); - this->setState(state); + self->setState(state); } #include "moc_acapsconvertelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -23,47 +23,37 @@ #include class ACapsConvertElementPrivate; -class AkCaps; +class AkAudioCaps; class ACapsConvertElement: public AkElement { Q_OBJECT - Q_PROPERTY(QString caps + Q_PROPERTY(AkAudioCaps caps READ caps WRITE setCaps RESET resetCaps NOTIFY capsChanged) - Q_PROPERTY(QString convertLib - READ convertLib - WRITE setConvertLib - RESET resetConvertLib - NOTIFY convertLibChanged) public: ACapsConvertElement(); ~ACapsConvertElement(); - Q_INVOKABLE QString caps() const; - Q_INVOKABLE QString convertLib() const; + Q_INVOKABLE AkAudioCaps caps() const; private: ACapsConvertElementPrivate *d; + protected: + AkPacket iAudioStream(const AkAudioPacket &packet); + signals: - void capsChanged(const QString &caps); - void convertLibChanged(const QString &convertLib); + void capsChanged(const AkAudioCaps &caps); public slots: - void setCaps(const QString &caps); - void setConvertLib(const QString &convertLib); + void setCaps(const AkAudioCaps &caps); void resetCaps(); - void resetConvertLib(); - AkPacket iStream(const AkAudioPacket &packet); bool setState(AkElement::ElementState state); - - private slots: - void convertLibUpdated(const QString &convertLib); }; #endif // ACAPSCONVERTELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelementsettings.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelementsettings.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelementsettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelementsettings.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,54 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "acapsconvertelementsettings.h" +#include "acapsconvertglobals.h" + +Q_GLOBAL_STATIC(ACapsConvertGlobals, globalACapsConvert) + +ACapsConvertElementSettings::ACapsConvertElementSettings(QObject *parent): + QObject(parent) +{ + QObject::connect(globalACapsConvert, + &ACapsConvertGlobals::convertLibChanged, + this, + &ACapsConvertElementSettings::convertLibChanged); +} + +QString ACapsConvertElementSettings::convertLib() const +{ + return globalACapsConvert->convertLib(); +} + +QStringList ACapsConvertElementSettings::subModules() const +{ + return globalACapsConvert->subModules(); +} + +void ACapsConvertElementSettings::setConvertLib(const QString &convertLib) +{ + globalACapsConvert->setConvertLib(convertLib); +} + +void ACapsConvertElementSettings::resetConvertLib() +{ + globalACapsConvert->resetConvertLib(); +} + +#include "moc_acapsconvertelementsettings.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelementsettings.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelementsettings.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelementsettings.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertelementsettings.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,52 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef ACAPSCONVERTELEMENTSETTINGS_H +#define ACAPSCONVERTELEMENTSETTINGS_H + +#include + +class ACapsConvertElementSettings: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString convertLib + READ convertLib + WRITE setConvertLib + RESET resetConvertLib + NOTIFY convertLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules + NOTIFY subModulesChanged) + + public: + ACapsConvertElementSettings(QObject *parent=nullptr); + + Q_INVOKABLE QString convertLib() const; + Q_INVOKABLE QStringList subModules() const; + + signals: + void convertLibChanged(const QString &convertLib); + void subModulesChanged(const QStringList &subModules); + + public slots: + void setConvertLib(const QString &convertLib); + void resetConvertLib(); +}; + +#endif // ACAPSCONVERTELEMENTSETTINGS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertglobals.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertglobals.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertglobals.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertglobals.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,29 +21,43 @@ #include "acapsconvertglobals.h" +class ACapsConvertGlobalsPrivate +{ + public: + QString m_convertLib; + QStringList m_preferredFramework; + + ACapsConvertGlobalsPrivate(); +}; + ACapsConvertGlobals::ACapsConvertGlobals(QObject *parent): QObject(parent) { - this->m_preferredFramework = QStringList { - "ffmpegsw", - "ffmpegav", - "gstreamer" - }; - + this->d = new ACapsConvertGlobalsPrivate; this->resetConvertLib(); } +ACapsConvertGlobals::~ACapsConvertGlobals() +{ + delete this->d; +} + QString ACapsConvertGlobals::convertLib() const { - return this->m_convertLib; + return this->d->m_convertLib; +} + +QStringList ACapsConvertGlobals::subModules() const +{ + return AkElement::listSubModules("ACapsConvert"); } void ACapsConvertGlobals::setConvertLib(const QString &convertLib) { - if (this->m_convertLib == convertLib) + if (this->d->m_convertLib == convertLib) return; - this->m_convertLib = convertLib; + this->d->m_convertLib = convertLib; emit this->convertLibChanged(convertLib); } @@ -51,15 +65,26 @@ { auto subModules = AkElement::listSubModules("ACapsConvert"); - for (auto &framework: this->m_preferredFramework) + for (auto &framework: this->d->m_preferredFramework) if (subModules.contains(framework)) { this->setConvertLib(framework); return; } - if (this->m_convertLib.isEmpty() && !subModules.isEmpty()) + if (this->d->m_convertLib.isEmpty() && !subModules.isEmpty()) this->setConvertLib(subModules.first()); else this->setConvertLib(""); } + +ACapsConvertGlobalsPrivate::ACapsConvertGlobalsPrivate() +{ + this->m_preferredFramework = QStringList { + "ffmpegsw", + "ffmpegav", + "gstreamer" + }; +} + +#include "moc_acapsconvertglobals.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertglobals.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertglobals.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertglobals.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/acapsconvertglobals.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,8 @@ #include +class ACapsConvertGlobalsPrivate; + class ACapsConvertGlobals: public QObject { Q_OBJECT @@ -30,15 +32,18 @@ WRITE setConvertLib RESET resetConvertLib NOTIFY convertLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules) public: ACapsConvertGlobals(QObject *parent=nullptr); + ~ACapsConvertGlobals(); Q_INVOKABLE QString convertLib() const; + Q_INVOKABLE QStringList subModules() const; private: - QString m_convertLib; - QStringList m_preferredFramework; + ACapsConvertGlobalsPrivate *d; signals: void convertLibChanged(const QString &convertLib); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegav/ffmpegav.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegav/ffmpegav.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegav/ffmpegav.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegav/ffmpegav.pro 2021-02-15 15:25:23.000000000 +0000 @@ -55,6 +55,9 @@ libavutil } +CONFIG(config_ffmpeg_avutil_sampleformat64): \ + DEFINES += HAVE_SAMPLEFORMAT64 + QT += qml SOURCES = \ diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegav/src/convertaudioffmpegav.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegav/src/convertaudioffmpegav.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegav/src/convertaudioffmpegav.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegav/src/convertaudioffmpegav.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,8 +19,9 @@ #include #include -#include +#include #include +#include #include extern "C" @@ -33,61 +34,77 @@ #include "convertaudioffmpegav.h" -typedef QMap ChannelLayoutsMap; - -inline ChannelLayoutsMap initChannelFormatsMap() -{ - ChannelLayoutsMap channelLayouts = { - {AkAudioCaps::Layout_mono , AV_CH_LAYOUT_MONO }, - {AkAudioCaps::Layout_stereo , AV_CH_LAYOUT_STEREO }, - {AkAudioCaps::Layout_2p1 , AV_CH_LAYOUT_2POINT1 }, - {AkAudioCaps::Layout_3p0 , AV_CH_LAYOUT_SURROUND }, - {AkAudioCaps::Layout_3p0_back , AV_CH_LAYOUT_2_1 }, - {AkAudioCaps::Layout_3p1 , AV_CH_LAYOUT_3POINT1 }, - {AkAudioCaps::Layout_4p0 , AV_CH_LAYOUT_4POINT0 }, - {AkAudioCaps::Layout_quad , AV_CH_LAYOUT_QUAD }, - {AkAudioCaps::Layout_quad_side , AV_CH_LAYOUT_2_2 }, - {AkAudioCaps::Layout_4p1 , AV_CH_LAYOUT_4POINT1 }, - {AkAudioCaps::Layout_5p0 , AV_CH_LAYOUT_5POINT0_BACK }, - {AkAudioCaps::Layout_5p0_side , AV_CH_LAYOUT_5POINT0 }, - {AkAudioCaps::Layout_5p1 , AV_CH_LAYOUT_5POINT1_BACK }, - {AkAudioCaps::Layout_5p1_side , AV_CH_LAYOUT_5POINT1 }, - {AkAudioCaps::Layout_6p0 , AV_CH_LAYOUT_6POINT0 }, - {AkAudioCaps::Layout_6p0_front , AV_CH_LAYOUT_6POINT0_FRONT }, - {AkAudioCaps::Layout_hexagonal , AV_CH_LAYOUT_HEXAGONAL }, - {AkAudioCaps::Layout_6p1 , AV_CH_LAYOUT_6POINT1 }, - {AkAudioCaps::Layout_6p1_back , AV_CH_LAYOUT_6POINT1_BACK }, - {AkAudioCaps::Layout_6p1_front , AV_CH_LAYOUT_6POINT1_FRONT }, - {AkAudioCaps::Layout_7p0 , AV_CH_LAYOUT_7POINT0 }, - {AkAudioCaps::Layout_7p0_front , AV_CH_LAYOUT_7POINT0_FRONT }, - {AkAudioCaps::Layout_7p1 , AV_CH_LAYOUT_7POINT1 }, - {AkAudioCaps::Layout_7p1_wide , AV_CH_LAYOUT_7POINT1_WIDE }, - {AkAudioCaps::Layout_7p1_wide_side, AV_CH_LAYOUT_7POINT1_WIDE_BACK}, - {AkAudioCaps::Layout_octagonal , AV_CH_LAYOUT_OCTAGONAL }, -#ifdef AV_CH_LAYOUT_HEXADECAGONAL - {AkAudioCaps::Layout_hexadecagonal, AV_CH_LAYOUT_HEXADECAGONAL }, -#endif - {AkAudioCaps::Layout_downmix , AV_CH_LAYOUT_STEREO_DOWNMIX }, - }; - - return channelLayouts; -} - -Q_GLOBAL_STATIC_WITH_ARGS(ChannelLayoutsMap, channelLayouts, (initChannelFormatsMap())) - +using SampleFormatsMap = QMap; +using ChannelLayoutsMap = QMap; class ConvertAudioFFmpegAVPrivate { public: AkAudioCaps m_caps; - AVAudioResampleContext *m_resampleContext; + AVAudioResampleContext *m_resampleContext {nullptr}; QMutex m_mutex; - bool m_contextIsOpen; + bool m_contextIsOpen {false}; - ConvertAudioFFmpegAVPrivate(): - m_resampleContext(nullptr), - m_contextIsOpen(false) + inline static const SampleFormatsMap &sampleFormats(bool planar) { + static const SampleFormatsMap formats = { + {AkAudioCaps::SampleFormat_u8 , AV_SAMPLE_FMT_U8 }, + {AkAudioCaps::SampleFormat_s16, AV_SAMPLE_FMT_S16}, + {AkAudioCaps::SampleFormat_s32, AV_SAMPLE_FMT_S32}, +#ifdef HAVE_SAMPLEFORMAT64 + {AkAudioCaps::SampleFormat_s64, AV_SAMPLE_FMT_S64 }, +#endif + {AkAudioCaps::SampleFormat_flt, AV_SAMPLE_FMT_FLT}, + {AkAudioCaps::SampleFormat_dbl, AV_SAMPLE_FMT_DBL}, + }; + static const SampleFormatsMap planarFormats = { + {AkAudioCaps::SampleFormat_u8 , AV_SAMPLE_FMT_U8P }, + {AkAudioCaps::SampleFormat_s16, AV_SAMPLE_FMT_S16P}, + {AkAudioCaps::SampleFormat_s32, AV_SAMPLE_FMT_S32P}, +#ifdef HAVE_SAMPLEFORMAT64 + {AkAudioCaps::SampleFormat_s64, AV_SAMPLE_FMT_S64P}, +#endif + {AkAudioCaps::SampleFormat_flt, AV_SAMPLE_FMT_FLTP}, + {AkAudioCaps::SampleFormat_dbl, AV_SAMPLE_FMT_DBLP}, + }; + + return planar? planarFormats: formats; + } + + inline static const ChannelLayoutsMap &channelLayouts() + { + static const ChannelLayoutsMap channelLayouts = { + {AkAudioCaps::Layout_mono , AV_CH_LAYOUT_MONO }, + {AkAudioCaps::Layout_stereo , AV_CH_LAYOUT_STEREO }, + {AkAudioCaps::Layout_2p1 , AV_CH_LAYOUT_2POINT1 }, + {AkAudioCaps::Layout_3p0 , AV_CH_LAYOUT_SURROUND }, + {AkAudioCaps::Layout_3p0_back , AV_CH_LAYOUT_2_1 }, + {AkAudioCaps::Layout_3p1 , AV_CH_LAYOUT_3POINT1 }, + {AkAudioCaps::Layout_4p0 , AV_CH_LAYOUT_4POINT0 }, + {AkAudioCaps::Layout_quad , AV_CH_LAYOUT_QUAD }, + {AkAudioCaps::Layout_quad_side , AV_CH_LAYOUT_2_2 }, + {AkAudioCaps::Layout_4p1 , AV_CH_LAYOUT_4POINT1 }, + {AkAudioCaps::Layout_5p0 , AV_CH_LAYOUT_5POINT0_BACK }, + {AkAudioCaps::Layout_5p0_side , AV_CH_LAYOUT_5POINT0 }, + {AkAudioCaps::Layout_5p1 , AV_CH_LAYOUT_5POINT1_BACK }, + {AkAudioCaps::Layout_5p1_side , AV_CH_LAYOUT_5POINT1 }, + {AkAudioCaps::Layout_6p0 , AV_CH_LAYOUT_6POINT0 }, + {AkAudioCaps::Layout_6p0_front , AV_CH_LAYOUT_6POINT0_FRONT }, + {AkAudioCaps::Layout_hexagonal , AV_CH_LAYOUT_HEXAGONAL }, + {AkAudioCaps::Layout_6p1 , AV_CH_LAYOUT_6POINT1 }, + {AkAudioCaps::Layout_6p1_back , AV_CH_LAYOUT_6POINT1_BACK }, + {AkAudioCaps::Layout_6p1_front , AV_CH_LAYOUT_6POINT1_FRONT }, + {AkAudioCaps::Layout_7p0 , AV_CH_LAYOUT_7POINT0 }, + {AkAudioCaps::Layout_7p0_front , AV_CH_LAYOUT_7POINT0_FRONT }, + {AkAudioCaps::Layout_7p1 , AV_CH_LAYOUT_7POINT1 }, + {AkAudioCaps::Layout_7p1_wide , AV_CH_LAYOUT_7POINT1_WIDE }, + {AkAudioCaps::Layout_7p1_wide_back, AV_CH_LAYOUT_7POINT1_WIDE_BACK}, + {AkAudioCaps::Layout_octagonal , AV_CH_LAYOUT_OCTAGONAL }, + {AkAudioCaps::Layout_hexadecagonal, AV_CH_LAYOUT_HEXADECAGONAL }, + {AkAudioCaps::Layout_downmix , AV_CH_LAYOUT_STEREO_DOWNMIX }, + }; + + return channelLayouts; } }; @@ -123,18 +140,20 @@ if (!this->d->m_caps || packet.buffer().size() < 1) return AkPacket(); - uint64_t iSampleLayout = channelLayouts->value(packet.caps().layout(), 0); + uint64_t iSampleLayout = + ConvertAudioFFmpegAVPrivate::channelLayouts().value(packet.caps().layout(), 0); AVSampleFormat iSampleFormat = - av_get_sample_fmt(AkAudioCaps::sampleFormatToString(packet.caps().format()) - .toStdString().c_str()); + ConvertAudioFFmpegAVPrivate::sampleFormats(packet.caps().planar()) + .value(packet.caps().format(), AV_SAMPLE_FMT_NONE); int iSampleRate = packet.caps().rate(); int iNChannels = packet.caps().channels(); int iNSamples = packet.caps().samples(); - uint64_t oSampleLayout = channelLayouts->value(this->d->m_caps.layout(), - AV_CH_LAYOUT_STEREO); + uint64_t oSampleLayout = + ConvertAudioFFmpegAVPrivate::channelLayouts().value(this->d->m_caps.layout(), + AV_CH_LAYOUT_STEREO); AVSampleFormat oSampleFormat = av_get_sample_fmt(AkAudioCaps::sampleFormatToString(this->d->m_caps.format()) @@ -156,17 +175,19 @@ iNChannels, iFrame.nb_samples, iSampleFormat, - packet.caps().align()); + 1); if (iFrameSize < 1) return AkPacket(); + auto tmpPacket = packet.realign(1); + if (avcodec_fill_audio_frame(&iFrame, iNChannels, iSampleFormat, - reinterpret_cast(packet.buffer().constData()), - packet.buffer().size(), - packet.caps().align()) < 0) { + reinterpret_cast(tmpPacket.buffer().constData()), + tmpPacket.buffer().size(), + 1) < 0) { return AkPacket(); } @@ -263,15 +284,15 @@ AkAudioPacket oAudioPacket; oAudioPacket.caps() = this->d->m_caps; - oAudioPacket.caps().samples() = oFrame.nb_samples; - oAudioPacket.caps().align() = 1; + oAudioPacket.caps().setSamples(oFrame.nb_samples); + oAudioPacket.buffer() = oBuffer; oAudioPacket.pts() = oFrame.pts; oAudioPacket.timeBase() = AkFrac(1, this->d->m_caps.rate()); oAudioPacket.index() = packet.index(); oAudioPacket.id() = packet.id(); - return oAudioPacket.toPacket(); + return oAudioPacket; } void ConvertAudioFFmpegAV::uninit() diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegsw/ffmpegsw.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegsw/ffmpegsw.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegsw/ffmpegsw.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegsw/ffmpegsw.pro 2021-02-15 15:25:23.000000000 +0000 @@ -55,6 +55,9 @@ libavutil } +CONFIG(config_ffmpeg_avutil_sampleformat64): \ + DEFINES += HAVE_SAMPLEFORMAT64 + QT += qml SOURCES = \ diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegsw/src/convertaudioffmpegsw.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegsw/src/convertaudioffmpegsw.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegsw/src/convertaudioffmpegsw.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/ffmpegsw/src/convertaudioffmpegsw.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,8 +19,9 @@ #include #include -#include +#include #include +#include #include extern "C" @@ -32,52 +33,77 @@ #include "convertaudioffmpegsw.h" +using SampleFormatsMap = QMap; using ChannelLayoutsMap = QMap; -inline ChannelLayoutsMap initChannelFormatsMap() -{ - ChannelLayoutsMap channelLayouts = { - {AkAudioCaps::Layout_mono , AV_CH_LAYOUT_MONO }, - {AkAudioCaps::Layout_stereo , AV_CH_LAYOUT_STEREO }, - {AkAudioCaps::Layout_2p1 , AV_CH_LAYOUT_2POINT1 }, - {AkAudioCaps::Layout_3p0 , AV_CH_LAYOUT_SURROUND }, - {AkAudioCaps::Layout_3p0_back , AV_CH_LAYOUT_2_1 }, - {AkAudioCaps::Layout_3p1 , AV_CH_LAYOUT_3POINT1 }, - {AkAudioCaps::Layout_4p0 , AV_CH_LAYOUT_4POINT0 }, - {AkAudioCaps::Layout_quad , AV_CH_LAYOUT_QUAD }, - {AkAudioCaps::Layout_quad_side , AV_CH_LAYOUT_2_2 }, - {AkAudioCaps::Layout_4p1 , AV_CH_LAYOUT_4POINT1 }, - {AkAudioCaps::Layout_5p0 , AV_CH_LAYOUT_5POINT0_BACK }, - {AkAudioCaps::Layout_5p0_side , AV_CH_LAYOUT_5POINT0 }, - {AkAudioCaps::Layout_5p1 , AV_CH_LAYOUT_5POINT1_BACK }, - {AkAudioCaps::Layout_5p1_side , AV_CH_LAYOUT_5POINT1 }, - {AkAudioCaps::Layout_6p0 , AV_CH_LAYOUT_6POINT0 }, - {AkAudioCaps::Layout_6p0_front , AV_CH_LAYOUT_6POINT0_FRONT }, - {AkAudioCaps::Layout_hexagonal , AV_CH_LAYOUT_HEXAGONAL }, - {AkAudioCaps::Layout_6p1 , AV_CH_LAYOUT_6POINT1 }, - {AkAudioCaps::Layout_6p1_back , AV_CH_LAYOUT_6POINT1_BACK }, - {AkAudioCaps::Layout_6p1_front , AV_CH_LAYOUT_6POINT1_FRONT }, - {AkAudioCaps::Layout_7p0 , AV_CH_LAYOUT_7POINT0 }, - {AkAudioCaps::Layout_7p0_front , AV_CH_LAYOUT_7POINT0_FRONT }, - {AkAudioCaps::Layout_7p1 , AV_CH_LAYOUT_7POINT1 }, - {AkAudioCaps::Layout_7p1_wide , AV_CH_LAYOUT_7POINT1_WIDE }, - {AkAudioCaps::Layout_7p1_wide_side, AV_CH_LAYOUT_7POINT1_WIDE_BACK}, - {AkAudioCaps::Layout_octagonal , AV_CH_LAYOUT_OCTAGONAL }, - {AkAudioCaps::Layout_hexadecagonal, AV_CH_LAYOUT_HEXADECAGONAL }, - {AkAudioCaps::Layout_downmix , AV_CH_LAYOUT_STEREO_DOWNMIX }, - }; - - return channelLayouts; -} - -Q_GLOBAL_STATIC_WITH_ARGS(ChannelLayoutsMap, channelLayouts, (initChannelFormatsMap())) - class ConvertAudioFFmpegSWPrivate { public: AkAudioCaps m_caps; SwrContext *m_resampleContext {nullptr}; QMutex m_mutex; + + inline static const SampleFormatsMap &sampleFormats(bool planar) + { + static const SampleFormatsMap formats { + {AkAudioCaps::SampleFormat_u8 , AV_SAMPLE_FMT_U8 }, + {AkAudioCaps::SampleFormat_s16, AV_SAMPLE_FMT_S16}, + {AkAudioCaps::SampleFormat_s32, AV_SAMPLE_FMT_S32}, +#ifdef HAVE_SAMPLEFORMAT64 + {AkAudioCaps::SampleFormat_s64, AV_SAMPLE_FMT_S64 }, +#endif + {AkAudioCaps::SampleFormat_flt, AV_SAMPLE_FMT_FLT}, + {AkAudioCaps::SampleFormat_dbl, AV_SAMPLE_FMT_DBL}, + }; + static const SampleFormatsMap planarFormats { + {AkAudioCaps::SampleFormat_u8 , AV_SAMPLE_FMT_U8P }, + {AkAudioCaps::SampleFormat_s16, AV_SAMPLE_FMT_S16P}, + {AkAudioCaps::SampleFormat_s32, AV_SAMPLE_FMT_S32P}, +#ifdef HAVE_SAMPLEFORMAT64 + {AkAudioCaps::SampleFormat_s64, AV_SAMPLE_FMT_S64P}, +#endif + {AkAudioCaps::SampleFormat_flt, AV_SAMPLE_FMT_FLTP}, + {AkAudioCaps::SampleFormat_dbl, AV_SAMPLE_FMT_DBLP}, + }; + + return planar? planarFormats: formats; + } + + inline static const ChannelLayoutsMap &channelLayouts() + { + static const ChannelLayoutsMap channelLayouts { + {AkAudioCaps::Layout_mono , AV_CH_LAYOUT_MONO }, + {AkAudioCaps::Layout_stereo , AV_CH_LAYOUT_STEREO }, + {AkAudioCaps::Layout_2p1 , AV_CH_LAYOUT_2POINT1 }, + {AkAudioCaps::Layout_3p0 , AV_CH_LAYOUT_SURROUND }, + {AkAudioCaps::Layout_3p0_back , AV_CH_LAYOUT_2_1 }, + {AkAudioCaps::Layout_3p1 , AV_CH_LAYOUT_3POINT1 }, + {AkAudioCaps::Layout_4p0 , AV_CH_LAYOUT_4POINT0 }, + {AkAudioCaps::Layout_quad , AV_CH_LAYOUT_QUAD }, + {AkAudioCaps::Layout_quad_side , AV_CH_LAYOUT_2_2 }, + {AkAudioCaps::Layout_4p1 , AV_CH_LAYOUT_4POINT1 }, + {AkAudioCaps::Layout_5p0 , AV_CH_LAYOUT_5POINT0_BACK }, + {AkAudioCaps::Layout_5p0_side , AV_CH_LAYOUT_5POINT0 }, + {AkAudioCaps::Layout_5p1 , AV_CH_LAYOUT_5POINT1_BACK }, + {AkAudioCaps::Layout_5p1_side , AV_CH_LAYOUT_5POINT1 }, + {AkAudioCaps::Layout_6p0 , AV_CH_LAYOUT_6POINT0 }, + {AkAudioCaps::Layout_6p0_front , AV_CH_LAYOUT_6POINT0_FRONT }, + {AkAudioCaps::Layout_hexagonal , AV_CH_LAYOUT_HEXAGONAL }, + {AkAudioCaps::Layout_6p1 , AV_CH_LAYOUT_6POINT1 }, + {AkAudioCaps::Layout_6p1_back , AV_CH_LAYOUT_6POINT1_BACK }, + {AkAudioCaps::Layout_6p1_front , AV_CH_LAYOUT_6POINT1_FRONT }, + {AkAudioCaps::Layout_7p0 , AV_CH_LAYOUT_7POINT0 }, + {AkAudioCaps::Layout_7p0_front , AV_CH_LAYOUT_7POINT0_FRONT }, + {AkAudioCaps::Layout_7p1 , AV_CH_LAYOUT_7POINT1 }, + {AkAudioCaps::Layout_7p1_wide , AV_CH_LAYOUT_7POINT1_WIDE }, + {AkAudioCaps::Layout_7p1_wide_back, AV_CH_LAYOUT_7POINT1_WIDE_BACK}, + {AkAudioCaps::Layout_octagonal , AV_CH_LAYOUT_OCTAGONAL }, + {AkAudioCaps::Layout_hexadecagonal, AV_CH_LAYOUT_HEXADECAGONAL }, + {AkAudioCaps::Layout_downmix , AV_CH_LAYOUT_STEREO_DOWNMIX }, + }; + + return channelLayouts; + } }; ConvertAudioFFmpegSW::ConvertAudioFFmpegSW(QObject *parent): @@ -109,24 +135,26 @@ QMutexLocker mutexLocker(&this->d->m_mutex); if (!this->d->m_caps) - return AkPacket(); + return {}; - int64_t iSampleLayout = channelLayouts->value(packet.caps().layout(), 0); + int64_t iSampleLayout = + ConvertAudioFFmpegSWPrivate::channelLayouts().value(packet.caps().layout(), 0); AVSampleFormat iSampleFormat = - av_get_sample_fmt(AkAudioCaps::sampleFormatToString(packet.caps().format()) - .toStdString().c_str()); + ConvertAudioFFmpegSWPrivate::sampleFormats(packet.caps().planar()) + .value(packet.caps().format(), AV_SAMPLE_FMT_NONE); int iSampleRate = packet.caps().rate(); int iNChannels = packet.caps().channels(); int iNSamples = packet.caps().samples(); - int64_t oSampleLayout = channelLayouts->value(this->d->m_caps.layout(), - AV_CH_LAYOUT_STEREO); + int64_t oSampleLayout = + ConvertAudioFFmpegSWPrivate::channelLayouts().value(this->d->m_caps.layout(), + AV_CH_LAYOUT_STEREO); AVSampleFormat oSampleFormat = - av_get_sample_fmt(AkAudioCaps::sampleFormatToString(this->d->m_caps.format()) - .toStdString().c_str()); + ConvertAudioFFmpegSWPrivate::sampleFormats(this->d->m_caps.planar()) + .value(this->d->m_caps.format(), AV_SAMPLE_FMT_NONE); int oSampleRate = this->d->m_caps.rate(); int oNChannels = this->d->m_caps.channels(); @@ -143,7 +171,7 @@ nullptr); if (!this->d->m_resampleContext) - return AkPacket(); + return {}; // Create input audio frame. static AVFrame iFrame; @@ -154,14 +182,15 @@ iFrame.sample_rate = iSampleRate; iFrame.nb_samples = iNSamples; iFrame.pts = packet.pts(); + auto tmpPacket = packet.realign(1); if (avcodec_fill_audio_frame(&iFrame, iFrame.channels, iSampleFormat, - reinterpret_cast(packet.buffer().constData()), - packet.buffer().size(), - packet.caps().align()) < 0) { - return AkPacket(); + reinterpret_cast(tmpPacket.buffer().constData()), + tmpPacket.buffer().size(), + 1) < 0) { + return {}; } // Fill output audio frame. @@ -193,14 +222,14 @@ reinterpret_cast(oBuffer.constData()), oBuffer.size(), 1) < 0) { - return AkPacket(); + return {}; } // convert to destination format if (swr_convert_frame(this->d->m_resampleContext, &oFrame, &iFrame) < 0) - return AkPacket(); + return {}; frameSize = av_samples_get_buffer_size(oFrame.linesize, oFrame.channels, @@ -212,15 +241,14 @@ AkAudioPacket oAudioPacket; oAudioPacket.caps() = this->d->m_caps; - oAudioPacket.caps().samples() = oFrame.nb_samples; - oAudioPacket.caps().align() = 1; + oAudioPacket.caps().setSamples(oFrame.nb_samples); oAudioPacket.buffer() = oBuffer; oAudioPacket.pts() = oFrame.pts; oAudioPacket.timeBase() = AkFrac(1, this->d->m_caps.rate()); oAudioPacket.index() = packet.index(); oAudioPacket.id() = packet.id(); - return oAudioPacket.toPacket(); + return oAudioPacket; } void ConvertAudioFFmpegSW::uninit() diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/generic.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/generic.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/generic.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/generic.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,63 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../akcommons.pri) { + include(../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +CONFIG += plugin + +HEADERS = \ + src/plugin.h \ + src/convertaudiogeneric.h \ + ../convertaudio.h + +INCLUDEPATH += \ + ../../../../Lib/src \ + ../ + +LIBS += -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} + +OTHER_FILES += pspec.json + +QT += qml + +SOURCES = \ + src/plugin.cpp \ + src/convertaudiogeneric.cpp \ + ../convertaudio.cpp + +akModule = ACapsConvert +DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,3 @@ +{ + "pluginType": "Ak.SubModule" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/convertaudiogeneric.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/convertaudiogeneric.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/convertaudiogeneric.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/convertaudiogeneric.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,85 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include + +#include "convertaudiogeneric.h" + +class ConvertAudioGenericPrivate +{ + public: + AkAudioCaps m_caps; + AkAudioCaps m_previousCaps; + QMutex m_mutex; + qreal m_sampleCorrection {0}; +}; + +ConvertAudioGeneric::ConvertAudioGeneric(QObject *parent): + ConvertAudio(parent) +{ + this->d = new ConvertAudioGenericPrivate; +} + +ConvertAudioGeneric::~ConvertAudioGeneric() +{ + this->uninit(); + delete this->d; +} + +bool ConvertAudioGeneric::init(const AkAudioCaps &caps) +{ + QMutexLocker mutexLocker(&this->d->m_mutex); + this->d->m_caps = caps; + this->d->m_previousCaps = AkAudioCaps(); + this->d->m_sampleCorrection = 0; + + return true; +} + +AkPacket ConvertAudioGeneric::convert(const AkAudioPacket &packet) +{ + QMutexLocker mutexLocker(&this->d->m_mutex); + + if (!this->d->m_caps || packet.buffer().size() < 1) + return {}; + + if (packet.caps() != this->d->m_previousCaps) { + this->d->m_previousCaps = packet.caps(); + this->d->m_sampleCorrection = 0; + } + + return packet.convertFormat(this->d->m_caps.format()) + .convertLayout(this->d->m_caps.layout()) + .convertPlanar(this->d->m_caps.planar()) + .convertSampleRate(this->d->m_caps.rate(), + this->d->m_sampleCorrection); +} + +void ConvertAudioGeneric::uninit() +{ + QMutexLocker mutexLocker(&this->d->m_mutex); + this->d->m_caps = AkAudioCaps(); +} + +#include "moc_convertaudiogeneric.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/convertaudiogeneric.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/convertaudiogeneric.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/convertaudiogeneric.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/convertaudiogeneric.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,43 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef CONVERTAUDIOGENERIC_H +#define CONVERTAUDIOGENERIC_H + +#include "convertaudio.h" + +class ConvertAudioGenericPrivate; + +class ConvertAudioGeneric: public ConvertAudio +{ + Q_OBJECT + + public: + ConvertAudioGeneric(QObject *parent=nullptr); + ~ConvertAudioGeneric(); + + Q_INVOKABLE bool init(const AkAudioCaps &caps); + Q_INVOKABLE AkPacket convert(const AkAudioPacket &packet); + Q_INVOKABLE void uninit(); + + private: + ConvertAudioGenericPrivate *d; +}; + +#endif // CONVERTAUDIOGENERIC_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "convertaudiogeneric.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new ConvertAudioGeneric(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return QStringList(); +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/generic/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/gstreamer/src/convertaudiogstreamer.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/gstreamer/src/convertaudiogstreamer.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/gstreamer/src/convertaudiogstreamer.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/gstreamer/src/convertaudiogstreamer.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,8 +21,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -31,61 +32,7 @@ #include "convertaudiogstreamer.h" -using StringStringMap = QMap; - -inline StringStringMap initGstToFF() -{ - StringStringMap gstToFF = { - {"S8" , "s8" }, - {"U8" , "u8" }, - {"S16LE" , "s16le" }, - {"S16BE" , "s16be" }, - {"U16LE" , "u16le" }, - {"U16BE" , "u16be" }, - {"S24_32LE", "s2432le"}, - {"S24_32BE", "s2432be"}, - {"U24_32LE", "u2432le"}, - {"U24_32BE", "u2432be"}, - {"S32LE" , "s32le" }, - {"S32BE" , "s32be" }, - {"U32LE" , "u32le" }, - {"U32BE" , "u32be" }, - {"S24LE" , "s24le" }, - {"S24BE" , "s24be" }, - {"U24LE" , "u24le" }, - {"U24BE" , "u24be" }, - {"S20LE" , "s20le" }, - {"S20BE" , "s20be" }, - {"U20LE" , "u20le" }, - {"U20BE" , "u20be" }, - {"S18LE" , "s18le" }, - {"S18BE" , "s18be" }, - {"U18LE" , "u18le" }, - {"U18BE" , "u18le" }, - {"F32LE" , "fltle" }, - {"F32BE" , "fltbe" }, - {"F64LE" , "dblle" }, - {"F64BE" , "dblbe" }, - {"S16" , "s16" }, - {"U16" , "u16" }, - {"S24_32" , "s2432" }, - {"U24_32" , "u2432" }, - {"S32" , "s32" }, - {"U32" , "u32" }, - {"S24" , "s24" }, - {"U24" , "u24" }, - {"S20" , "s20" }, - {"U20" , "u20" }, - {"S18" , "s18" }, - {"U18" , "u18" }, - {"F32" , "flt" }, - {"F64" , "dbl" } - }; - - return gstToFF; -} - -Q_GLOBAL_STATIC_WITH_ARGS(StringStringMap, gstToFF, (initGstToFF())) +using GstFormatMap = QMap; class ConvertAudioGStreamerPrivate { @@ -96,13 +43,35 @@ GstElement *m_source {nullptr}; GstElement *m_sink {nullptr}; GMainLoop *m_mainLoop {nullptr}; - guint m_busWatchId {0}; QMutex m_mutex; + guint m_busWatchId {0}; inline void waitState(GstState state); inline static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer userData); + + inline static const GstFormatMap &gstToFormat() + { + static const GstFormatMap gstToFormat { + {AkAudioCaps::SampleFormat_s8 , "S8" }, + {AkAudioCaps::SampleFormat_u8 , "U8" }, + {AkAudioCaps::SampleFormat_s16le, "S16LE"}, + {AkAudioCaps::SampleFormat_s16be, "S16BE"}, + {AkAudioCaps::SampleFormat_u16le, "U16LE"}, + {AkAudioCaps::SampleFormat_u16be, "U16BE"}, + {AkAudioCaps::SampleFormat_s32le, "S32LE"}, + {AkAudioCaps::SampleFormat_s32be, "S32BE"}, + {AkAudioCaps::SampleFormat_u32le, "U32LE"}, + {AkAudioCaps::SampleFormat_u32be, "U32BE"}, + {AkAudioCaps::SampleFormat_fltle, "F32LE"}, + {AkAudioCaps::SampleFormat_fltbe, "F32BE"}, + {AkAudioCaps::SampleFormat_dblle, "F64LE"}, + {AkAudioCaps::SampleFormat_dblbe, "F64BE"}, + }; + + return gstToFormat; + } }; ConvertAudioGStreamer::ConvertAudioGStreamer(QObject *parent): @@ -126,12 +95,16 @@ this->d->m_pipeline = gst_pipeline_new(nullptr); this->d->m_source = gst_element_factory_make("appsrc", nullptr); - gst_app_src_set_stream_type(GST_APP_SRC(this->d->m_source), GST_APP_STREAM_TYPE_STREAM); - g_object_set(G_OBJECT(this->d->m_source), "format", GST_FORMAT_TIME, nullptr); - - GstElement *audioConvert = gst_element_factory_make("audioconvert", nullptr); - GstElement *audioResample = gst_element_factory_make("audioresample", nullptr); - GstElement *audioRate = gst_element_factory_make("audiorate", nullptr); + gst_app_src_set_stream_type(GST_APP_SRC(this->d->m_source), + GST_APP_STREAM_TYPE_STREAM); + g_object_set(G_OBJECT(this->d->m_source), + "format", + GST_FORMAT_TIME, + nullptr); + + auto audioConvert = gst_element_factory_make("audioconvert", nullptr); + auto audioResample = gst_element_factory_make("audioresample", nullptr); + auto audioRate = gst_element_factory_make("audiorate", nullptr); this->d->m_sink = gst_element_factory_make("appsink", nullptr); gst_bin_add_many(GST_BIN(this->d->m_pipeline), @@ -171,31 +144,23 @@ || !this->d->m_caps) return AkPacket(); - QString iFormat = AkAudioCaps::sampleFormatToString(packet.caps().format()); - QString gstIFormat = gstToFF->key(iFormat, "S16"); - -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - QString fEnd = "LE"; -#elif Q_BYTE_ORDER == Q_BIG_ENDIAN - QString fEnd = "BE"; -#endif - - if (packet.caps().bps() > 8 && !gstIFormat.endsWith(fEnd)) - gstIFormat += fEnd; + auto gstIFormat = + ConvertAudioGStreamerPrivate::gstToFormat().value(packet.caps().format()); const char *gstInLayout = - AkAudioCaps::isPlanar(packet.caps().format())? + packet.caps().planar()? "non-interleaved": "interleaved"; - auto inCaps = gst_caps_new_simple("audio/x-raw", - "format", G_TYPE_STRING, gstIFormat.toStdString().c_str(), - "layout", G_TYPE_STRING, gstInLayout, - "rate", G_TYPE_INT, packet.caps().rate(), - "channels", G_TYPE_INT, packet.caps().channels(), - nullptr); + auto inCaps = + gst_caps_new_simple("audio/x-raw", + "format", G_TYPE_STRING, gstIFormat.toStdString().c_str(), + "layout", G_TYPE_STRING, gstInLayout, + "rate", G_TYPE_INT, packet.caps().rate(), + "channels", G_TYPE_INT, packet.caps().channels(), + nullptr); inCaps = gst_caps_fixate(inCaps); - GstCaps *sourceCaps = gst_app_src_get_caps(GST_APP_SRC(this->d->m_source)); + auto sourceCaps = gst_app_src_get_caps(GST_APP_SRC(this->d->m_source)); if (!sourceCaps || !gst_caps_is_equal(sourceCaps, inCaps)) gst_app_src_set_caps(GST_APP_SRC(this->d->m_source), inCaps); @@ -205,22 +170,19 @@ if (sourceCaps) gst_caps_unref(sourceCaps); - QString oFormat = AkAudioCaps::sampleFormatToString(this->d->m_caps.format()); - QString gstOFormat = gstToFF->key(oFormat, "S16"); + auto gstOFormat = + ConvertAudioGStreamerPrivate::gstToFormat().value(this->d->m_caps.format()); - if (this->d->m_caps.bps() > 8 && !gstOFormat.endsWith(fEnd)) - gstOFormat += fEnd; - - const char *gstOutLayout = - AkAudioCaps::isPlanar(this->d->m_caps.format())? - "non-interleaved": "interleaved"; + const char *gstOutLayout = this->d->m_caps.planar()? + "non-interleaved": "interleaved"; - auto outCaps = gst_caps_new_simple("audio/x-raw", - "format", G_TYPE_STRING, gstOFormat.toStdString().c_str(), - "layout", G_TYPE_STRING, gstOutLayout, - "rate", G_TYPE_INT, this->d->m_caps.rate(), - "channels", G_TYPE_INT, this->d->m_caps.channels(), - nullptr); + auto outCaps = + gst_caps_new_simple("audio/x-raw", + "format", G_TYPE_STRING, gstOFormat.toStdString().c_str(), + "layout", G_TYPE_STRING, gstOutLayout, + "rate", G_TYPE_INT, this->d->m_caps.rate(), + "channels", G_TYPE_INT, this->d->m_caps.channels(), + nullptr); outCaps = gst_caps_fixate(outCaps); GstCaps *sinkCaps = gst_app_sink_get_caps(GST_APP_SINK(this->d->m_sink)); @@ -243,7 +205,9 @@ if (state != GST_STATE_PLAYING) { // Run the main GStreamer loop. this->d->m_mainLoop = g_main_loop_new(nullptr, FALSE); - QtConcurrent::run(&this->d->m_threadPool, g_main_loop_run, this->d->m_mainLoop); + QtConcurrent::run(&this->d->m_threadPool, + g_main_loop_run, + this->d->m_mainLoop); gst_element_set_state(this->d->m_pipeline, GST_STATE_PLAYING); } @@ -256,7 +220,8 @@ memcpy(info.data, packet.buffer().constData(), info.size); gst_buffer_unmap(buffer, &info); - GST_BUFFER_PTS(buffer) = GstClockTime(packet.pts() * packet.timeBase().value() * GST_SECOND); + GST_BUFFER_PTS(buffer) = + GstClockTime(packet.pts() * packet.timeBase().value() * GST_SECOND); GST_BUFFER_DTS(buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION(buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET(buffer) = GST_BUFFER_OFFSET_NONE; @@ -275,7 +240,7 @@ QByteArray oBuffer(int(info.size), 0); memcpy(oBuffer.data(), info.data, info.size); gst_buffer_unmap(buffer, &info); - qint64 pts = qint64(GST_BUFFER_PTS(buffer) / packet.timeBase().value() / GST_SECOND); + auto pts = qint64(GST_BUFFER_PTS(buffer) / packet.timeBase().value() / GST_SECOND); gst_sample_unref(sample); // Create a package and return it. @@ -285,14 +250,14 @@ AkAudioPacket oAudioPacket; oAudioPacket.caps() = this->d->m_caps; - oAudioPacket.caps().samples() = nSamples; + oAudioPacket.caps().setSamples(nSamples); oAudioPacket.buffer() = oBuffer; oAudioPacket.pts() = pts; oAudioPacket.timeBase() = AkFrac(1, this->d->m_caps.rate()); oAudioPacket.index() = packet.index(); oAudioPacket.id() = packet.id(); - return oAudioPacket.toPacket(); + return oAudioPacket; } void ConvertAudioGStreamer::uninit() @@ -393,7 +358,10 @@ GstState oldstate; GstState newstate; GstState pending; - gst_message_parse_state_changed(message, &oldstate, &newstate, &pending); + gst_message_parse_state_changed(message, + &oldstate, + &newstate, + &pending); qDebug() << "State changed from" << gst_element_state_get_name(oldstate) << "to" @@ -453,8 +421,8 @@ break; } case GST_MESSAGE_ELEMENT: { - const GstStructure *messageStructure = gst_message_get_structure(message); - gchar *structure = gst_structure_to_string(messageStructure); + auto messageStructure = gst_message_get_structure(message); + auto structure = gst_structure_to_string(messageStructure); // qDebug() << structure; g_free(structure); break; @@ -484,7 +452,12 @@ guint64 streamTime; guint64 timestamp; guint64 duration; - gst_message_parse_qos(message, &live, &runningTime, &streamTime, ×tamp, &duration); + gst_message_parse_qos(message, + &live, + &runningTime, + &streamTime, + ×tamp, + &duration); qDebug() << " Is live stream =" << live; qDebug() << " Runninng time =" << runningTime; qDebug() << " Stream time =" << streamTime; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/src.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/src.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ACapsConvert/src/src.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ACapsConvert/src/src.pro 2021-02-15 15:25:23.000000000 +0000 @@ -31,8 +31,9 @@ HEADERS = \ acapsconvert.h \ acapsconvertelement.h \ - convertaudio.h \ - acapsconvertglobals.h + acapsconvertelementsettings.h \ + acapsconvertglobals.h \ + convertaudio.h INCLUDEPATH += \ ../../../Lib/src @@ -46,8 +47,9 @@ SOURCES = \ acapsconvert.cpp \ acapsconvertelement.cpp \ - convertaudio.cpp \ - acapsconvertglobals.cpp + acapsconvertelementsettings.cpp \ + acapsconvertglobals.cpp \ + convertaudio.cpp DESTDIR = $${OUT_PWD}/../$${BIN_DIR} TARGET = ACapsConvert diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Aging/src/agingelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Aging/src/agingelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Aging/src/agingelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Aging/src/agingelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,12 +17,13 @@ * Web-Site: http://webcamoid.github.io/ */ -#include #include #include #include #include #include +#include +#include #include #include "agingelement.h" @@ -46,8 +47,6 @@ { this->d = new AgingElementPrivate; this->d->m_scratches.resize(7); - - qsrand(uint(QTime::currentTime().msec())); } AgingElement::~AgingElement() @@ -81,13 +80,33 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket AgingElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + QImage oFrame = src.convertToFormat(QImage::Format_ARGB32); + oFrame = this->d->colorAging(oFrame); + this->d->scratching(oFrame); + this->d->pits(oFrame); + + if (this->d->m_addDust) + this->d->dusts(oFrame); + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void AgingElement::setNScratches(int nScratches) { if (this->d->m_scratches.size() == nScratches) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_scratches.resize(nScratches); + this->d->m_mutex.unlock(); emit this->nScratchesChanged(nScratches); } @@ -110,40 +129,17 @@ this->setAddDust(true); } -AkPacket AgingElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - QImage oFrame = src.convertToFormat(QImage::Format_ARGB32); - oFrame = this->d->colorAging(oFrame); - this->d->scratching(oFrame); - this->d->pits(oFrame); - - if (this->d->m_addDust) - this->d->dusts(oFrame); - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - QImage AgingElementPrivate::colorAging(const QImage &src) { QImage dst(src.size(), src.format()); - - int lumaVariance = 8; - int colorVariance = 24; - int luma = -32 + qrand() % lumaVariance; + int luma = QRandomGenerator::global()->bounded(-32, -25); for (int y = 0; y < src.height(); y++) { auto srcLine = reinterpret_cast(src.constScanLine(y)); auto dstLine = reinterpret_cast(dst.scanLine(y)); for (int x = 0; x < src.width(); x++) { - int c = qrand() % colorVariance; + int c = QRandomGenerator::global()->bounded(24); int r = qRed(srcLine[x]) + luma + c; int g = qGreen(srcLine[x]) + luma + c; int b = qBlue(srcLine[x]) + luma + c; @@ -165,7 +161,7 @@ for (auto &scratch: this->m_scratches) { if (scratch.life() < 1.0) { - if (qrand() <= 0.06 * RAND_MAX) { + if (QRandomGenerator::global()->bounded(RAND_MAX) <= 0.06 * RAND_MAX) { scratch = Scratch(2.0, 33.0, 1.0, 1.0, 0.0, dest.width() - 1, @@ -182,13 +178,12 @@ continue; } - int lumaVariance = 8; - int luma = 32 + qrand() % lumaVariance; + int luma = QRandomGenerator::global()->bounded(32, 40); int x = int(scratch.x()); int y1 = scratch.y(); int y2 = scratch.isAboutToDie()? - qrand() % dest.height(): + QRandomGenerator::global()->bounded(dest.height()): dest.height(); for (int y = y1; y < y2; y++) { @@ -210,28 +205,25 @@ void AgingElementPrivate::pits(QImage &dest) { - int pnum; - int pnumscale = int(0.03 * qMax(dest.width(), dest.height())); + int pnumscale = qRound(0.03 * qMax(dest.width(), dest.height())); static int pitsInterval = 0; + int pnum = QRandomGenerator::global()->bounded(pnumscale); if (pitsInterval) { - pnum = pnumscale + (qrand() % pnumscale); + pnum += pnumscale; pitsInterval--; - } else { - pnum = qrand() % pnumscale; - - if (qrand() <= 0.03 * RAND_MAX) - pitsInterval = (qrand() % 16) + 20; + } else if (QRandomGenerator::global()->bounded(RAND_MAX) <= 0.03 * RAND_MAX) { + pitsInterval = QRandomGenerator::global()->bounded(20, 36); } for (int i = 0; i < pnum; i++) { - int x = qrand() % (dest.width() - 1); - int y = qrand() % (dest.height() - 1); - int size = qrand() % 16; + int x = QRandomGenerator::global()->bounded(dest.width()); + int y = QRandomGenerator::global()->bounded(dest.height()); + int size = QRandomGenerator::global()->bounded(16); for (int j = 0; j < size; j++) { - x += qrand() % 3 - 1; - y += qrand() % 3 - 1; + x += QRandomGenerator::global()->bounded(-1, 2); + y += QRandomGenerator::global()->bounded(-1, 2); if (x < 0 || x >= dest.width() || y < 0 || y >= dest.height()) @@ -248,25 +240,24 @@ static int dustInterval = 0; if (dustInterval == 0) { - if (qrand() <= 0.03 * RAND_MAX) - dustInterval = qrand() % 8; + if (QRandomGenerator::global()->bounded(RAND_MAX) <= 0.03 * RAND_MAX) + dustInterval = QRandomGenerator::global()->bounded(8); return; } dustInterval--; - - int areaScale = int(0.02 * qMax(dest.width(), dest.height())); - int dnum = areaScale * 4 + (qrand() % 32); + int areaScale = qRound(0.02 * qMax(dest.width(), dest.height())); + int dnum = 4 * areaScale + QRandomGenerator::global()->bounded(32); for (int i = 0; i < dnum; i++) { - int x = qrand() % (dest.width() - 1); - int y = qrand() % (dest.height() - 1); - int len = qrand() % areaScale + 5; - - for (int j = 0; j < len; j++) { - x += qrand() % 3 - 1; - y += qrand() % 3 - 1; + int x = QRandomGenerator::global()->bounded(dest.width()); + int y = QRandomGenerator::global()->bounded(dest.height()); + int size = QRandomGenerator::global()->bounded(areaScale) + 5; + + for (int j = 0; j < size; j++) { + x += QRandomGenerator::global()->bounded(-1, 2); + y += QRandomGenerator::global()->bounded(-1, 2); if (x < 0 || x >= dest.width() || y < 0 || y >= dest.height()) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Aging/src/agingelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Aging/src/agingelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Aging/src/agingelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Aging/src/agingelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -52,6 +52,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void nScratchesChanged(int nScratches); @@ -62,8 +63,6 @@ void setAddDust(bool addDust); void resetNScratches(); void resetAddDust(); - - AkPacket iStream(const AkPacket &packet); }; #endif // AGINGELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Aging/src/scratch.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Aging/src/scratch.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Aging/src/scratch.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Aging/src/scratch.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -18,17 +18,28 @@ */ #include +#include +#include +#include #include "scratch.h" -Scratch::Scratch(): - m_life0(0.0), - m_life(0.0), - m_dlife(0.0), - m_x(0.0), - m_dx(0.0), - m_y(0) +class ScratchPrivate { + public: + qreal m_life0 {0.0}; + qreal m_life {0.0}; + qreal m_dlife {0.0}; + qreal m_x {0.0}; + qreal m_dx {0.0}; + int m_y {0}; + + inline qreal boundedReal(qreal min, qreal max); +}; + +Scratch::Scratch() +{ + this->d = new ScratchPrivate; } Scratch::Scratch(qreal minLife, qreal maxLife, @@ -37,111 +48,140 @@ qreal minDX, qreal maxDX, int minY, int maxY) { - this->m_life = this->m_life0 = qrand() * (maxLife - minLife) / RAND_MAX + minLife; - this->m_dlife = qrand() * (maxDLife - minDLife) / RAND_MAX + minDLife; + this->d = new ScratchPrivate; + this->d->m_life = this->d->m_life0 = this->d->boundedReal(minLife, maxLife); + this->d->m_dlife = this->d->boundedReal(minDLife, maxDLife); - if (!qIsNull(this->m_dlife)) - this->m_dlife = maxDLife - minDLife; + if (!qIsNull(this->d->m_dlife)) + this->d->m_dlife = maxDLife - minDLife; - this->m_x = qrand() * (maxX - minX) / RAND_MAX + minX; - this->m_dx = qrand() * (maxDX - minDX) / RAND_MAX + minDX; + this->d->m_x = this->d->boundedReal(minX, maxX); + this->d->m_dx = this->d->boundedReal(minDX, maxDX); - if (!qIsNull(this->m_dx)) - this->m_dx = maxDX - minDX; + if (!qIsNull(this->d->m_dx)) + this->d->m_dx = maxDX - minDX; -// this->m_dx *= (qrand() & 0x1? 1.0: -1.0); + this->d->m_y = QRandomGenerator::global()->bounded(minY, maxY); +} - this->m_y = int(qrand() * (maxY - minY) / RAND_MAX) + minY; +Scratch::Scratch(const Scratch &other) +{ + this->d = new ScratchPrivate; + this->d->m_life0 = other.d->m_life0; + this->d->m_life = other.d->m_life; + this->d->m_dlife = other.d->m_dlife; + this->d->m_x = other.d->m_x; + this->d->m_dx = other.d->m_dx; + this->d->m_y = other.d->m_y; +} + +Scratch::~Scratch() +{ + delete this->d; +} + +Scratch &Scratch::operator =(const Scratch &other) +{ + if (this != &other) { + this->d->m_life0 = other.d->m_life0; + this->d->m_life = other.d->m_life; + this->d->m_dlife = other.d->m_dlife; + this->d->m_x = other.d->m_x; + this->d->m_dx = other.d->m_dx; + this->d->m_y = other.d->m_y; + } + + return *this; } Scratch Scratch::operator ++(int) { - this->m_life -= this->m_dlife; - this->m_x += this->m_dx; + this->d->m_life -= this->d->m_dlife; + this->d->m_x += this->d->m_dx; return *this; } qreal Scratch::life() const { - return this->m_life; + return this->d->m_life; } qreal &Scratch::life() { - return this->m_life; + return this->d->m_life; } qreal Scratch::dlife() const { - return this->m_dlife; + return this->d->m_dlife; } qreal &Scratch::dlife() { - return this->m_dlife; + return this->d->m_dlife; } qreal Scratch::x() const { - return this->m_x; + return this->d->m_x; } qreal &Scratch::x() { - return this->m_x; + return this->d->m_x; } qreal Scratch::dx() const { - return this->m_dx; + return this->d->m_dx; } qreal &Scratch::dx() { - return this->m_dx; + return this->d->m_dx; } int Scratch::y() const { - return this->m_y; + return this->d->m_y; } int &Scratch::y() { - return this->m_y; + return this->d->m_y; } bool Scratch::isAboutToDie() const { const qreal threshold = 0.75; - return this->m_life <= this->m_dlife * (1.0 + threshold); + return this->d->m_life <= this->d->m_dlife * (1.0 + threshold); } void Scratch::setLife(qreal life) { - this->m_life = life; + this->d->m_life = life; } void Scratch::setDLife(qreal dlife) { - this->m_dlife = dlife; + this->d->m_dlife = dlife; } void Scratch::setX(qreal x) { - this->m_x = x; + this->d->m_x = x; } void Scratch::setDx(qreal dx) { - this->m_dx = dx; + this->d->m_dx = dx; } void Scratch::setY(int y) { - this->m_y = y; + this->d->m_y = y; } void Scratch::resetLife() @@ -168,3 +208,10 @@ { this->setY(0); } + +qreal ScratchPrivate::boundedReal(qreal min, qreal max) +{ + std::uniform_real_distribution distribution(min, max); + + return distribution(*QRandomGenerator::global()); +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Aging/src/scratch.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Aging/src/scratch.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Aging/src/scratch.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Aging/src/scratch.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,8 @@ #include +class ScratchPrivate; + class Scratch { public: @@ -31,8 +33,9 @@ qreal minX, qreal maxX, qreal minDX, qreal maxDX, int minY, int maxY); - Scratch(const Scratch &other) = default; - Scratch &operator =(const Scratch &other) = default; + Scratch(const Scratch &other); + ~Scratch(); + Scratch &operator =(const Scratch &other); Scratch operator ++(int); qreal life() const; @@ -59,12 +62,7 @@ void resetY(); private: - qreal m_life0; - qreal m_life; - qreal m_dlife; - qreal m_x; - qreal m_dx; - int m_y; + ScratchPrivate *d; }; #endif // SCRATCH_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/AudioDevice.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/AudioDevice.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/AudioDevice.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/AudioDevice.pro 2021-02-15 15:25:23.000000000 +0000 @@ -24,7 +24,7 @@ CONFIG(config_alsa): SUBDIRS += src/alsa CONFIG(config_coreaudio): SUBDIRS += src/coreaudio CONFIG(config_jack): SUBDIRS += src/jack -CONFIG(config_oss): SUBDIRS += src/oss +CONFIG(config_ndk_audio): SUBDIRS += src/ndkaudio +CONFIG(config_opensl): SUBDIRS += src/opensl CONFIG(config_pulseaudio): SUBDIRS += src/pulseaudio -CONFIG(config_qtaudio): SUBDIRS += src/qtaudio CONFIG(config_wasapi): SUBDIRS += src/wasapi diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/alsa/src/audiodevalsa.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/alsa/src/audiodevalsa.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/alsa/src/audiodevalsa.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/alsa/src/audiodevalsa.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -31,42 +31,22 @@ using SampleFormatMap = QMap; -inline SampleFormatMap initSampleFormatMap() +inline const SampleFormatMap &sampleFormats() { - SampleFormatMap sampleFormat = { - {AkAudioCaps::SampleFormat_s8 , SND_PCM_FORMAT_S8 }, - {AkAudioCaps::SampleFormat_u8 , SND_PCM_FORMAT_U8 }, - {AkAudioCaps::SampleFormat_s16 , SND_PCM_FORMAT_S16_LE }, - {AkAudioCaps::SampleFormat_s16be, SND_PCM_FORMAT_S16_BE }, - {AkAudioCaps::SampleFormat_u16le, SND_PCM_FORMAT_U16_LE }, - {AkAudioCaps::SampleFormat_u16be, SND_PCM_FORMAT_U16_BE }, - {AkAudioCaps::SampleFormat_s24le, SND_PCM_FORMAT_S24_LE }, - {AkAudioCaps::SampleFormat_s24be, SND_PCM_FORMAT_S24_BE }, - {AkAudioCaps::SampleFormat_u24le, SND_PCM_FORMAT_U24_LE }, - {AkAudioCaps::SampleFormat_u24be, SND_PCM_FORMAT_U24_BE }, - {AkAudioCaps::SampleFormat_s32le, SND_PCM_FORMAT_S32_LE }, - {AkAudioCaps::SampleFormat_s32be, SND_PCM_FORMAT_S32_BE }, - {AkAudioCaps::SampleFormat_u32le, SND_PCM_FORMAT_U32_LE }, - {AkAudioCaps::SampleFormat_u32be, SND_PCM_FORMAT_U32_BE }, - {AkAudioCaps::SampleFormat_fltle, SND_PCM_FORMAT_FLOAT_LE }, - {AkAudioCaps::SampleFormat_fltbe, SND_PCM_FORMAT_FLOAT_BE }, - {AkAudioCaps::SampleFormat_dblle, SND_PCM_FORMAT_FLOAT64_LE}, - {AkAudioCaps::SampleFormat_dblbe, SND_PCM_FORMAT_FLOAT64_BE}, - {AkAudioCaps::SampleFormat_s16 , SND_PCM_FORMAT_S16 }, - {AkAudioCaps::SampleFormat_u16 , SND_PCM_FORMAT_U16 }, - {AkAudioCaps::SampleFormat_s24 , SND_PCM_FORMAT_S24 }, - {AkAudioCaps::SampleFormat_u24 , SND_PCM_FORMAT_U24 }, - {AkAudioCaps::SampleFormat_s32 , SND_PCM_FORMAT_S32 }, - {AkAudioCaps::SampleFormat_u32 , SND_PCM_FORMAT_U32 }, - {AkAudioCaps::SampleFormat_flt , SND_PCM_FORMAT_FLOAT }, - {AkAudioCaps::SampleFormat_dbl , SND_PCM_FORMAT_FLOAT64 }, + static const SampleFormatMap sampleFormat { + {AkAudioCaps::SampleFormat_s8 , SND_PCM_FORMAT_S8 }, + {AkAudioCaps::SampleFormat_u8 , SND_PCM_FORMAT_U8 }, + {AkAudioCaps::SampleFormat_s16, SND_PCM_FORMAT_S16 }, + {AkAudioCaps::SampleFormat_u16, SND_PCM_FORMAT_U16 }, + {AkAudioCaps::SampleFormat_s32, SND_PCM_FORMAT_S32 }, + {AkAudioCaps::SampleFormat_u32, SND_PCM_FORMAT_U32 }, + {AkAudioCaps::SampleFormat_flt, SND_PCM_FORMAT_FLOAT }, + {AkAudioCaps::SampleFormat_dbl, SND_PCM_FORMAT_FLOAT64}, }; return sampleFormat; } -Q_GLOBAL_STATIC_WITH_ARGS(SampleFormatMap, sampleFormats, (initSampleFormatMap())) - class AudioDevAlsaPrivate { public: @@ -78,17 +58,18 @@ QStringList m_sources; QMap m_pinDescriptionMap; QMap> m_supportedFormats; - QMap> m_supportedChannels; + QMap> m_supportedLayouts; QMap> m_supportedSampleRates; snd_pcm_t *m_pcmHnd {nullptr}; QFileSystemWatcher *m_fsWatcher {nullptr}; QTimer m_timer; QMutex m_mutex; + int m_samples {0}; explicit AudioDevAlsaPrivate(AudioDevAlsa *self); void fillDeviceInfo(const QString &device, QList *supportedFormats, - QList *supportedChannels, + QList *supportedLayouts, QList *supportedSampleRates) const; }; @@ -161,11 +142,11 @@ AkAudioCaps AudioDevAlsa::preferredFormat(const QString &device) { return this->d->m_sinks.contains(device)? - AkAudioCaps(AkAudioCaps::SampleFormat_s16, - 2, + AkAudioCaps(AkAudioCaps::SampleFormat_s32, + AkAudioCaps::Layout_stereo, 44100): AkAudioCaps(AkAudioCaps::SampleFormat_u8, - 1, + AkAudioCaps::Layout_mono, 8000); } @@ -174,9 +155,9 @@ return this->d->m_supportedFormats.value(device); } -QList AudioDevAlsa::supportedChannels(const QString &device) +QList AudioDevAlsa::supportedChannelLayouts(const QString &device) { - return this->d->m_supportedChannels.value(device); + return this->d->m_supportedLayouts.value(device); } QList AudioDevAlsa::supportedSampleRates(const QString &device) @@ -189,29 +170,32 @@ QMutexLocker mutexLockeer(&this->d->m_mutex); this->d->m_pcmHnd = nullptr; - int error = snd_pcm_open(&this->d->m_pcmHnd, - QString(device) - .remove(QRegExp(":Input$|:Output$")) - .toStdString().c_str(), - device.endsWith(":Input")? - SND_PCM_STREAM_CAPTURE: SND_PCM_STREAM_PLAYBACK, - SND_PCM_NONBLOCK); + int error = + snd_pcm_open(&this->d->m_pcmHnd, + QString(device) + .remove(QRegExp(":Input$|:Output$")) + .toStdString().c_str(), + device.endsWith(":Input")? + SND_PCM_STREAM_CAPTURE: SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK); if (error < 0) goto init_fail; error = snd_pcm_set_params(this->d->m_pcmHnd, - sampleFormats->value(caps.format(), - SND_PCM_FORMAT_UNKNOWN), + sampleFormats().value(caps.format(), + SND_PCM_FORMAT_UNKNOWN), SND_PCM_ACCESS_RW_INTERLEAVED, uint(caps.channels()), uint(caps.rate()), 1, - 500000); + uint(1000 * this->latency())); if (error < 0) goto init_fail; + this->d->m_samples = qMax(this->latency() * caps.rate() / 1000, 1); + return true; init_fail: @@ -222,13 +206,11 @@ return false; } -QByteArray AudioDevAlsa::read(int samples) +QByteArray AudioDevAlsa::read() { - if (samples < 1) - return {}; + int samples = this->d->m_samples; QMutexLocker mutexLockeer(&this->d->m_mutex); - auto bufferSize = snd_pcm_frames_to_bytes(this->d->m_pcmHnd, samples); QByteArray buffer(int(bufferSize), 0); auto data = buffer.data(); @@ -250,7 +232,7 @@ continue; } - return QByteArray(); + return {}; } } @@ -313,7 +295,7 @@ void AudioDevAlsaPrivate::fillDeviceInfo(const QString &device, QList *supportedFormats, - QList *supportedChannels, + QList *supportedLayouts, QList *supportedSampleRates) const { snd_pcm_t *pcmHnd = nullptr; @@ -328,6 +310,8 @@ if (error < 0) return; + uint maxChannels = 0; + snd_pcm_hw_params_t *hwParams = nullptr; snd_pcm_hw_params_malloc(&hwParams); snd_pcm_hw_params_any(pcmHnd, hwParams); @@ -339,7 +323,7 @@ SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto deviceCaps_fail; - static const QVector preferredFormats = { + static const QVector preferredFormats { SND_PCM_FORMAT_FLOAT, SND_PCM_FORMAT_S32, SND_PCM_FORMAT_U32, @@ -350,12 +334,27 @@ }; for (auto fmt: preferredFormats) - if (snd_pcm_hw_params_test_format(pcmHnd, hwParams, fmt) >= 0) - supportedFormats->append(sampleFormats->key(fmt)); + if (snd_pcm_hw_params_test_format(pcmHnd, hwParams, fmt) >= 0) { + auto format = sampleFormats().key(fmt); + + if (!supportedFormats->contains(format)) + supportedFormats->append(format); + } - for (int channels = 1; channels < 3; channels++) - if (snd_pcm_hw_params_test_channels(pcmHnd, hwParams, uint(channels)) >= 0) - supportedChannels->append(channels); + std::sort(supportedFormats->begin(), supportedFormats->end()); + + if (snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels) < 0) + maxChannels = 3; + else + maxChannels = qBound(1, maxChannels, 16) + 1; + + for (uint channels = 1; channels < maxChannels; channels++) + if (snd_pcm_hw_params_test_channels(pcmHnd, hwParams, channels) >= 0) { + auto layout = AkAudioCaps::defaultChannelLayout(int(channels)); + + if (layout != AkAudioCaps::Layout_none) + supportedLayouts->append(layout); + } for (auto &rate: self->commonSampleRates()) if (snd_pcm_hw_params_test_rate(pcmHnd, hwParams, uint(rate), 0) >= 0) @@ -374,7 +373,7 @@ decltype(this->d->m_sinks) outputs; decltype(this->d->m_pinDescriptionMap) pinDescriptionMap; decltype(this->d->m_supportedFormats) supportedFormats; - decltype(this->d->m_supportedChannels) supportedChannels; + decltype(this->d->m_supportedLayouts) supportedChannels; decltype(this->d->m_supportedSampleRates) supportedSampleRates; int card = -1; @@ -412,60 +411,60 @@ snd_ctl_close(ctlHnd); QList _supportedFormats; - QList _supportedChannels; + QList _supportedLayouts; QList _supportedSampleRates; auto input = deviceId + ":Input"; this->d->fillDeviceInfo(input, &_supportedFormats, - &_supportedChannels, + &_supportedLayouts, &_supportedSampleRates); if (_supportedFormats.isEmpty()) _supportedFormats = this->d->m_supportedFormats.value(input); - if (_supportedChannels.isEmpty()) - _supportedChannels = this->d->m_supportedChannels.value(input); + if (_supportedLayouts.isEmpty()) + _supportedLayouts = this->d->m_supportedLayouts.value(input); if (_supportedSampleRates.isEmpty()) _supportedSampleRates = this->d->m_supportedSampleRates.value(input); if (!_supportedFormats.isEmpty() - && !_supportedChannels.isEmpty() + && !_supportedLayouts.isEmpty() && !_supportedSampleRates.isEmpty()) { inputs << input; pinDescriptionMap[input] = description; supportedFormats[input] = _supportedFormats; - supportedChannels[input] = _supportedChannels; + supportedChannels[input] = _supportedLayouts; supportedSampleRates[input] = _supportedSampleRates; } _supportedFormats.clear(); - _supportedChannels.clear(); + _supportedLayouts.clear(); _supportedSampleRates.clear(); auto output = deviceId + ":Output"; this->d->fillDeviceInfo(output, &_supportedFormats, - &_supportedChannels, + &_supportedLayouts, &_supportedSampleRates); if (_supportedFormats.isEmpty()) _supportedFormats = this->d->m_supportedFormats.value(output); - if (_supportedChannels.isEmpty()) - _supportedChannels = this->d->m_supportedChannels.value(output); + if (_supportedLayouts.isEmpty()) + _supportedLayouts = this->d->m_supportedLayouts.value(output); if (_supportedSampleRates.isEmpty()) _supportedSampleRates = this->d->m_supportedSampleRates.value(output); if (!_supportedFormats.isEmpty() - && !_supportedChannels.isEmpty() + && !_supportedLayouts.isEmpty() && !_supportedSampleRates.isEmpty()) { outputs << output; pinDescriptionMap[output] = description; supportedFormats[output] = _supportedFormats; - supportedChannels[output] = _supportedChannels; + supportedChannels[output] = _supportedLayouts; supportedSampleRates[output] = _supportedSampleRates; } } @@ -490,7 +489,7 @@ QString io = snd_device_name_get_hint(*hint, "IOID"); QList _supportedFormats; - QList _supportedChannels; + QList _supportedLayouts; QList _supportedSampleRates; if (fillInputs && (io.isEmpty() || io == "Input")) { @@ -498,31 +497,31 @@ this->d->fillDeviceInfo(input, &_supportedFormats, - &_supportedChannels, + &_supportedLayouts, &_supportedSampleRates); if (_supportedFormats.isEmpty()) _supportedFormats = this->d->m_supportedFormats.value(input); - if (_supportedChannels.isEmpty()) - _supportedChannels = this->d->m_supportedChannels.value(input); + if (_supportedLayouts.isEmpty()) + _supportedLayouts = this->d->m_supportedLayouts.value(input); if (_supportedSampleRates.isEmpty()) _supportedSampleRates = this->d->m_supportedSampleRates.value(input); if (!_supportedFormats.isEmpty() - && !_supportedChannels.isEmpty() + && !_supportedLayouts.isEmpty() && !_supportedSampleRates.isEmpty()) { inputs << input; pinDescriptionMap[input] = description; supportedFormats[input] = _supportedFormats; - supportedChannels[input] = _supportedChannels; + supportedChannels[input] = _supportedLayouts; supportedSampleRates[input] = _supportedSampleRates; } } _supportedFormats.clear(); - _supportedChannels.clear(); + _supportedLayouts.clear(); _supportedSampleRates.clear(); if (fillOuputs && (io.isEmpty() || io == "Output")) { @@ -530,25 +529,25 @@ this->d->fillDeviceInfo(output, &_supportedFormats, - &_supportedChannels, + &_supportedLayouts, &_supportedSampleRates); if (_supportedFormats.isEmpty()) _supportedFormats = this->d->m_supportedFormats.value(output); - if (_supportedChannels.isEmpty()) - _supportedChannels = this->d->m_supportedChannels.value(output); + if (_supportedLayouts.isEmpty()) + _supportedLayouts = this->d->m_supportedLayouts.value(output); if (_supportedSampleRates.isEmpty()) _supportedSampleRates = this->d->m_supportedSampleRates.value(output); if (!_supportedFormats.isEmpty() - && !_supportedChannels.isEmpty() + && !_supportedLayouts.isEmpty() && !_supportedSampleRates.isEmpty()) { outputs << output; pinDescriptionMap[output] = description; supportedFormats[output] = _supportedFormats; - supportedChannels[output] = _supportedChannels; + supportedChannels[output] = _supportedLayouts; supportedSampleRates[output] = _supportedSampleRates; } } @@ -560,8 +559,8 @@ if (this->d->m_supportedFormats != supportedFormats) this->d->m_supportedFormats = supportedFormats; - if (this->d->m_supportedChannels != supportedChannels) - this->d->m_supportedChannels = supportedChannels; + if (this->d->m_supportedLayouts != supportedChannels) + this->d->m_supportedLayouts = supportedChannels; if (this->d->m_supportedSampleRates != supportedSampleRates) this->d->m_supportedSampleRates = supportedSampleRates; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/alsa/src/audiodevalsa.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/alsa/src/audiodevalsa.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/alsa/src/audiodevalsa.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/alsa/src/audiodevalsa.h 2021-02-15 15:25:23.000000000 +0000 @@ -40,10 +40,10 @@ Q_INVOKABLE QString description(const QString &device); Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); Q_INVOKABLE QList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); + Q_INVOKABLE QList supportedChannelLayouts(const QString &device); Q_INVOKABLE QList supportedSampleRates(const QString &device); Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps); - Q_INVOKABLE QByteArray read(int samples); + Q_INVOKABLE QByteArray read(); Q_INVOKABLE bool write(const AkAudioPacket &packet); Q_INVOKABLE bool uninit(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodev.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodev.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodev.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodev.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -28,6 +28,7 @@ { public: QVector m_commonSampleRates; + int m_latency {25}; }; AudioDev::AudioDev(QObject *parent): @@ -56,69 +57,74 @@ delete this->d; } -QVector &AudioDev::commonSampleRates() +int AudioDev::latency() const +{ + return this->d->m_latency; +} + +const QVector &AudioDev::commonSampleRates() const { return this->d->m_commonSampleRates; } QString AudioDev::error() const { - return QString(); + return {}; } QString AudioDev::defaultInput() { - return QString(); + return {}; } QString AudioDev::defaultOutput() { - return QString(); + return {}; } QStringList AudioDev::inputs() { - return QStringList(); + return {}; } QStringList AudioDev::outputs() { - return QStringList(); + return {}; } QString AudioDev::description(const QString &device) { Q_UNUSED(device) - return QString(); + return {}; } AkAudioCaps AudioDev::preferredFormat(const QString &device) { Q_UNUSED(device) - return AkAudioCaps(); + return {}; } QList AudioDev::supportedFormats(const QString &device) { Q_UNUSED(device) - return QList(); + return {}; } -QList AudioDev::supportedChannels(const QString &device) +QList AudioDev::supportedChannelLayouts(const QString &device) { Q_UNUSED(device) - return QList(); + return {AkAudioCaps::Layout_mono, AkAudioCaps::Layout_stereo}; } QList AudioDev::supportedSampleRates(const QString &device) { Q_UNUSED(device) - return QList(); + return {}; } bool AudioDev::init(const QString &device, const AkAudioCaps &caps) @@ -129,11 +135,9 @@ return false; } -QByteArray AudioDev::read(int samples) +QByteArray AudioDev::read() { - Q_UNUSED(samples) - - return QByteArray(); + return {}; } bool AudioDev::write(const AkAudioPacket &packet) @@ -148,4 +152,18 @@ return true; } +void AudioDev::setLatency(int latency) +{ + if (this->d->m_latency == latency) + return; + + this->d->m_latency = latency; + Q_EMIT this->latencyChanged(latency); +} + +void AudioDev::resetLatency() +{ + this->setLatency(25); +} + #include "moc_audiodev.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodev.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodev.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodev.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodev.h 2021-02-15 15:25:23.000000000 +0000 @@ -28,6 +28,11 @@ class AudioDev: public QObject { Q_OBJECT + Q_PROPERTY(int latency + READ latency + WRITE setLatency + RESET resetLatency + NOTIFY latencyChanged) Q_PROPERTY(QString error READ error NOTIFY errorChanged) @@ -36,7 +41,8 @@ AudioDev(QObject *parent=nullptr); virtual ~AudioDev(); - Q_INVOKABLE QVector &commonSampleRates(); + Q_INVOKABLE int latency() const; + Q_INVOKABLE const QVector &commonSampleRates() const; Q_INVOKABLE virtual QString error() const; Q_INVOKABLE virtual QString defaultInput(); Q_INVOKABLE virtual QString defaultOutput(); @@ -45,10 +51,10 @@ Q_INVOKABLE virtual QString description(const QString &device); Q_INVOKABLE virtual AkAudioCaps preferredFormat(const QString &device); Q_INVOKABLE virtual QList supportedFormats(const QString &device); - Q_INVOKABLE virtual QList supportedChannels(const QString &device); + Q_INVOKABLE virtual QList supportedChannelLayouts(const QString &device); Q_INVOKABLE virtual QList supportedSampleRates(const QString &device); Q_INVOKABLE virtual bool init(const QString &device, const AkAudioCaps &caps); - Q_INVOKABLE virtual QByteArray read(int samples); + Q_INVOKABLE virtual QByteArray read(); Q_INVOKABLE virtual bool write(const AkAudioPacket &packet); Q_INVOKABLE virtual bool uninit(); @@ -56,11 +62,16 @@ AudioDevPrivate *d; Q_SIGNALS: + void latencyChanged(int latency); void errorChanged(const QString &error); void defaultInputChanged(const QString &defaultInput); void defaultOutputChanged(const QString &defaultOutput); void inputsChanged(const QStringList &inputs); void outputsChanged(const QStringList &outputs); + + public Q_SLOTS: + void setLatency(int latency); + void resetLatency(); }; #endif // AUDIODEV_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodevice.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodevice.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodevice.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodevice.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include "audiodevice.h" #include "audiodeviceelement.h" +#include "audiodeviceelementsettings.h" QObject *AudioDevice::create(const QString &key, const QString &specification) { @@ -26,13 +27,16 @@ if (key == AK_PLUGIN_TYPE_ELEMENT) return new AudioDeviceElement(); + else if (key == AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + return new AudioDeviceElementSettings(); return nullptr; } QStringList AudioDevice::keys() const { - return QStringList(); + return {AK_PLUGIN_TYPE_ELEMENT, + AK_PLUGIN_TYPE_ELEMENT_SETTINGS}; } #include "moc_audiodevice.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -24,11 +24,11 @@ #include #include #include -#include +#include #include #include "audiodeviceelement.h" -#include "audiodeviceglobals.h" +#include "audiodeviceelementsettings.h" #include "audiodev.h" #define PAUSE_TIMEOUT 500 @@ -38,8 +38,6 @@ #include #endif -Q_GLOBAL_STATIC(AudioDeviceGlobals, globalAudioDevice) - template inline QSharedPointer ptr_cast(QObject *obj=nullptr) { @@ -52,39 +50,38 @@ { public: AudioDeviceElement *self; + AudioDeviceElementSettings m_settings; QStringList m_inputs; QStringList m_outputs; QString m_device; - AkCaps m_caps; + AkAudioCaps m_caps; AudioDevPtr m_audioDevice; AkElementPtr m_convert {AkElement::create("ACapsConvert")}; QThreadPool m_threadPool; QFuture m_readFramesLoopResult; QMutex m_mutex; QMutex m_mutexLib; - int m_bufferSize {1024}; bool m_readFramesLoop {false}; bool m_pause {false}; explicit AudioDeviceElementPrivate(AudioDeviceElement *self); void readFramesLoop(); + void setInputs(const QStringList &inputs); + void setOutputs(const QStringList &outputs); + void audioLibUpdated(const QString &audioLib); }; AudioDeviceElement::AudioDeviceElement(): AkElement() { this->d = new AudioDeviceElementPrivate(this); + QObject::connect(&this->d->m_settings, + &AudioDeviceElementSettings::audioLibChanged, + [this] (const QString &audioLib) { + this->d->audioLibUpdated(audioLib); + }); - QObject::connect(globalAudioDevice, - SIGNAL(audioLibChanged(const QString &)), - this, - SIGNAL(audioLibChanged(const QString &))); - QObject::connect(globalAudioDevice, - SIGNAL(audioLibChanged(const QString &)), - this, - SLOT(audioLibUpdated(const QString &))); - - this->audioLibUpdated(globalAudioDevice->audioLib()); + this->d->audioLibUpdated(this->d->m_settings.audioLib()); } AudioDeviceElement::~AudioDeviceElement() @@ -153,12 +150,15 @@ return this->d->m_device; } -int AudioDeviceElement::bufferSize() const +int AudioDeviceElement::latency() const { - return this->d->m_bufferSize; + if (this->d->m_audioDevice) + return this->d->m_audioDevice->latency(); + + return 25; } -AkCaps AudioDeviceElement::caps() const +AkAudioCaps AudioDeviceElement::caps() const { return this->d->m_caps; } @@ -167,7 +167,7 @@ { if (device == DUMMY_OUTPUT_DEVICE) return AkAudioCaps(AkAudioCaps::SampleFormat_s16, - 2, + AkAudioCaps::Layout_stereo, 44100); AkAudioCaps preferredFormat; @@ -204,21 +204,25 @@ return supportedFormats; } -QList AudioDeviceElement::supportedChannels(const QString &device) +QList AudioDeviceElement::supportedChannelLayouts(const QString &device) { if (device == DUMMY_OUTPUT_DEVICE) - return QList {1, 2}; + return QList { + AkAudioCaps::Layout_mono, + AkAudioCaps::Layout_stereo, + }; - QList supportedChannels; + QList supportedChannelLayouts; this->d->m_mutexLib.lock(); if (this->d->m_audioDevice) - supportedChannels = this->d->m_audioDevice->supportedChannels(device); + supportedChannelLayouts = + this->d->m_audioDevice->supportedChannelLayouts(device); this->d->m_mutexLib.unlock(); - return supportedChannels; + return supportedChannelLayouts; } QList AudioDeviceElement::supportedSampleRates(const QString &device) @@ -238,11 +242,6 @@ return supportedSampleRates; } -QString AudioDeviceElement::audioLib() const -{ - return globalAudioDevice->audioLib(); -} - AudioDeviceElementPrivate::AudioDeviceElementPrivate(AudioDeviceElement *self): self(self) { @@ -271,27 +270,25 @@ continue; } - int bufferSize = this->m_bufferSize; - QByteArray buffer = this->m_audioDevice->read(bufferSize); + auto buffer = this->m_audioDevice->read(); if (buffer.isEmpty()) return; QByteArray oBuffer(buffer.size(), 0); memcpy(oBuffer.data(), buffer.constData(), size_t(buffer.size())); - - caps.samples() = bufferSize; - AkAudioPacket packet(caps, oBuffer); - - qint64 pts = qint64(QTime::currentTime().msecsSinceStartOfDay() - / timeBase.value() / 1e3); - + auto pts = qint64(QTime::currentTime().msecsSinceStartOfDay() + / timeBase.value() / 1e3); + caps.setSamples(8 * buffer.size() / (caps.channels() * caps.bps())); + AkAudioPacket packet; + packet.caps() = caps; + packet.buffer() = oBuffer; packet.setPts(pts); packet.setTimeBase(timeBase); packet.setIndex(0); packet.setId(streamId); - emit self->oStream(packet.toPacket()); + emit self->oStream(packet); } this->m_audioDevice->uninit(); @@ -303,64 +300,91 @@ #endif } -void AudioDeviceElement::setDevice(const QString &device) +void AudioDeviceElementPrivate::setInputs(const QStringList &inputs) { - if (this->d->m_device == device) + if (this->m_inputs == inputs) return; - this->d->m_device = device; - emit this->deviceChanged(device); + this->m_inputs = inputs; + emit self->inputsChanged(inputs); } -void AudioDeviceElement::setBufferSize(int bufferSize) +void AudioDeviceElementPrivate::setOutputs(const QStringList &outputs) { - if (this->d->m_bufferSize == bufferSize) + if (this->m_outputs == outputs) return; - this->d->m_bufferSize = bufferSize; - emit this->bufferSizeChanged(bufferSize); + this->m_outputs = outputs; + emit self->outputsChanged(outputs); } -void AudioDeviceElement::setCaps(const AkCaps &caps) +void AudioDeviceElementPrivate::audioLibUpdated(const QString &audioLib) { - if (this->d->m_caps == caps) - return; + auto state = self->state(); + self->setState(AkElement::ElementStateNull); - this->d->m_caps = caps; - this->d->m_convert->setProperty("caps", caps.toString()); - emit this->capsChanged(caps); -} + bool isInput = this->m_inputs.contains(this->m_device); -void AudioDeviceElement::setAudioLib(const QString &audioLib) -{ - globalAudioDevice->setAudioLib(audioLib); -} + this->m_mutexLib.lock(); + int latency = 25; -void AudioDeviceElement::resetDevice() -{ - this->setDevice(""); -} + if (this->m_audioDevice) + latency = this->m_audioDevice->latency(); -void AudioDeviceElement::resetBufferSize() -{ - this->setBufferSize(1024); -} + this->m_audioDevice = + ptr_cast(AudioDeviceElement::loadSubModule("AudioDevice", + audioLib)); -void AudioDeviceElement::resetCaps() -{ - this->d->m_mutexLib.lock(); - auto preferredFormat = this->preferredFormat(this->d->m_device); - this->d->m_mutexLib.unlock(); + if (!this->m_audioDevice) { + this->m_mutexLib.unlock(); - this->setCaps(preferredFormat.toCaps()); -} + return; + } -void AudioDeviceElement::resetAudioLib() -{ - globalAudioDevice->resetAudioLib(); + this->m_mutexLib.unlock(); + + QObject::connect(this->m_audioDevice.data(), + &AudioDev::defaultInputChanged, + self, + &AudioDeviceElement::defaultInputChanged); + QObject::connect(this->m_audioDevice.data(), + &AudioDev::defaultOutputChanged, + self, + &AudioDeviceElement::defaultOutputChanged); + QObject::connect(this->m_audioDevice.data(), + &AudioDev::latencyChanged, + self, + &AudioDeviceElement::latencyChanged); + QObject::connect(this->m_audioDevice.data(), + &AudioDev::inputsChanged, + [this] (const QStringList &inputs) { + this->setInputs(inputs); + }); + QObject::connect(this->m_audioDevice.data(), + &AudioDev::outputsChanged, + [this] (const QStringList &outputs) { + this->setOutputs(outputs); + }); + + this->m_audioDevice->setLatency(latency); + this->setInputs(this->m_audioDevice->inputs()); + this->setOutputs(this->m_audioDevice->outputs()); + emit self->defaultInputChanged(this->m_audioDevice->defaultInput()); + emit self->defaultOutputChanged(this->m_audioDevice->defaultOutput()); + + if (this->m_device != DUMMY_OUTPUT_DEVICE) { + self->setDevice(isInput? + this->m_audioDevice->defaultInput(): + this->m_audioDevice->defaultOutput()); + auto preferredFormat = + this->m_audioDevice->preferredFormat(this->m_device); + self->setCaps(preferredFormat); + } + + self->setState(state); } -AkPacket AudioDeviceElement::iStream(const AkAudioPacket &packet) +AkPacket AudioDeviceElement::iAudioStream(const AkAudioPacket &packet) { if (!this->d->m_audioDevice) return AkPacket(); @@ -386,7 +410,7 @@ this->d->m_mutex.lock(); if (this->d->m_convert) - iPacket = this->d->m_convert->iStream(packet.toPacket()); + iPacket = this->d->m_convert->iStream(packet); this->d->m_mutex.unlock(); @@ -400,6 +424,54 @@ return AkPacket(); } +void AudioDeviceElement::setDevice(const QString &device) +{ + if (this->d->m_device == device) + return; + + this->d->m_device = device; + emit this->deviceChanged(device); +} + +void AudioDeviceElement::setLatency(int latency) +{ + if (this->d->m_audioDevice) + this->d->m_audioDevice->setLatency(latency); +} + +void AudioDeviceElement::setCaps(const AkAudioCaps &caps) +{ + if (this->d->m_caps == caps) + return; + + this->d->m_caps = caps; + + if (this->d->m_convert) + this->d->m_convert->setProperty("caps", QVariant::fromValue(caps)); + + emit this->capsChanged(caps); +} + +void AudioDeviceElement::resetDevice() +{ + this->setDevice(""); +} + +void AudioDeviceElement::resetLatency() +{ + if (this->d->m_audioDevice) + this->d->m_audioDevice->resetLatency(); +} + +void AudioDeviceElement::resetCaps() +{ + this->d->m_mutexLib.lock(); + auto preferredFormat = this->preferredFormat(this->d->m_device); + this->d->m_mutexLib.unlock(); + + this->setCaps(preferredFormat); +} + bool AudioDeviceElement::setState(AkElement::ElementState state) { if (!this->d->m_audioDevice) @@ -415,9 +487,10 @@ this->d->m_convert->setState(state); this->d->m_pause = true; this->d->m_readFramesLoop = true; - this->d->m_readFramesLoopResult = QtConcurrent::run(&this->d->m_threadPool, - this->d, - &AudioDeviceElementPrivate::readFramesLoop); + this->d->m_readFramesLoopResult = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &AudioDeviceElementPrivate::readFramesLoop); } return AkElement::setState(state); @@ -427,9 +500,10 @@ this->d->m_convert->setState(state); this->d->m_pause = false; this->d->m_readFramesLoop = true; - this->d->m_readFramesLoopResult = QtConcurrent::run(&this->d->m_threadPool, - this->d, - &AudioDeviceElementPrivate::readFramesLoop); + this->d->m_readFramesLoopResult = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &AudioDeviceElementPrivate::readFramesLoop); } else if (this->d->m_device != DUMMY_OUTPUT_DEVICE && this->d->m_outputs.contains(this->d->m_device)) { this->d->m_convert->setState(state); @@ -536,76 +610,4 @@ return false; } -void AudioDeviceElement::setInputs(const QStringList &inputs) -{ - if (this->d->m_inputs == inputs) - return; - - this->d->m_inputs = inputs; - emit this->inputsChanged(inputs); -} - -void AudioDeviceElement::setOutputs(const QStringList &outputs) -{ - if (this->d->m_outputs == outputs) - return; - - this->d->m_outputs = outputs; - emit this->outputsChanged(outputs); -} - -void AudioDeviceElement::audioLibUpdated(const QString &audioLib) -{ - auto state = this->state(); - this->setState(AkElement::ElementStateNull); - - bool isInput = this->d->m_inputs.contains(this->d->m_device); - - this->d->m_mutexLib.lock(); - - this->d->m_audioDevice = - ptr_cast(AudioDeviceElement::loadSubModule("AudioDevice", - audioLib)); - - if (!this->d->m_audioDevice) { - this->d->m_mutexLib.unlock(); - - return; - } - - this->d->m_mutexLib.unlock(); - - QObject::connect(this->d->m_audioDevice.data(), - &AudioDev::defaultInputChanged, - this, - &AudioDeviceElement::defaultInputChanged); - QObject::connect(this->d->m_audioDevice.data(), - &AudioDev::defaultOutputChanged, - this, - &AudioDeviceElement::defaultOutputChanged); - QObject::connect(this->d->m_audioDevice.data(), - &AudioDev::inputsChanged, - this, - &AudioDeviceElement::setInputs); - QObject::connect(this->d->m_audioDevice.data(), - &AudioDev::outputsChanged, - this, - &AudioDeviceElement::setOutputs); - - this->setInputs(this->d->m_audioDevice->inputs()); - this->setOutputs(this->d->m_audioDevice->outputs()); - emit this->defaultInputChanged(this->d->m_audioDevice->defaultInput()); - emit this->defaultOutputChanged(this->d->m_audioDevice->defaultOutput()); - - if (this->d->m_device != DUMMY_OUTPUT_DEVICE) { - this->setDevice(isInput? - this->d->m_audioDevice->defaultInput(): - this->d->m_audioDevice->defaultOutput()); - auto preferredFormat = this->d->m_audioDevice->preferredFormat(this->d->m_device); - this->setCaps(preferredFormat.toCaps()); - } - - this->setState(state); -} - #include "moc_audiodeviceelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -24,7 +24,6 @@ #include class AudioDeviceElementPrivate; -class AkCaps; class AudioDeviceElement: public AkElement { @@ -46,22 +45,17 @@ WRITE setDevice RESET resetDevice NOTIFY deviceChanged) - // Buffer size in samples. - Q_PROPERTY(int bufferSize - READ bufferSize - WRITE setBufferSize - RESET resetBufferSize - NOTIFY bufferSizeChanged) - Q_PROPERTY(AkCaps caps + // In milliseconds + Q_PROPERTY(int latency + READ latency + WRITE setLatency + RESET resetLatency + NOTIFY latencyChanged) + Q_PROPERTY(AkAudioCaps caps READ caps WRITE setCaps RESET resetCaps NOTIFY capsChanged) - Q_PROPERTY(QString audioLib - READ audioLib - WRITE setAudioLib - RESET resetAudioLib - NOTIFY audioLibChanged) public: AudioDeviceElement(); @@ -73,43 +67,36 @@ Q_INVOKABLE QStringList outputs(); Q_INVOKABLE QString description(const QString &device); Q_INVOKABLE QString device() const; - Q_INVOKABLE int bufferSize() const; - Q_INVOKABLE AkCaps caps() const; + Q_INVOKABLE int latency() const; + Q_INVOKABLE AkAudioCaps caps() const; Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); Q_INVOKABLE QList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); + Q_INVOKABLE QList supportedChannelLayouts(const QString &device); Q_INVOKABLE QList supportedSampleRates(const QString &device); - Q_INVOKABLE QString audioLib() const; private: AudioDeviceElementPrivate *d; + protected: + AkPacket iAudioStream(const AkAudioPacket &packet); + signals: void defaultInputChanged(const QString &defaultInput); void defaultOutputChanged(const QString &defaultOutput); void inputsChanged(const QStringList &inputs); void outputsChanged(const QStringList &outputs); void deviceChanged(const QString &device); - void bufferSizeChanged(int bufferSize); - void capsChanged(const AkCaps &caps); - void audioLibChanged(const QString &audioLib); + void latencyChanged(int latency); + void capsChanged(const AkAudioCaps &caps); public slots: void setDevice(const QString &device); - void setBufferSize(int bufferSize); - void setCaps(const AkCaps &caps); - void setAudioLib(const QString &audioLib); + void setLatency(int latency); + void setCaps(const AkAudioCaps &caps); void resetDevice(); - void resetBufferSize(); + void resetLatency(); void resetCaps(); - void resetAudioLib(); - AkPacket iStream(const AkAudioPacket &packet); bool setState(AkElement::ElementState state); - - private slots: - void setInputs(const QStringList &inputs); - void setOutputs(const QStringList &outputs); - void audioLibUpdated(const QString &audioLib); }; #endif // AUDIODEVICEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelementsettings.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelementsettings.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelementsettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelementsettings.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,54 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "audiodeviceelementsettings.h" +#include "audiodeviceglobals.h" + +Q_GLOBAL_STATIC(AudioDeviceGlobals, globalAudioDevice) + +AudioDeviceElementSettings::AudioDeviceElementSettings(QObject *parent): + QObject(parent) +{ + QObject::connect(globalAudioDevice, + &AudioDeviceGlobals::audioLibChanged, + this, + &AudioDeviceElementSettings::audioLibChanged); +} + +QString AudioDeviceElementSettings::audioLib() const +{ + return globalAudioDevice->audioLib(); +} + +QStringList AudioDeviceElementSettings::subModules() const +{ + return globalAudioDevice->subModules(); +} + +void AudioDeviceElementSettings::setAudioLib(const QString &audioLib) +{ + globalAudioDevice->setAudioLib(audioLib); +} + +void AudioDeviceElementSettings::resetAudioLib() +{ + globalAudioDevice->resetAudioLib(); +} + +#include "moc_audiodeviceelementsettings.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelementsettings.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelementsettings.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelementsettings.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceelementsettings.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,52 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef AUDIODEVICEELEMENTSETTINGS_H +#define AUDIODEVICEELEMENTSETTINGS_H + +#include + +class AudioDeviceElementSettings: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString audioLib + READ audioLib + WRITE setAudioLib + RESET resetAudioLib + NOTIFY audioLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules + NOTIFY subModulesChanged) + + public: + AudioDeviceElementSettings(QObject *parent=nullptr); + + Q_INVOKABLE QString audioLib() const; + Q_INVOKABLE QStringList subModules() const; + + signals: + void audioLibChanged(const QString &audioLib); + void subModulesChanged(const QStringList &subModules); + + public slots: + void setAudioLib(const QString &audioLib); + void resetAudioLib(); +}; + +#endif // AUDIODEVICEELEMENTSETTINGS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceglobals.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceglobals.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceglobals.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceglobals.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,41 +21,43 @@ #include "audiodeviceglobals.h" +class AudioDeviceGlobalsPrivate +{ + public: + QString m_audioLib; + QStringList m_preferredLibrary; + + AudioDeviceGlobalsPrivate(); +}; + AudioDeviceGlobals::AudioDeviceGlobals(QObject *parent): QObject(parent) { - this->m_preferredLibrary = QStringList { -#ifdef Q_OS_WIN32 - "wasapi", - "qtaudio" -#elif defined(Q_OS_OSX) - "coreaudio", - "pulseaudio", - "jack", - "qtaudio" -#else - "pulseaudio", - "alsa", - "oss", - "jack", - "qtaudio" -#endif - }; - + this->d = new AudioDeviceGlobalsPrivate; this->resetAudioLib(); } +AudioDeviceGlobals::~AudioDeviceGlobals() +{ + delete this->d; +} + QString AudioDeviceGlobals::audioLib() const { - return this->m_audioLib; + return this->d->m_audioLib; +} + +QStringList AudioDeviceGlobals::subModules() const +{ + return AkElement::listSubModules("AudioDevice"); } void AudioDeviceGlobals::setAudioLib(const QString &audioLib) { - if (this->m_audioLib == audioLib) + if (this->d->m_audioLib == audioLib) return; - this->m_audioLib = audioLib; + this->d->m_audioLib = audioLib; emit this->audioLibChanged(audioLib); } @@ -63,15 +65,37 @@ { auto subModules = AkElement::listSubModules("AudioDevice"); - for (auto &framework: this->m_preferredLibrary) + for (auto &framework: this->d->m_preferredLibrary) if (subModules.contains(framework)) { this->setAudioLib(framework); return; } - if (this->m_audioLib.isEmpty() && !subModules.isEmpty()) + if (this->d->m_audioLib.isEmpty() && !subModules.isEmpty()) this->setAudioLib(subModules.first()); else this->setAudioLib(""); } + +AudioDeviceGlobalsPrivate::AudioDeviceGlobalsPrivate() +{ + this->m_preferredLibrary = QStringList { +#ifdef Q_OS_WIN32 + "wasapi", +#elif defined(Q_OS_OSX) + "coreaudio", + "pulseaudio", + "jack", +#elif defined(Q_OS_ANDROID) + "ndkaudio", + "opensl", +#else + "pulseaudio", + "alsa", + "jack", +#endif + }; +} + +#include "moc_audiodeviceglobals.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceglobals.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceglobals.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceglobals.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/audiodeviceglobals.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,8 @@ #include +class AudioDeviceGlobalsPrivate; + class AudioDeviceGlobals: public QObject { Q_OBJECT @@ -30,15 +32,18 @@ WRITE setAudioLib RESET resetAudioLib NOTIFY audioLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules) public: AudioDeviceGlobals(QObject *parent=nullptr); + ~AudioDeviceGlobals(); Q_INVOKABLE QString audioLib() const; + Q_INVOKABLE QStringList subModules() const; private: - QString m_audioLib; - QStringList m_preferredLibrary; + AudioDeviceGlobalsPrivate *d; signals: void audioLibChanged(const QString &audioLib); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/coreaudio/src/audiodevcoreaudio.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/coreaudio/src/audiodevcoreaudio.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/coreaudio/src/audiodevcoreaudio.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/coreaudio/src/audiodevcoreaudio.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -42,7 +42,7 @@ QMap m_descriptionMap; QMap m_defaultCaps; QMap> m_supportedFormats; - QMap> m_supportedChannels; + QMap> m_supportedLayouts; QMap> m_supportedSampleRates; AudioUnit m_audioUnit {nullptr}; UInt32 m_bufferSize {0}; @@ -52,6 +52,7 @@ QWaitCondition m_canWrite; QWaitCondition m_samplesAvailable; AkAudioCaps m_curCaps; + int m_samples {0}; int m_maxBufferSize {0}; bool m_isInput {false}; @@ -62,8 +63,8 @@ void clearBuffer(); QList supportedCAFormats(AudioDeviceID deviceId, AudioObjectPropertyScope scope); - QList supportedCAChannels(AudioDeviceID deviceId, - AudioObjectPropertyScope scope); + QList supportedCALayouts(AudioDeviceID deviceId, + AudioObjectPropertyScope scope); QList supportedCASampleRates(AudioDeviceID deviceId, AudioObjectPropertyScope scope); AkAudioCaps::SampleFormat descriptionToSampleFormat(const AudioStreamBasicDescription &streamDescription); @@ -208,9 +209,9 @@ return this->d->m_supportedFormats.value(device); } -QList AudioDevCoreAudio::supportedChannels(const QString &device) +QList AudioDevCoreAudio::supportedChannelLayouts(const QString &device) { - return this->d->m_supportedChannels.value(device); + return this->d->m_supportedLayouts.value(device); } QList AudioDevCoreAudio::supportedSampleRates(const QString &device) @@ -352,7 +353,7 @@ AkAudioCaps::endianness(caps.format()) == Q_BIG_ENDIAN? kAudioFormatFlagIsBigEndian: 0; AudioFormatFlags sampleIsPlanar = - AkAudioCaps::isPlanar(caps.format())? + caps.planar()? kAudioFormatFlagIsNonInterleaved: 0; AudioStreamBasicDescription streamDescription; @@ -452,20 +453,19 @@ & kAudioFormatFlagIsNonInterleaved)? 1: streamDescription.mChannelsPerFrame; this->d->m_bufferList->mBuffers[i].mDataByteSize = 0; - this->d->m_bufferList->mBuffers[i].mData = 0; + this->d->m_bufferList->mBuffers[i].mData = nullptr; } + this->d->m_samples = qMax(this->latency() * caps.rate() / 1000, 1); + return true; } -QByteArray AudioDevCoreAudio::read(int samples) +QByteArray AudioDevCoreAudio::read() { - if (samples < 1) - return {}; - int bufferSize = this->d->m_curCaps.bps() * this->d->m_curCaps.channels() - * samples / 8; + * this->d->m_samples / 8; QByteArray audioData; this->d->m_mutex.lock(); @@ -544,7 +544,7 @@ UniChar str[len]; CFStringGetCharacters(cfstr, CFRangeMake(0, len), str); - return QString(reinterpret_cast(str), len); + return QString(reinterpret_cast(str), int(len)); } QString AudioDevCoreAudioPrivate::defaultDevice(bool input, bool *ok) @@ -585,7 +585,7 @@ { for (UInt32 i = 0; i < self->d->m_bufferList->mNumberBuffers; i++) { self->d->m_bufferList->mBuffers[i].mDataByteSize = 0; - self->d->m_bufferList->mBuffers[i].mData = 0; + self->d->m_bufferList->mBuffers[i].mData = nullptr; } } @@ -610,7 +610,7 @@ int nStreams = propSize / sizeof(AudioStreamID); if (status != noErr || nStreams < 1) - return QList(); + return {}; QVector streams(nStreams); @@ -630,10 +630,6 @@ AkAudioCaps::SampleFormat_s32, AkAudioCaps::SampleFormat_s16, AkAudioCaps::SampleFormat_u8 -// AkAudioCaps::SampleFormat_fltp, -// AkAudioCaps::SampleFormat_s32p, -// AkAudioCaps::SampleFormat_s16p, -// AkAudioCaps::SampleFormat_u8p, }; static const QVector selectorType { @@ -687,11 +683,13 @@ } } + std::sort(supportedFormats.begin(), supportedFormats.end()); + return supportedFormats; } -QList AudioDevCoreAudioPrivate::supportedCAChannels(AudioDeviceID deviceId, - AudioObjectPropertyScope scope) +QList AudioDevCoreAudioPrivate::supportedCALayouts(AudioDeviceID deviceId, + AudioObjectPropertyScope scope) { UInt32 propSize = 0; AudioObjectPropertyAddress streamConfiguration = { @@ -707,12 +705,12 @@ &propSize); if (status != noErr) - return QList(); + return {}; int nBuffers = propSize / sizeof(AudioBufferList); if (nBuffers < 1) - return QList(); + return {}; QVector buffers(nBuffers); @@ -724,9 +722,9 @@ buffers.data()); if (status != noErr) - return QList(); + return {}; - QList supportedCAChannels; + QList supportedCALayouts; for (auto &buffer: buffers) { int channels = 0; @@ -734,11 +732,14 @@ for (UInt32 i = 0; i < buffer.mNumberBuffers; i++) channels += buffer.mBuffers[i].mNumberChannels; - if (!supportedCAChannels.contains(channels)) - supportedCAChannels << channels; + auto layout = AkAudioCaps::defaultChannelLayout(channels); + + if (layout != AkAudioCaps::Layout_none + && !supportedCALayouts.contains(layout)) + supportedCALayouts << layout; } - return supportedCAChannels; + return supportedCALayouts; } QList AudioDevCoreAudioPrivate::supportedCASampleRates(AudioDeviceID deviceId, @@ -810,12 +811,10 @@ Q_BYTE_ORDER: (streamDescription.mFormatFlags & kAudioFormatFlagIsBigEndian)? Q_BIG_ENDIAN: Q_LITTLE_ENDIAN; - bool planar = streamDescription.mFormatFlags & kAudioFormatFlagIsNonInterleaved; return AkAudioCaps::sampleFormatFromProperties(formatType, int(bps), - endian, - planar); + endian); } OSStatus AudioDevCoreAudioPrivate::devicesChangedCallback(AudioObjectID objectId, @@ -972,7 +971,7 @@ decltype(this->d->m_descriptionMap) descriptionMap; decltype(this->d->m_defaultCaps) defaultCaps; decltype(this->d->m_supportedFormats) supportedFormats; - decltype(this->d->m_supportedChannels) supportedChannels; + decltype(this->d->m_supportedLayouts) supportedLayouts; decltype(this->d->m_supportedSampleRates) supportedSampleRates; // List default devices @@ -1056,13 +1055,13 @@ CFRelease(name); auto formats = this->d->supportedCAFormats(deviceId, deviceType); - auto channels = this->d->supportedCAChannels(deviceId, - deviceType); + auto layouts = this->d->supportedCALayouts(deviceId, + deviceType); auto sampleRates = this->d->supportedCASampleRates(deviceId, deviceType); if (formats.isEmpty() - || channels.isEmpty() + || layouts.isEmpty() || sampleRates.isEmpty()) continue; @@ -1079,11 +1078,12 @@ descriptionMap[devId] = description; supportedFormats[devId] = formats; - supportedChannels[devId] = channels; + supportedLayouts[devId] = layouts; supportedSampleRates[devId] = sampleRates; - defaultCaps[devId] = AkAudioCaps(formats.first(), - channels.first(), - sampleRates.first()); + defaultCaps[devId] = + AkAudioCaps(formats.first(), + AkAudioCaps::defaultChannelLayout(layouts.first()), + sampleRates.first()); } } } @@ -1096,8 +1096,8 @@ if (this->d->m_supportedFormats != supportedFormats) this->d->m_supportedFormats = supportedFormats; - if (this->d->m_supportedChannels != supportedChannels) - this->d->m_supportedChannels = supportedChannels; + if (this->d->m_supportedLayouts != supportedLayouts) + this->d->m_supportedLayouts = supportedLayouts; if (this->d->m_supportedSampleRates != supportedSampleRates) this->d->m_supportedSampleRates = supportedSampleRates; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/coreaudio/src/audiodevcoreaudio.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/coreaudio/src/audiodevcoreaudio.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/coreaudio/src/audiodevcoreaudio.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/coreaudio/src/audiodevcoreaudio.h 2021-02-15 15:25:23.000000000 +0000 @@ -40,10 +40,10 @@ Q_INVOKABLE QString description(const QString &device); Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); Q_INVOKABLE QList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); + Q_INVOKABLE QList supportedChannelLayouts(const QString &device); Q_INVOKABLE QList supportedSampleRates(const QString &device); Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps); - Q_INVOKABLE QByteArray read(int samples); + Q_INVOKABLE QByteArray read(); Q_INVOKABLE bool write(const AkAudioPacket &packet); Q_INVOKABLE bool uninit(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/audiodevjack.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/audiodevjack.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/audiodevjack.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/audiodevjack.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -68,6 +68,7 @@ QMutex m_mutex; QWaitCondition m_canWrite; QWaitCondition m_samplesAvailable; + int m_samples {0}; int m_sampleRate {0}; int m_curChannels {0}; int m_maxBufferSize {0}; @@ -138,7 +139,7 @@ if (channels > 0) this->d->m_caps[it.key()] = AkAudioCaps(AkAudioCaps::SampleFormat_flt, - channels, + AkAudioCaps::defaultChannelLayout(qBound(1, channels, 2)), this->d->m_sampleRate); } } @@ -200,12 +201,16 @@ return QList {AkAudioCaps::SampleFormat_flt}; } -QList AudioDevJack::supportedChannels(const QString &device) +QList AudioDevJack::supportedChannelLayouts(const QString &device) { - QList supportedChannels; + QList supportedChannels; - for (int i = 0; i < this->d->m_devicePorts.value(device).size(); i++) - supportedChannels << i + 1; + for (int i = 0; i < this->d->m_devicePorts.value(device).size(); i++) { + auto layout = AkAudioCaps::defaultChannelLayout(i + 1); + + if (layout != AkAudioCaps::Layout_none) + supportedChannels << layout; + } return supportedChannels; } @@ -304,19 +309,17 @@ * uint(caps.channels()) * bufferSize); this->d->m_isInput = device == ":jackinput:"; + this->d->m_samples = qMax(this->latency() * caps.rate() / 1000, 1); return true; } -QByteArray AudioDevJack::read(int samples) +QByteArray AudioDevJack::read() { - if (samples < 1) - return {}; - int bufferSize = 2 * int(sizeof(jack_default_audio_sample_t)) * this->d->m_curChannels - * samples; + * this->d->m_samples; QByteArray audioData; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/audiodevjack.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/audiodevjack.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/audiodevjack.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/audiodevjack.h 2021-02-15 15:25:23.000000000 +0000 @@ -40,10 +40,10 @@ Q_INVOKABLE QString description(const QString &device); Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); Q_INVOKABLE QList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); + Q_INVOKABLE QList supportedChannelLayouts(const QString &device); Q_INVOKABLE QList supportedSampleRates(const QString &device); Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps); - Q_INVOKABLE QByteArray read(int samples); + Q_INVOKABLE QByteArray read(); Q_INVOKABLE bool write(const AkAudioPacket &packet); Q_INVOKABLE bool uninit(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/jackserver.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/jackserver.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/jackserver.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/jackserver.h 2021-02-15 15:25:23.000000000 +0000 @@ -34,8 +34,8 @@ #define LOAD_FUNC(library, func) \ m_##func = reinterpret_cast(library.resolve(#func)) -typedef bool (*on_device_acquire_t)(const char *device_name); -typedef void (*on_device_release_t)(const char *device_name); +using on_device_acquire_t = bool (*)(const char *device_name); +using on_device_release_t = void (*)(const char *device_name); class JackServer: public QObject { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/jackservertypedefs.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/jackservertypedefs.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/jackservertypedefs.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/jack/src/jackservertypedefs.h 2021-02-15 15:25:23.000000000 +0000 @@ -48,8 +48,8 @@ JackParamBool } jackctl_param_type_t; -typedef struct jackctl_server jackctl_server_t; -typedef struct jackctl_driver jackctl_driver_t; -typedef struct jackctl_parameter jackctl_parameter_t; +using jackctl_server_t = struct jackctl_server; +using jackctl_driver_t = struct jackctl_driver; +using jackctl_parameter_t = struct jackctl_parameter; #endif // JACKSERVERTYPEDEFS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/ndkaudio.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/ndkaudio.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/ndkaudio.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/ndkaudio.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,64 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../akcommons.pri) { + include(../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +CONFIG += plugin + +HEADERS = \ + src/plugin.h \ + src/audiodevndkaudio.h \ + ../audiodev.h + +INCLUDEPATH += \ + ../../../../Lib/src \ + ../ + +LIBS += -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} +LIBS += -laaudio + +OTHER_FILES += pspec.json + +QT += qml + +SOURCES = \ + src/plugin.cpp \ + src/audiodevndkaudio.cpp \ + ../audiodev.cpp + +akModule = AudioDevice +DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,3 @@ +{ + "pluginType": "Ak.SubModule" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/audiodevndkaudio.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/audiodevndkaudio.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/audiodevndkaudio.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/audiodevndkaudio.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,375 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include + +#include "audiodevndkaudio.h" + +#define N_BUFFERS 4 + +class AudioDevNDKAudioPrivate +{ + public: + AudioDevNDKAudio *self; + QString m_error; + QStringList m_sinks; + QStringList m_sources; + QMap m_pinDescriptionMap; + QMap> m_supportedFormats; + QMap> m_supportedLayouts; + QMap> m_supportedSampleRates; + QMap m_preferredCaps; + QMutex m_mutex; + AAudioStreamBuilder *m_streamBuilder {nullptr}; + AAudioStream *m_stream {nullptr}; + int m_samples {0}; + + explicit AudioDevNDKAudioPrivate(AudioDevNDKAudio *self); + AAudioStream *createStream(AAudioStreamBuilder *streamBuilder, + aaudio_direction_t direction, + const AkAudioCaps &caps); + static void errorCallback(AAudioStream *stream, + void *userData, + aaudio_result_t error); + void updateDevices(); +}; + +AudioDevNDKAudio::AudioDevNDKAudio(QObject *parent): + AudioDev(parent) +{ + this->d = new AudioDevNDKAudioPrivate(this); + this->d->updateDevices(); +} + +AudioDevNDKAudio::~AudioDevNDKAudio() +{ + this->uninit(); + delete this->d; +} + +QString AudioDevNDKAudio::error() const +{ + return this->d->m_error; +} + +QString AudioDevNDKAudio::defaultInput() +{ + return this->d->m_sources.value(0); +} + +QString AudioDevNDKAudio::defaultOutput() +{ + return this->d->m_sinks.value(0); +} + +QStringList AudioDevNDKAudio::inputs() +{ + return this->d->m_sources; +} + +QStringList AudioDevNDKAudio::outputs() +{ + return this->d->m_sinks; +} + +QString AudioDevNDKAudio::description(const QString &device) +{ + return this->d->m_pinDescriptionMap.value(device); +} + +AkAudioCaps AudioDevNDKAudio::preferredFormat(const QString &device) +{ + return this->d->m_preferredCaps.value(device); +} + +QList AudioDevNDKAudio::supportedFormats(const QString &device) +{ + return this->d->m_supportedFormats.value(device); +} + +QList AudioDevNDKAudio::supportedChannelLayouts(const QString &device) +{ + return this->d->m_supportedLayouts.value(device); +} + +QList AudioDevNDKAudio::supportedSampleRates(const QString &device) +{ + return this->d->m_supportedSampleRates.value(device); +} + +bool AudioDevNDKAudio::init(const QString &device, const AkAudioCaps &caps) +{ + aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT; + + if (device == ":aaudioinput:") + direction = AAUDIO_DIRECTION_INPUT; + else if (device != ":aaudiooutput:") + return false; + + if (AAudio_createStreamBuilder(&this->d->m_streamBuilder) != AAUDIO_OK) + return false; + + this->d->m_stream = this->d->createStream(this->d->m_streamBuilder, + direction, + caps); + + if (!this->d->m_stream) + goto init_failed; + + if (AAudioStream_requestStart(this->d->m_stream) != AAUDIO_OK) + goto init_failed; + + return true; + +init_failed: + if (this->d->m_stream) { + AAudioStream_close(this->d->m_stream); + this->d->m_stream = nullptr; + } + + if (this->d->m_streamBuilder) { + AAudioStreamBuilder_delete(this->d->m_streamBuilder); + this->d->m_streamBuilder = nullptr; + } + + return false; +} + +QByteArray AudioDevNDKAudio::read() +{ + static const QMap fmtToSampleSize { + {AAUDIO_FORMAT_PCM_I16 , sizeof(qint16)}, + {AAUDIO_FORMAT_PCM_FLOAT, sizeof(float) }, + }; + + auto format = AAudioStream_getFormat(this->d->m_stream); + auto samples = this->latency() + * AAudioStream_getSampleRate(this->d->m_stream) + / 1000; + + if (samples < 1) + samples = 1; + + auto bufferSize = int(fmtToSampleSize.value(format)) + * AAudioStream_getChannelCount(this->d->m_stream) + * samples; + QByteArray buffer(bufferSize, Qt::Uninitialized); + samples = AAudioStream_read(this->d->m_stream, + buffer.data(), + samples, + 500e6); + + if (samples < 1) + return {}; + + bufferSize = int(fmtToSampleSize.value(format)) + * AAudioStream_getChannelCount(this->d->m_stream) + * samples; + buffer.resize(bufferSize); + + return buffer; +} + +bool AudioDevNDKAudio::write(const AkAudioPacket &packet) +{ + if (AAudioStream_write(this->d->m_stream, + packet.buffer().constData(), + packet.caps().samples(), + 500e6) != AAUDIO_OK) + return false; + + return true; +} + +bool AudioDevNDKAudio::uninit() +{ + if (this->d->m_stream) { + AAudioStream_requestStop(this->d->m_stream); + + forever { + auto state = AAudioStream_getState(this->d->m_stream); + + if (state == AAUDIO_STREAM_STATE_STOPPED) + break; + + aaudio_stream_state_t curState; + auto tiemeout = std::numeric_limits::max(); + AAudioStream_waitForStateChange(this->d->m_stream, + state, + &curState, + tiemeout); + } + + AAudioStream_close(this->d->m_stream); + this->d->m_stream = nullptr; + } + + if (this->d->m_streamBuilder) { + AAudioStreamBuilder_delete(this->d->m_streamBuilder); + this->d->m_streamBuilder = nullptr; + } + + return true; +} + +AudioDevNDKAudioPrivate::AudioDevNDKAudioPrivate(AudioDevNDKAudio *self): + self(self) +{ +} + +AAudioStream *AudioDevNDKAudioPrivate::createStream(AAudioStreamBuilder *streamBuilder, + aaudio_direction_t direction, + const AkAudioCaps &caps) +{ + static const QMap formatsMap { + {AkAudioCaps::SampleFormat_s16, AAUDIO_FORMAT_PCM_I16 }, + {AkAudioCaps::SampleFormat_flt, AAUDIO_FORMAT_PCM_FLOAT}, + }; + + auto samples = this->self->latency() * caps.rate() / 1000; + AAudioStreamBuilder_setBufferCapacityInFrames(streamBuilder, + N_BUFFERS * samples); + AAudioStreamBuilder_setChannelCount(streamBuilder, caps.channels()); + AAudioStreamBuilder_setDeviceId(streamBuilder, AAUDIO_UNSPECIFIED); + AAudioStreamBuilder_setDirection(streamBuilder, direction); + AAudioStreamBuilder_setErrorCallback(streamBuilder, + AudioDevNDKAudioPrivate::errorCallback, + this); + AAudioStreamBuilder_setFormat(streamBuilder, + formatsMap.value(caps.format(), + AAUDIO_FORMAT_INVALID)); + AAudioStreamBuilder_setFramesPerDataCallback(streamBuilder, samples); + AAudioStreamBuilder_setPerformanceMode(streamBuilder, + AAUDIO_PERFORMANCE_MODE_NONE); + AAudioStreamBuilder_setSampleRate(streamBuilder, caps.rate()); + AAudioStreamBuilder_setSamplesPerFrame(streamBuilder, caps.channels()); + AAudioStreamBuilder_setSharingMode(streamBuilder, + AAUDIO_SHARING_MODE_SHARED); + AAudioStream *stream = nullptr; + + if (AAudioStreamBuilder_openStream(streamBuilder, &stream) != AAUDIO_OK) + return nullptr; + + return stream; +} + +void AudioDevNDKAudioPrivate::errorCallback(AAudioStream *stream, + void *userData, + aaudio_result_t error) +{ + Q_UNUSED(stream) + Q_UNUSED(userData) + Q_UNUSED(error) +} + +void AudioDevNDKAudioPrivate::updateDevices() +{ + AAudioStreamBuilder *streamBuilder = nullptr; + + if (AAudio_createStreamBuilder(&streamBuilder) != AAUDIO_OK) + return; + + static const QVector sampleFormats { + AkAudioCaps::SampleFormat_s16, + AkAudioCaps::SampleFormat_flt, + }; + static const QVector layouts { + AkAudioCaps::Layout_mono, + AkAudioCaps::Layout_stereo, + }; + + // Test audio input + for (auto &format: sampleFormats) + for (auto &layout: layouts) + for (auto &rate: this->self->commonSampleRates()) { + AkAudioCaps caps(format, layout, rate); + auto stream = this->createStream(streamBuilder, + AAUDIO_DIRECTION_INPUT, + caps); + + if (stream) { + if (!this->m_supportedFormats[":aaudioinput:"].contains(format)) + this->m_supportedFormats[":aaudioinput:"] << format; + + if (!this->m_supportedLayouts[":aaudioinput:"].contains(layout)) + this->m_supportedLayouts[":aaudioinput:"] << layout; + + if (!this->m_supportedSampleRates[":aaudioinput:"].contains(rate)) + this->m_supportedSampleRates[":aaudioinput:"] << rate; + + AAudioStream_close(stream); + } + } + + if (this->m_supportedFormats.contains(":aaudioinput:") + && this->m_supportedLayouts.contains(":aaudioinput:") + && this->m_supportedSampleRates.contains(":aaudioinput:")) { + this->m_sources = QStringList {":aaudioinput:"}; + this->m_pinDescriptionMap[":aaudioinput:"] = "Android Audio Input"; + this->m_preferredCaps[":aaudioinput:"] = { + AkAudioCaps::SampleFormat_s16, + AkAudioCaps::Layout_mono, + 44100, + }; + } + + // Test audio output + for (auto &format: sampleFormats) + for (auto &layout: layouts) + for (auto &rate: this->self->commonSampleRates()) { + AkAudioCaps caps(format, layout, rate); + auto stream = this->createStream(streamBuilder, + AAUDIO_DIRECTION_OUTPUT, + caps); + + if (stream) { + if (!this->m_supportedFormats[":aaudiooutput:"].contains(format)) + this->m_supportedFormats[":aaudiooutput:"] << format; + + if (!this->m_supportedLayouts[":aaudiooutput:"].contains(layout)) + this->m_supportedLayouts[":aaudiooutput:"] << layout; + + if (!this->m_supportedSampleRates[":aaudiooutput:"].contains(rate)) + this->m_supportedSampleRates[":aaudiooutput:"] << rate; + + AAudioStream_close(stream); + } + } + + if (this->m_supportedFormats.contains(":aaudiooutput:") + && this->m_supportedLayouts.contains(":aaudiooutput:") + && this->m_supportedSampleRates.contains(":aaudiooutput:")) { + this->m_sinks = QStringList {":aaudiooutput:"}; + this->m_pinDescriptionMap[":aaudiooutput:"] = "Android Audio Output"; + this->m_preferredCaps[":aaudiooutput:"] = { + AkAudioCaps::SampleFormat_s16, + AkAudioCaps::Layout_stereo, + 44100, + }; + } + + AAudioStreamBuilder_delete(streamBuilder); +} + +#include "moc_audiodevndkaudio.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/audiodevndkaudio.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/audiodevndkaudio.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/audiodevndkaudio.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/audiodevndkaudio.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,56 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef AUDIODEVNDKAUDIO_H +#define AUDIODEVNDKAUDIO_H + +#include "audiodev.h" + +class AudioDevNDKAudioPrivate; + +class AudioDevNDKAudio: public AudioDev +{ + Q_OBJECT + + public: + AudioDevNDKAudio(QObject *parent=nullptr); + ~AudioDevNDKAudio(); + + Q_INVOKABLE QString error() const; + Q_INVOKABLE QString defaultInput(); + Q_INVOKABLE QString defaultOutput(); + Q_INVOKABLE QStringList inputs(); + Q_INVOKABLE QStringList outputs(); + Q_INVOKABLE QString description(const QString &device); + Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); + Q_INVOKABLE QList supportedFormats(const QString &device); + Q_INVOKABLE QList supportedChannelLayouts(const QString &device); + Q_INVOKABLE QList supportedSampleRates(const QString &device); + Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps); + Q_INVOKABLE QByteArray read(); + Q_INVOKABLE bool write(const AkAudioPacket &frame); + Q_INVOKABLE bool uninit(); + + private: + AudioDevNDKAudioPrivate *d; + + friend class AudioDevNDKAudioPrivate; +}; + +#endif // AUDIODEVNDKAUDIO_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "audiodevndkaudio.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new AudioDevNDKAudio(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return {}; +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/ndkaudio/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/opensl.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/opensl.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/opensl.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/opensl.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,64 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../akcommons.pri) { + include(../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +CONFIG += plugin + +HEADERS = \ + src/plugin.h \ + src/audiodevopensl.h \ + ../audiodev.h + +INCLUDEPATH += \ + ../../../../Lib/src \ + ../ + +LIBS += -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} +LIBS += -lOpenSLES + +OTHER_FILES += pspec.json + +QT += qml + +SOURCES = \ + src/plugin.cpp \ + src/audiodevopensl.cpp \ + ../audiodev.cpp + +akModule = AudioDevice +DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,3 @@ +{ + "pluginType": "Ak.SubModule" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/audiodevopensl.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/audiodevopensl.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/audiodevopensl.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/audiodevopensl.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,735 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include + +#include "audiodevopensl.h" + +#define N_BUFFERS 4 + +class AudioDevOpenSLPrivate +{ + public: + AudioDevOpenSL *self; + QString m_error; + QStringList m_sinks; + QStringList m_sources; + QMap m_pinDescriptionMap; + QMap> m_supportedFormats; + QMap> m_supportedLayouts; + QMap> m_supportedSampleRates; + QMap m_preferredCaps; + SLObjectItf m_engine {nullptr}; + SLObjectItf m_outputMix {nullptr}; + SLObjectItf m_audioPlayer {nullptr}; + SLObjectItf m_audioRecorder {nullptr}; + QVector m_audioBuffers; + QMutex m_mutex; + QWaitCondition m_bufferReady; + QByteArray m_tmpBuffer; + AkAudioCaps m_curCaps; + int m_samples {0}; + + explicit AudioDevOpenSLPrivate(AudioDevOpenSL *self); + static SLObjectItf createEngine(); + static SLObjectItf createOutputMix(SLObjectItf engine); + static SLObjectItf createAudioPlayer(SLObjectItf engine, + SLObjectItf outputMix, + const AkAudioCaps &caps); + static SLObjectItf createAudioRecorder(SLObjectItf engine, + const AkAudioCaps &caps); + static SLAndroidDataFormat_PCM_EX dataFormatFromCaps(const AkAudioCaps &caps); + static SLuint32 channelMaskFromLayout(AkAudioCaps::ChannelLayout layout); + static void sampleProcess(SLAndroidSimpleBufferQueueItf bufferQueue, + void *context); + void updateDevices(); +}; + +AudioDevOpenSL::AudioDevOpenSL(QObject *parent): + AudioDev(parent) +{ + this->d = new AudioDevOpenSLPrivate(this); + this->d->updateDevices(); +} + +AudioDevOpenSL::~AudioDevOpenSL() +{ + this->uninit(); + delete this->d; +} + +QString AudioDevOpenSL::error() const +{ + return this->d->m_error; +} + +QString AudioDevOpenSL::defaultInput() +{ + return this->d->m_sources.value(0); +} + +QString AudioDevOpenSL::defaultOutput() +{ + return this->d->m_sinks.value(0); +} + +QStringList AudioDevOpenSL::inputs() +{ + return this->d->m_sources; +} + +QStringList AudioDevOpenSL::outputs() +{ + return this->d->m_sinks; +} + +QString AudioDevOpenSL::description(const QString &device) +{ + return this->d->m_pinDescriptionMap.value(device); +} + +AkAudioCaps AudioDevOpenSL::preferredFormat(const QString &device) +{ + return this->d->m_preferredCaps.value(device); +} + +QList AudioDevOpenSL::supportedFormats(const QString &device) +{ + return this->d->m_supportedFormats.value(device); +} + +QList AudioDevOpenSL::supportedChannelLayouts(const QString &device) +{ + return this->d->m_supportedLayouts.value(device); +} + +QList AudioDevOpenSL::supportedSampleRates(const QString &device) +{ + return this->d->m_supportedSampleRates.value(device); +} + +bool AudioDevOpenSL::init(const QString &device, const AkAudioCaps &caps) +{ + this->d->m_engine = AudioDevOpenSLPrivate::createEngine(); + + if (!this->d->m_engine) + return false; + + this->d->m_samples = qMax(this->latency() * caps.rate() / 1000, 1); + this->d->m_curCaps = caps; + this->d->m_curCaps.setSamples(this->latency() * caps.rate() / 1000); + + if (device == ":openslinput:") { + this->d->m_audioRecorder = + AudioDevOpenSLPrivate::createAudioRecorder(this->d->m_engine, + caps); + + if (!this->d->m_audioRecorder) + goto init_failed; + + SLPlayItf audioRecorder = nullptr; + + if ((*this->d->m_audioRecorder)->GetInterface(this->d->m_audioRecorder, + SL_IID_RECORD, + &audioRecorder) != SL_RESULT_SUCCESS) + goto init_failed; + + SLAndroidSimpleBufferQueueItf bufferQueue = nullptr; + + if ((*this->d->m_audioRecorder)->GetInterface(this->d->m_audioRecorder, + SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue) != SL_RESULT_SUCCESS) + goto init_failed; + + if ((*bufferQueue)->RegisterCallback(bufferQueue, + AudioDevOpenSLPrivate::sampleProcess, + this->d) != SL_RESULT_SUCCESS) + goto init_failed; + + auto bufferSize = this->d->self->latency() + * this->d->m_curCaps.bps() + * this->d->m_curCaps.channels() + * this->d->m_curCaps.rate() + / 1000; + this->d->m_tmpBuffer = {bufferSize, 0}; + AudioDevOpenSLPrivate::sampleProcess(bufferQueue, this->d); + + if ((*audioRecorder)->SetPlayState(audioRecorder, + SL_RECORDSTATE_RECORDING) != SL_RESULT_SUCCESS) + goto init_failed; + } else { + this->d->m_outputMix = + AudioDevOpenSLPrivate::createOutputMix(this->d->m_engine); + + if (!this->d->m_outputMix) + goto init_failed; + + this->d->m_audioPlayer = + AudioDevOpenSLPrivate::createAudioPlayer(this->d->m_engine, + this->d->m_outputMix, + caps); + + if (!this->d->m_audioPlayer) + goto init_failed; + + SLPlayItf audioPlayer = nullptr; + + if ((*this->d->m_audioPlayer)->GetInterface(this->d->m_audioPlayer, + SL_IID_PLAY, + &audioPlayer) != SL_RESULT_SUCCESS) + goto init_failed; + + SLAndroidSimpleBufferQueueItf bufferQueue = nullptr; + + if ((*this->d->m_audioPlayer)->GetInterface(this->d->m_audioPlayer, + SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue) != SL_RESULT_SUCCESS) + goto init_failed; + + if ((*bufferQueue)->RegisterCallback(bufferQueue, + AudioDevOpenSLPrivate::sampleProcess, + this->d) != SL_RESULT_SUCCESS) + goto init_failed; + + if ((*audioPlayer)->SetPlayState(audioPlayer, + SL_PLAYSTATE_PLAYING) != SL_RESULT_SUCCESS) + goto init_failed; + + AudioDevOpenSLPrivate::sampleProcess(bufferQueue, this->d); + } + + return true; + +init_failed: + if (this->d->m_audioRecorder) { + (*this->d->m_audioRecorder)->Destroy(this->d->m_audioRecorder); + this->d->m_audioRecorder = nullptr; + } + + if (this->d->m_audioPlayer) { + (*this->d->m_audioPlayer)->Destroy(this->d->m_audioPlayer); + this->d->m_audioPlayer = nullptr; + } + + if (this->d->m_outputMix) { + (*this->d->m_outputMix)->Destroy(this->d->m_outputMix); + this->d->m_outputMix = nullptr; + } + + (*this->d->m_engine)->Destroy(this->d->m_engine); + this->d->m_engine = nullptr; + this->d->m_audioBuffers.clear(); + + return false; +} + +QByteArray AudioDevOpenSL::read() +{ + this->d->m_mutex.lock(); + + if (this->d->m_audioBuffers.size() < 1) + this->d->m_bufferReady.wait(&this->d->m_mutex); + + auto buffer = this->d->m_audioBuffers.takeFirst(); + this->d->m_mutex.unlock(); + + return buffer; +} + +bool AudioDevOpenSL::write(const AkAudioPacket &packet) +{ + this->d->m_mutex.lock(); + + if (this->d->m_audioBuffers.size() >= N_BUFFERS) + this->d->m_bufferReady.wait(&this->d->m_mutex); + + this->d->m_audioBuffers << packet.buffer(); + this->d->m_mutex.unlock(); + + return true; +} + +bool AudioDevOpenSL::uninit() +{ + if (this->d->m_audioRecorder) { + SLRecordItf audioRecorder = nullptr; + + if ((*this->d->m_audioRecorder)->GetInterface(this->d->m_audioRecorder, + SL_IID_RECORD, + &audioRecorder) == SL_RESULT_SUCCESS) { + (*audioRecorder)->SetRecordState(audioRecorder, SL_RECORDSTATE_STOPPED); + } + + (*this->d->m_audioRecorder)->Destroy(this->d->m_audioRecorder); + this->d->m_audioRecorder = nullptr; + } + + if (this->d->m_audioPlayer) { + SLPlayItf audioPlayer = nullptr; + + if ((*this->d->m_audioPlayer)->GetInterface(this->d->m_audioPlayer, + SL_IID_PLAY, + &audioPlayer) == SL_RESULT_SUCCESS) { + (*audioPlayer)->SetPlayState(audioPlayer, SL_PLAYSTATE_STOPPED); + } + + (*this->d->m_audioPlayer)->Destroy(this->d->m_audioPlayer); + this->d->m_audioPlayer = nullptr; + } + + if (this->d->m_outputMix) { + (*this->d->m_outputMix)->Destroy(this->d->m_outputMix); + this->d->m_outputMix = nullptr; + } + + if (this->d->m_engine) { + (*this->d->m_engine)->Destroy(this->d->m_engine); + this->d->m_engine = nullptr; + } + + this->d->m_audioBuffers.clear(); + + return true; +} + +AudioDevOpenSLPrivate::AudioDevOpenSLPrivate(AudioDevOpenSL *self): + self(self) +{ +} + +SLObjectItf AudioDevOpenSLPrivate::createEngine() +{ + SLObjectItf engineObject = nullptr; + + if (slCreateEngine(&engineObject, + 0, + nullptr, + 0, + nullptr, + nullptr) != SL_RESULT_SUCCESS) + return nullptr; + + if ((*engineObject)->Realize(engineObject, + SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { + (*engineObject)->Destroy(engineObject); + + return nullptr; + } + + return engineObject; +} + +SLObjectItf AudioDevOpenSLPrivate::createOutputMix(SLObjectItf engine) +{ + SLEngineItf engineInterface = nullptr; + + if ((*engine)->GetInterface(engine, + SL_IID_ENGINE, + &engineInterface) != SL_RESULT_SUCCESS) + return nullptr; + + SLObjectItf outputMixObject = nullptr; + + if ((*engineInterface)->CreateOutputMix(engineInterface, + &outputMixObject, + 0, + nullptr, + nullptr) != SL_RESULT_SUCCESS) + return nullptr; + + if ((*outputMixObject)->Realize(outputMixObject, + SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { + (*outputMixObject)->Destroy(outputMixObject); + + return nullptr; + } + + return outputMixObject; +} + +SLObjectItf AudioDevOpenSLPrivate::createAudioPlayer(SLObjectItf engine, + SLObjectItf outputMix, + const AkAudioCaps &caps) +{ + if (!outputMix) + return nullptr; + + SLEngineItf engineInterface = nullptr; + + if ((*engine)->GetInterface(engine, + SL_IID_ENGINE, + &engineInterface) != SL_RESULT_SUCCESS) + return nullptr; + + SLObjectItf audioPlayerObject = nullptr; + + SLDataLocator_AndroidSimpleBufferQueue bufferQueueLocator { + SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, + N_BUFFERS + }; + auto format = AudioDevOpenSLPrivate::dataFormatFromCaps(caps); + SLDataSource dataSource { + &bufferQueueLocator, + &format + }; + SLDataLocator_OutputMix outputMixLocator { + SL_DATALOCATOR_OUTPUTMIX, + outputMix + }; + SLDataSink dataSink { + &outputMixLocator, + nullptr + }; + + QMap interfaces { + {SL_IID_BUFFERQUEUE, SL_BOOLEAN_TRUE}, + }; + auto requiredKeys = interfaces.keys().toVector(); + auto requiredValues = interfaces.values().toVector(); + + if ((*engineInterface)->CreateAudioPlayer(engineInterface, + &audioPlayerObject, + &dataSource, + &dataSink, + SLuint32(interfaces.size()), + requiredKeys.data(), + requiredValues.data()) != SL_RESULT_SUCCESS) + return nullptr; + + if ((*audioPlayerObject)->Realize(audioPlayerObject, + SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { + (*audioPlayerObject)->Destroy(audioPlayerObject); + + return nullptr; + } + + return audioPlayerObject; +} + +SLObjectItf AudioDevOpenSLPrivate::createAudioRecorder(SLObjectItf engine, + const AkAudioCaps &caps) +{ + SLEngineItf engineInterface = nullptr; + + if ((*engine)->GetInterface(engine, + SL_IID_ENGINE, + &engineInterface) != SL_RESULT_SUCCESS) + return nullptr; + + SLObjectItf audioRecorderObject = nullptr; + SLDataLocator_IODevice ioDeviceLocator { + SL_DATALOCATOR_IODEVICE, + SL_IODEVICE_AUDIOINPUT, + SL_DEFAULTDEVICEID_AUDIOINPUT, + nullptr + }; + SLDataLocator_AndroidSimpleBufferQueue bufferQueueLocator { + SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, + N_BUFFERS + }; + auto format = AudioDevOpenSLPrivate::dataFormatFromCaps(caps); + SLDataSource dataSource { + &ioDeviceLocator, + nullptr + }; + SLDataSink dataSink { + &bufferQueueLocator, + &format + }; + QMap interfaces { + {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_BOOLEAN_TRUE}, + {SL_IID_ANDROIDCONFIGURATION , SL_BOOLEAN_TRUE}, + }; + auto requiredKeys = interfaces.keys().toVector(); + auto requiredValues = interfaces.values().toVector(); + + if ((*engineInterface)->CreateAudioRecorder(engineInterface, + &audioRecorderObject, + &dataSource, + &dataSink, + SLuint32(interfaces.size()), + requiredKeys.data(), + requiredValues.data()) != SL_RESULT_SUCCESS) + return nullptr; + + if ((*audioRecorderObject)->Realize(audioRecorderObject, + SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { + (*audioRecorderObject)->Destroy(audioRecorderObject); + + return nullptr; + } + + return audioRecorderObject; +} + +SLAndroidDataFormat_PCM_EX AudioDevOpenSLPrivate::dataFormatFromCaps(const AkAudioCaps &caps) +{ + SLuint32 bitsPerSample = 0; + + switch (AkAudioCaps::bitsPerSample(caps.format())) { + case 8: + bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_8; + + break; + + case 16: + bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; + + break; + + case 32: + bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32; + + break; + + default: + break; + } + + SLuint32 representation = 0; + + switch (AkAudioCaps::sampleType(caps.format())) { + case AkAudioCaps::SampleType_int: + representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; + + break; + + case AkAudioCaps::SampleType_uint: + representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT; + + break; + + case AkAudioCaps::SampleType_float: + representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; + + break; + + default: + break; + } + + return { + SL_ANDROID_DATAFORMAT_PCM_EX, + SLuint32(caps.channels()), + 1000 * SLuint32(caps.rate()), + bitsPerSample, + bitsPerSample, + AudioDevOpenSLPrivate::channelMaskFromLayout(caps.layout()), + AkAudioCaps::endianness(caps.format()) == Q_LITTLE_ENDIAN? + SL_BYTEORDER_LITTLEENDIAN: SL_BYTEORDER_BIGENDIAN, + representation + }; +} + +SLuint32 AudioDevOpenSLPrivate::channelMaskFromLayout(AkAudioCaps::ChannelLayout layout) +{ + static const QMap positiosMap { + {AkAudioCaps::Position_FrontLeft , SL_SPEAKER_FRONT_LEFT }, + {AkAudioCaps::Position_FrontRight , SL_SPEAKER_FRONT_RIGHT }, + {AkAudioCaps::Position_FrontCenter , SL_SPEAKER_FRONT_CENTER }, + {AkAudioCaps::Position_LowFrequency1 , SL_SPEAKER_LOW_FREQUENCY }, + {AkAudioCaps::Position_BackLeft , SL_SPEAKER_BACK_LEFT }, + {AkAudioCaps::Position_BackRight , SL_SPEAKER_BACK_RIGHT }, + {AkAudioCaps::Position_FrontLeftOfCenter , SL_SPEAKER_FRONT_LEFT_OF_CENTER }, + {AkAudioCaps::Position_FrontRightOfCenter, SL_SPEAKER_FRONT_RIGHT_OF_CENTER}, + {AkAudioCaps::Position_BackCenter , SL_SPEAKER_BACK_CENTER }, + {AkAudioCaps::Position_SideLeft , SL_SPEAKER_SIDE_LEFT }, + {AkAudioCaps::Position_SideRight , SL_SPEAKER_SIDE_RIGHT }, + {AkAudioCaps::Position_TopCenter , SL_SPEAKER_TOP_CENTER }, + {AkAudioCaps::Position_TopFrontLeft , SL_SPEAKER_TOP_FRONT_LEFT }, + {AkAudioCaps::Position_TopFrontCenter , SL_SPEAKER_TOP_FRONT_CENTER }, + {AkAudioCaps::Position_TopFrontRight , SL_SPEAKER_TOP_FRONT_RIGHT }, + {AkAudioCaps::Position_TopBackLeft , SL_SPEAKER_TOP_BACK_LEFT }, + {AkAudioCaps::Position_TopBackCenter , SL_SPEAKER_TOP_BACK_CENTER }, + {AkAudioCaps::Position_TopBackRight , SL_SPEAKER_TOP_BACK_RIGHT }, + }; + SLuint32 channelMask = 0; + + for (auto &position: AkAudioCaps::positions(layout)) + channelMask |= positiosMap.value(position, 0); + + return channelMask; +} + +void AudioDevOpenSLPrivate::sampleProcess(SLAndroidSimpleBufferQueueItf bufferQueue, + void *context) +{ + auto self = reinterpret_cast(context); + QByteArray buffer; + + if (self->m_audioPlayer) { + self->m_mutex.lock(); + + if (self->m_audioBuffers.isEmpty()) { + auto bufferSize = self->self->latency() + * self->m_curCaps.bps() + * self->m_curCaps.channels() + * self->m_curCaps.rate() + / 8000; + buffer = {bufferSize, 0}; + } else { + buffer = self->m_audioBuffers.takeFirst(); + } + + self->m_bufferReady.wakeAll(); + self->m_mutex.unlock(); + + (*bufferQueue)->Enqueue(bufferQueue, + buffer.data(), + SLuint32(buffer.size())); + } else { + self->m_mutex.lock(); + self->m_audioBuffers << self->m_tmpBuffer; + + if (self->m_audioBuffers.size() > N_BUFFERS) + self->m_audioBuffers.takeFirst(); + + self->m_bufferReady.wakeAll(); + self->m_mutex.unlock(); + + (*bufferQueue)->Enqueue(bufferQueue, + self->m_tmpBuffer.data(), + SLuint32(self->m_tmpBuffer.size())); + } +} + +void AudioDevOpenSLPrivate::updateDevices() +{ + auto engine = AudioDevOpenSLPrivate::createEngine(); + + if (!engine) + return; + + static const QVector sampleFormats { + AkAudioCaps::SampleFormat_s8, + AkAudioCaps::SampleFormat_u8, + AkAudioCaps::SampleFormat_s16, + AkAudioCaps::SampleFormat_u16, + AkAudioCaps::SampleFormat_s32, + AkAudioCaps::SampleFormat_u32, + AkAudioCaps::SampleFormat_s64, + AkAudioCaps::SampleFormat_u64, + AkAudioCaps::SampleFormat_flt, + AkAudioCaps::SampleFormat_dbl, + }; + static const QVector layouts { + AkAudioCaps::Layout_mono, + AkAudioCaps::Layout_stereo, + }; + static const QVector sampleRates { + SL_SAMPLINGRATE_8 / 1000, + SL_SAMPLINGRATE_11_025 / 1000, + SL_SAMPLINGRATE_12 / 1000, + SL_SAMPLINGRATE_16 / 1000, + SL_SAMPLINGRATE_22_05 / 1000, + SL_SAMPLINGRATE_24 / 1000, + SL_SAMPLINGRATE_32 / 1000, + SL_SAMPLINGRATE_44_1 / 1000, + SL_SAMPLINGRATE_48 / 1000, + SL_SAMPLINGRATE_64 / 1000, + SL_SAMPLINGRATE_88_2 / 1000, + SL_SAMPLINGRATE_96 / 1000, + SL_SAMPLINGRATE_192 / 1000, + }; + + // Test audio input + for (auto &format: sampleFormats) + for (auto &layout: layouts) + for (auto &rate: sampleRates) { + AkAudioCaps caps(format, layout, rate); + auto audioRecorder = + AudioDevOpenSLPrivate::createAudioRecorder(engine, caps); + + if (audioRecorder) { + if (!this->m_supportedFormats[":openslinput:"].contains(format)) + this->m_supportedFormats[":openslinput:"] << format; + + if (!this->m_supportedLayouts[":openslinput:"].contains(layout)) + this->m_supportedLayouts[":openslinput:"] << layout; + + if (!this->m_supportedSampleRates[":openslinput:"].contains(rate)) + this->m_supportedSampleRates[":openslinput:"] << rate; + + (*audioRecorder)->Destroy(audioRecorder); + } + } + + if (this->m_supportedFormats.contains(":openslinput:") + && this->m_supportedLayouts.contains(":openslinput:") + && this->m_supportedSampleRates.contains(":openslinput:")) { + this->m_sources = QStringList {":openslinput:"}; + this->m_pinDescriptionMap[":openslinput:"] = "OpenSL ES Input"; + this->m_preferredCaps[":openslinput:"] = { + AkAudioCaps::SampleFormat_s16, + AkAudioCaps::Layout_mono, + 44100, + }; + } + + // Test audio output + auto outputMix = AudioDevOpenSLPrivate::createOutputMix(engine); + + if (outputMix) { + for (auto &format: sampleFormats) + for (auto &layout: layouts) + for (auto &rate: sampleRates) { + AkAudioCaps caps(format, layout, rate); + auto audioPlayer = + AudioDevOpenSLPrivate::createAudioPlayer(engine, + outputMix, + caps); + + if (audioPlayer) { + if (!this->m_supportedFormats[":opensloutput:"].contains(format)) + this->m_supportedFormats[":opensloutput:"] << format; + + if (!this->m_supportedLayouts[":opensloutput:"].contains(layout)) + this->m_supportedLayouts[":opensloutput:"] << layout; + + if (!this->m_supportedSampleRates[":opensloutput:"].contains(rate)) + this->m_supportedSampleRates[":opensloutput:"] << rate; + + (*audioPlayer)->Destroy(audioPlayer); + } + } + + if (this->m_supportedFormats.contains(":opensloutput:") + && this->m_supportedLayouts.contains(":opensloutput:") + && this->m_supportedSampleRates.contains(":opensloutput:")) { + this->m_sinks = QStringList {":opensloutput:"}; + this->m_pinDescriptionMap[":opensloutput:"] = "OpenSL ES Output"; + this->m_preferredCaps[":opensloutput:"] = { + AkAudioCaps::SampleFormat_s16, + AkAudioCaps::Layout_stereo, + 44100, + }; + } + + (*outputMix)->Destroy(outputMix); + } + + (*engine)->Destroy(engine); +} + +#include "moc_audiodevopensl.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/audiodevopensl.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/audiodevopensl.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/audiodevopensl.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/audiodevopensl.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,56 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef AUDIODEVOPENSL_H +#define AUDIODEVOPENSL_H + +#include "audiodev.h" + +class AudioDevOpenSLPrivate; + +class AudioDevOpenSL: public AudioDev +{ + Q_OBJECT + + public: + AudioDevOpenSL(QObject *parent=nullptr); + ~AudioDevOpenSL(); + + Q_INVOKABLE QString error() const; + Q_INVOKABLE QString defaultInput(); + Q_INVOKABLE QString defaultOutput(); + Q_INVOKABLE QStringList inputs(); + Q_INVOKABLE QStringList outputs(); + Q_INVOKABLE QString description(const QString &device); + Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); + Q_INVOKABLE QList supportedFormats(const QString &device); + Q_INVOKABLE QList supportedChannelLayouts(const QString &device); + Q_INVOKABLE QList supportedSampleRates(const QString &device); + Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps); + Q_INVOKABLE QByteArray read(); + Q_INVOKABLE bool write(const AkAudioPacket &frame); + Q_INVOKABLE bool uninit(); + + private: + AudioDevOpenSLPrivate *d; + + friend class AudioDevOpenSLPrivate; +}; + +#endif // AUDIODEVOPENSL_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "audiodevopensl.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new AudioDevOpenSL(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return {}; +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/opensl/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/oss.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/oss.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/oss.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/oss.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -# Webcamoid, webcam capture application. -# Copyright (C) 2016 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -exists(akcommons.pri) { - include(akcommons.pri) -} else { - exists(../../../../akcommons.pri) { - include(../../../../akcommons.pri) - } else { - error("akcommons.pri file not found.") - } -} - -CONFIG += plugin - -HEADERS = \ - src/plugin.h \ - src/audiodevoss.h \ - ../audiodev.h - -INCLUDEPATH += \ - ../../../../Lib/src \ - ../ - -LIBS += -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} - -OTHER_FILES += pspec.json - -exists($${INCLUDEDIR}/linux/soundcard.h): DEFINES += HAVE_OSS_LINUX - -QT += qml - -SOURCES = \ - src/plugin.cpp \ - src/audiodevoss.cpp \ - ../audiodev.cpp - -akModule = AudioDevice -DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} - -TEMPLATE = lib - -INSTALLS += target - -android { - TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} - target.path = $${LIBDIR} -} else { - target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/pspec.json 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/pspec.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -{ - "pluginType": "Ak.SubModule" -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/audiodevoss.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/audiodevoss.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/audiodevoss.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/audiodevoss.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,522 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_OSS_LINUX -#include -#else -#include -#endif - -#include "audiodevoss.h" - -#define BUFFER_SIZE 1024 // In samples - -using SampleFormatMap = QMap; - -inline SampleFormatMap initSampleFormatMap() -{ - SampleFormatMap sampleFormat = { - {AkAudioCaps::SampleFormat_s8 , AFMT_S8}, - {AkAudioCaps::SampleFormat_u8 , AFMT_U8}, - {AkAudioCaps::SampleFormat_s16 , AFMT_S16_NE}, - {AkAudioCaps::SampleFormat_s16le, AFMT_S16_LE}, - {AkAudioCaps::SampleFormat_s16be, AFMT_S16_BE}, - {AkAudioCaps::SampleFormat_u16le, AFMT_U16_LE}, - {AkAudioCaps::SampleFormat_u16be, AFMT_U16_BE}, - }; - - return sampleFormat; -} - -Q_GLOBAL_STATIC_WITH_ARGS(SampleFormatMap, sampleFormats, (initSampleFormatMap())) - -class AudioDevOSSPrivate -{ - public: - AudioDevOSS *self; - QString m_error; - QString m_defaultSink; - QString m_defaultSource; - QStringList m_sinks; - QStringList m_sources; - QMap m_pinDescriptionMap; - QMap> m_supportedFormats; - QMap> m_supportedChannels; - QMap> m_supportedSampleRates; - AkAudioCaps m_curCaps; - QFile m_deviceFile; - QFileSystemWatcher *m_fsWatcher {nullptr}; - QMutex m_mutex; - - explicit AudioDevOSSPrivate(AudioDevOSS *self); - int fragmentSize(const QString &device, const AkAudioCaps &caps); - void fillDeviceInfo(const QString &device, - QList *supportedFormats, - QList *supportedChannels, - QList *supportedSampleRates) const; -}; - -AudioDevOSS::AudioDevOSS(QObject *parent): - AudioDev(parent) -{ - this->d = new AudioDevOSSPrivate(this); - this->d->m_fsWatcher = new QFileSystemWatcher({"/dev"}, this); - - QObject::connect(this->d->m_fsWatcher, - &QFileSystemWatcher::directoryChanged, - this, - &AudioDevOSS::updateDevices); - - this->updateDevices(); -} - -AudioDevOSS::~AudioDevOSS() -{ - this->uninit(); - - if (this->d->m_fsWatcher) - delete this->d->m_fsWatcher; - - delete this->d; -} - -QString AudioDevOSS::error() const -{ - return this->d->m_error; -} - -QString AudioDevOSS::defaultInput() -{ - return this->d->m_defaultSource; -} - -QString AudioDevOSS::defaultOutput() -{ - return this->d->m_defaultSink; -} - -QStringList AudioDevOSS::inputs() -{ - return this->d->m_sources; -} - -QStringList AudioDevOSS::outputs() -{ - return this->d->m_sinks; -} - -QString AudioDevOSS::description(const QString &device) -{ - return this->d->m_pinDescriptionMap.value(device); -} - -AkAudioCaps AudioDevOSS::preferredFormat(const QString &device) -{ - return this->d->m_sinks.contains(device)? - AkAudioCaps(AkAudioCaps::SampleFormat_s16, - 2, - 44100): - AkAudioCaps(AkAudioCaps::SampleFormat_u8, - 1, - 8000); -} - -QList AudioDevOSS::supportedFormats(const QString &device) -{ - return this->d->m_supportedFormats.value(device); -} - -QList AudioDevOSS::supportedChannels(const QString &device) -{ - return this->d->m_supportedChannels.value(device); -} - -QList AudioDevOSS::supportedSampleRates(const QString &device) -{ - return this->d->m_supportedSampleRates.value(device); -} - -bool AudioDevOSS::init(const QString &device, const AkAudioCaps &caps) -{ - QMutexLocker mutexLockeer(&this->d->m_mutex); - - int fragmentSize = this->d->fragmentSize(device, caps); - - if (fragmentSize < 1) - return false; - - this->d->m_deviceFile.setFileName(QString(device) - .remove(QRegExp(":Input$|:Output$"))); - - if (!this->d->m_deviceFile.open(device.endsWith(":Input")? - QIODevice::ReadOnly: QIODevice::WriteOnly)) - return false; - - int format; - format = sampleFormats->value(caps.format(), AFMT_QUERY); - - if (ioctl(this->d->m_deviceFile.handle(), SNDCTL_DSP_SETFMT, &format) < 0) - goto init_fail; - - int stereo; - stereo = caps.channels() > 1? 1: 0; - - if (ioctl(this->d->m_deviceFile.handle(), SNDCTL_DSP_STEREO, &stereo) < 0) - goto init_fail; - - int sampleRate; - sampleRate = caps.rate(); - - if (ioctl(this->d->m_deviceFile.handle(), SNDCTL_DSP_SPEED, &sampleRate) < 0) - goto init_fail; - - if (device.endsWith(":Output")) - ioctl(this->d->m_deviceFile.handle(), SNDCTL_DSP_SETFRAGMENT, &fragmentSize); - - this->d->m_curCaps = caps; - - return true; - -init_fail: - this->d->m_deviceFile.close(); - - return false; -} - -QByteArray AudioDevOSS::read(int samples) -{ - if (samples < 1) - return {}; - - QMutexLocker mutexLockeer(&this->d->m_mutex); - - if (!this->d->m_deviceFile.isOpen()) - return QByteArray(); - - QByteArray buffer; - int bufferSize = samples - * this->d->m_curCaps.channels() - * AkAudioCaps::bitsPerSample(this->d->m_curCaps.format()) - / 8; - - while (bufferSize > 0) { - auto data = this->d->m_deviceFile.read(bufferSize); - - if (data.size() > 0) { - buffer += data; - bufferSize -= data.size(); - } - } - - return buffer; -} - -bool AudioDevOSS::write(const AkAudioPacket &packet) -{ - QMutexLocker mutexLockeer(&this->d->m_mutex); - - if (!this->d->m_deviceFile.isOpen()) - return false; - - return this->d->m_deviceFile.write(packet.buffer()) > 0; -} - -bool AudioDevOSS::uninit() -{ - QMutexLocker mutexLockeer(&this->d->m_mutex); - - this->d->m_deviceFile.close(); - this->d->m_curCaps = AkAudioCaps(); - - return true; -} - -AudioDevOSSPrivate::AudioDevOSSPrivate(AudioDevOSS *self): - self(self) -{ -} - -int AudioDevOSSPrivate::fragmentSize(const QString &device, - const AkAudioCaps &caps) -{ - if (!device.endsWith(":Output")) - return 0; - - QFile deviceFile; - - deviceFile.setFileName(QString(device).remove(":Output")); - - if (!deviceFile.open(QIODevice::WriteOnly)) - return 0; - - int format = sampleFormats->value(caps.format(), AFMT_QUERY); - - if (ioctl(deviceFile.handle(), SNDCTL_DSP_SETFMT, &format) < 0) { - deviceFile.close(); - - return 0; - } - - int stereo; - stereo = caps.channels() > 1? 1: 0; - - if (ioctl(deviceFile.handle(), SNDCTL_DSP_STEREO, &stereo) < 0) { - deviceFile.close(); - - return 0; - } - - int sampleRate; - sampleRate = caps.rate(); - - if (ioctl(deviceFile.handle(), SNDCTL_DSP_SPEED, &sampleRate) < 0) { - deviceFile.close(); - - return 0; - } - - // Set the buffer to a maximum of 1024 samples. - int bufferSize = - BUFFER_SIZE - * caps.channels() - * AkAudioCaps::bitsPerSample(caps.format()) - / 8; - - // Let's try setting the fragmet to just 2 pieces, and the half of the - // buffer size, for low latency. - int fragmentSize = (2 << 16) | (bufferSize / 2); - ioctl(deviceFile.handle(), SNDCTL_DSP_SETFRAGMENT, &fragmentSize); - - // Let's see what OSS did actually set, - audio_buf_info info; - ioctl(deviceFile.handle(), SNDCTL_DSP_GETOSPACE, &info); - - fragmentSize = info.fragsize > 0? - ((bufferSize / info.fragsize) << 16) | info.fragsize: - 0; - deviceFile.close(); - - return fragmentSize; -} - -void AudioDevOSSPrivate::fillDeviceInfo(const QString &device, - QList *supportedFormats, - QList *supportedChannels, - QList *supportedSampleRates) const -{ - QFile pcmFile(QString(device) - .remove(QRegExp(":Input$|:Output$"))); - - if (!pcmFile.open(device.endsWith(":Input")? - QIODevice::ReadOnly: QIODevice::WriteOnly)) - return; - - int formats = AFMT_QUERY; - - if (ioctl(pcmFile.handle(), SNDCTL_DSP_GETFMTS, &formats) < 0) - goto deviceCaps_fail; - - static const QVector preferredFormats = { - AFMT_S16_LE, - AFMT_S16_BE, - AFMT_U16_LE, - AFMT_U16_BE, - AFMT_S8, - AFMT_U8 - }; - - int format; - format = AFMT_QUERY; - - for (const auto &fmt: preferredFormats) - if (formats & fmt) { - if (format == AFMT_QUERY) - format = fmt; - - supportedFormats->append(sampleFormats->key(fmt)); - } - - if (format == AFMT_QUERY) - goto deviceCaps_fail; - - if (ioctl(pcmFile.handle(), SNDCTL_DSP_SETFMT, &format) < 0) - goto deviceCaps_fail; - - for (int channels = 0; channels < 2; channels++) - if (ioctl(pcmFile.handle(), SNDCTL_DSP_STEREO, &channels) >= 0) - supportedChannels->append(channels + 1); - - for (auto &rate: self->commonSampleRates()) - if (ioctl(pcmFile.handle(), SNDCTL_DSP_SPEED, &rate) >= 0) - supportedSampleRates->append(rate); - -deviceCaps_fail: - pcmFile.close(); -} - -void AudioDevOSS::updateDevices() -{ - decltype(this->d->m_sources) inputs; - decltype(this->d->m_sinks) outputs; - decltype(this->d->m_pinDescriptionMap) pinDescriptionMap; - decltype(this->d->m_supportedFormats) supportedFormats; - decltype(this->d->m_supportedChannels) supportedChannels; - decltype(this->d->m_supportedSampleRates) supportedSampleRates; - - QDir devicesDir("/dev"); - - QStringList devices = devicesDir.entryList(QStringList() << "mixer*", - QDir::System - | QDir::Readable - | QDir::Writable - | QDir::NoSymLinks - | QDir::NoDotAndDotDot - | QDir::CaseSensitive, - QDir::Name); - - for (const auto &devicePath: devices) { - auto mixerDevice = devicesDir.absoluteFilePath(devicePath); - auto dspDevice = QString(mixerDevice).replace("mixer", "dsp"); - - if (!QFile::exists(mixerDevice) - || !QFile::exists(dspDevice)) - continue; - - QString description; - QFile mixerFile(mixerDevice); - - if (!mixerFile.open(QIODevice::ReadWrite)) - continue; - - mixer_info mixerInfo; - - if (ioctl(mixerFile.handle(), SOUND_MIXER_INFO, &mixerInfo) < 0) { - mixerFile.close(); - - continue; - } - - mixerFile.close(); - description = QString("%1, %2").arg(mixerInfo.id, mixerInfo.name); - - QList _supportedFormats; - QList _supportedChannels; - QList _supportedSampleRates; - - auto input = dspDevice + ":Input"; - this->d->fillDeviceInfo(input, - &_supportedFormats, - &_supportedChannels, - &_supportedSampleRates); - - if (_supportedFormats.isEmpty()) - _supportedFormats = this->d->m_supportedFormats.value(input); - - if (_supportedChannels.isEmpty()) - _supportedChannels = this->d->m_supportedChannels.value(input); - - if (_supportedSampleRates.isEmpty()) - _supportedSampleRates = this->d->m_supportedSampleRates.value(input); - - if (!_supportedFormats.isEmpty() - && !_supportedChannels.isEmpty() - && !_supportedSampleRates.isEmpty()) { - inputs << input; - pinDescriptionMap[input] = description; - supportedFormats[input] = _supportedFormats; - supportedChannels[input] = _supportedChannels; - supportedSampleRates[input] = _supportedSampleRates; - } - - _supportedFormats.clear(); - _supportedChannels.clear(); - _supportedSampleRates.clear(); - - auto output = dspDevice + ":Output"; - this->d->fillDeviceInfo(output, - &_supportedFormats, - &_supportedChannels, - &_supportedSampleRates); - - if (_supportedFormats.isEmpty()) - _supportedFormats = this->d->m_supportedFormats.value(output); - - if (_supportedChannels.isEmpty()) - _supportedChannels = this->d->m_supportedChannels.value(output); - - if (_supportedSampleRates.isEmpty()) - _supportedSampleRates = this->d->m_supportedSampleRates.value(output); - - if (!_supportedFormats.isEmpty() - && !_supportedChannels.isEmpty() - && !_supportedSampleRates.isEmpty()) { - outputs << output; - pinDescriptionMap[output] = description; - supportedFormats[output] = _supportedFormats; - supportedChannels[output] = _supportedChannels; - supportedSampleRates[output] = _supportedSampleRates; - } - } - - if (this->d->m_supportedFormats != supportedFormats) - this->d->m_supportedFormats = supportedFormats; - - if (this->d->m_supportedChannels != supportedChannels) - this->d->m_supportedChannels = supportedChannels; - - if (this->d->m_supportedSampleRates != supportedSampleRates) - this->d->m_supportedSampleRates = supportedSampleRates; - - if (this->d->m_pinDescriptionMap != pinDescriptionMap) - this->d->m_pinDescriptionMap = pinDescriptionMap; - - if (this->d->m_sources != inputs) { - this->d->m_sources = inputs; - emit this->inputsChanged(inputs); - } - - if (this->d->m_sinks != outputs) { - this->d->m_sinks = outputs; - emit this->outputsChanged(outputs); - } - - QString defaultOutput = outputs.isEmpty()? "": outputs.first(); - QString defaultInput = inputs.isEmpty()? "": inputs.first(); - - if (this->d->m_defaultSource != defaultInput) { - this->d->m_defaultSource = defaultInput; - emit this->defaultInputChanged(defaultInput); - } - - if (this->d->m_defaultSink != defaultOutput) { - this->d->m_defaultSink = defaultOutput; - emit this->defaultOutputChanged(defaultOutput); - } -} - -#include "moc_audiodevoss.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/audiodevoss.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/audiodevoss.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/audiodevoss.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/audiodevoss.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef AUDIODEVPULSEAUDIO_H -#define AUDIODEVPULSEAUDIO_H - -#include "audiodev.h" - -/* In GNU/Linux load the OSS drivers as: - * - * sudo modprobe snd_pcm_oss snd_mixer_oss snd_seq_oss - */ - -class AudioDevOSSPrivate; - -class AudioDevOSS: public AudioDev -{ - Q_OBJECT - - public: - AudioDevOSS(QObject *parent=nullptr); - ~AudioDevOSS(); - - Q_INVOKABLE QString error() const; - Q_INVOKABLE QString defaultInput(); - Q_INVOKABLE QString defaultOutput(); - Q_INVOKABLE QStringList inputs(); - Q_INVOKABLE QStringList outputs(); - Q_INVOKABLE QString description(const QString &device); - Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); - Q_INVOKABLE QList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); - Q_INVOKABLE QList supportedSampleRates(const QString &device); - Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps); - Q_INVOKABLE QByteArray read(int samples); - Q_INVOKABLE bool write(const AkAudioPacket &frame); - Q_INVOKABLE bool uninit(); - - private: - AudioDevOSSPrivate *d; - - private slots: - void updateDevices(); - - friend class AudioDevOSSPrivate; -}; - -#endif // AUDIODEVPULSEAUDIO_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/plugin.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "plugin.h" -#include "audiodevoss.h" - -QObject *Plugin::create(const QString &key, const QString &specification) -{ - Q_UNUSED(specification) - - if (key == AK_PLUGIN_TYPE_SUBMODULE) - return new AudioDevOSS(); - - return nullptr; -} - -QStringList Plugin::keys() const -{ - return QStringList(); -} - -#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/plugin.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/oss/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef PLUGIN_H -#define PLUGIN_H - -#include - -class Plugin: public QObject, public AkPlugin -{ - Q_OBJECT - Q_INTERFACES(AkPlugin) - Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") - - public: - QObject *create(const QString &key, const QString &specification); - QStringList keys() const; -}; - -#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/pulseaudio/src/audiodevpulseaudio.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/pulseaudio/src/audiodevpulseaudio.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/pulseaudio/src/audiodevpulseaudio.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/pulseaudio/src/audiodevpulseaudio.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -36,10 +36,17 @@ inline SampleFormatMap initSampleFormatMap() { SampleFormatMap sampleFormat = { - {AkAudioCaps::SampleFormat_u8 , PA_SAMPLE_U8 }, + {AkAudioCaps::SampleFormat_u8 , PA_SAMPLE_U8 }, + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN {AkAudioCaps::SampleFormat_s16, PA_SAMPLE_S16LE }, {AkAudioCaps::SampleFormat_s32, PA_SAMPLE_S32LE }, - {AkAudioCaps::SampleFormat_flt, PA_SAMPLE_FLOAT32LE} + {AkAudioCaps::SampleFormat_flt, PA_SAMPLE_FLOAT32LE}, +#else + {AkAudioCaps::SampleFormat_s16, PA_SAMPLE_S16BE }, + {AkAudioCaps::SampleFormat_s32, PA_SAMPLE_S32BE }, + {AkAudioCaps::SampleFormat_flt, PA_SAMPLE_FLOAT32BE}, +#endif }; return sampleFormat; @@ -62,6 +69,7 @@ QMap m_pinCapsMap; QMap m_pinDescriptionMap; QMutex m_mutex; + int m_samples {0}; int m_curBps {0}; int m_curChannels {0}; @@ -311,11 +319,11 @@ return sampleFormats->keys(); } -QList AudioDevPulseAudio::supportedChannels(const QString &device) +QList AudioDevPulseAudio::supportedChannelLayouts(const QString &device) { Q_UNUSED(device) - return QList {1, 2}; + return {AkAudioCaps::Layout_mono, AkAudioCaps::Layout_stereo}; } QList AudioDevPulseAudio::supportedSampleRates(const QString &device) @@ -360,17 +368,19 @@ return false; } + this->d->m_samples = qMax(this->latency() * caps.rate() / 1000, 1); + return true; } -QByteArray AudioDevPulseAudio::read(int samples) +QByteArray AudioDevPulseAudio::read() { - if (samples < 1 || !this->d->m_paSimple) + if (!this->d->m_paSimple) return {}; int error; - QByteArray buffer(samples + QByteArray buffer(this->d->m_samples * this->d->m_curBps * this->d->m_curChannels, 0); @@ -452,15 +462,23 @@ case PA_SUBSCRIPTION_EVENT_CHANGE: switch (facility) { case PA_SUBSCRIPTION_EVENT_SERVER: - pa_operation_unref(pa_context_get_server_info(context, serverInfoCallback, userData)); + pa_operation_unref(pa_context_get_server_info(context, + serverInfoCallback, + userData)); break; case PA_SUBSCRIPTION_EVENT_SINK: - pa_operation_unref(pa_context_get_sink_info_by_index(context, index, sinkInfoCallback, userData)); + pa_operation_unref(pa_context_get_sink_info_by_index(context, + index, + sinkInfoCallback, + userData)); break; case PA_SUBSCRIPTION_EVENT_SOURCE: - pa_operation_unref(pa_context_get_source_info_by_index(context, index, sourceInfoCallback, userData)); + pa_operation_unref(pa_context_get_source_info_by_index(context, + index, + sourceInfoCallback, + userData)); break; default: @@ -546,7 +564,8 @@ auto audioDevice = reinterpret_cast(userdata); if (isLast < 0) { - audioDevice->d->m_error = QString(pa_strerror(pa_context_errno(context))); + audioDevice->d->m_error = + QString(pa_strerror(pa_context_errno(context))); emit audioDevice->errorChanged(audioDevice->d->m_error); return; @@ -563,9 +582,9 @@ // Get info for the pin. audioDevice->d->m_mutex.lock(); - QMap sources = audioDevice->d->m_sources; - QMap pinCapsMap = audioDevice->d->m_pinCapsMap; - QMap pinDescriptionMap = audioDevice->d->m_pinDescriptionMap; + auto sources = audioDevice->d->m_sources; + auto pinCapsMap = audioDevice->d->m_pinCapsMap; + auto pinDescriptionMap = audioDevice->d->m_pinDescriptionMap; audioDevice->d->m_sources[info->index] = info->name; @@ -575,7 +594,7 @@ audioDevice->d->m_pinCapsMap[info->name] = AkAudioCaps(sampleFormats->key(info->sample_spec.format), - info->sample_spec.channels, + AkAudioCaps::defaultChannelLayout(info->sample_spec.channels), int(info->sample_spec.rate)); if (sources != audioDevice->d->m_sources @@ -594,7 +613,8 @@ auto audioDevice = reinterpret_cast(userdata); if (isLast < 0) { - audioDevice->d->m_error = QString(pa_strerror(pa_context_errno(context))); + audioDevice->d->m_error = + QString(pa_strerror(pa_context_errno(context))); emit audioDevice->errorChanged(audioDevice->d->m_error); return; @@ -623,7 +643,7 @@ audioDevice->d->m_pinCapsMap[info->name] = AkAudioCaps(sampleFormats->key(info->sample_spec.format), - info->sample_spec.channels, + AkAudioCaps::defaultChannelLayout(info->sample_spec.channels), int(info->sample_spec.rate)); if (sinks != audioDevice->d->m_sinks diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/pulseaudio/src/audiodevpulseaudio.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/pulseaudio/src/audiodevpulseaudio.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/pulseaudio/src/audiodevpulseaudio.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/pulseaudio/src/audiodevpulseaudio.h 2021-02-15 15:25:23.000000000 +0000 @@ -40,10 +40,10 @@ Q_INVOKABLE QString description(const QString &device); Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); Q_INVOKABLE QList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); + Q_INVOKABLE QList supportedChannelLayouts(const QString &device); Q_INVOKABLE QList supportedSampleRates(const QString &device); Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps); - Q_INVOKABLE QByteArray read(int samples); + Q_INVOKABLE QByteArray read(); Q_INVOKABLE bool write(const AkAudioPacket &frame); Q_INVOKABLE bool uninit(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/pspec.json 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/pspec.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -{ - "pluginType": "Ak.SubModule" -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/qtaudio.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/qtaudio.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/qtaudio.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/qtaudio.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -# Webcamoid, webcam capture application. -# Copyright (C) 2016 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -exists(akcommons.pri) { - include(akcommons.pri) -} else { - exists(../../../../akcommons.pri) { - include(../../../../akcommons.pri) - } else { - error("akcommons.pri file not found.") - } -} - -CONFIG += plugin - -HEADERS = \ - src/plugin.h \ - src/audiodevqtaudio.h \ - ../audiodev.h \ - src/audiodevicebuffer.h - -INCLUDEPATH += \ - ../../../../Lib/src \ - ../ - -LIBS += -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} - -OTHER_FILES += pspec.json - -QT += qml multimedia - -SOURCES = \ - src/plugin.cpp \ - src/audiodevqtaudio.cpp \ - ../audiodev.cpp \ - src/audiodevicebuffer.cpp - -akModule = AudioDevice -DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} - -TEMPLATE = lib - -INSTALLS += target - -android { - TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} - target.path = $${LIBDIR} -} else { - target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevicebuffer.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevicebuffer.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevicebuffer.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevicebuffer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,197 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "audiodevicebuffer.h" - -#define TIME_OUT 500 -#define BLOCK_SIZE (2 * 2 * 1024) - -AudioDeviceBuffer::AudioDeviceBuffer(QObject *parent): - QIODevice(parent) -{ - this->m_blockSize = BLOCK_SIZE; - this->m_maxBufferSize = 4 * BLOCK_SIZE; - this->m_isOpen = false; -} - -AudioDeviceBuffer::~AudioDeviceBuffer() -{ - this->close(); -} - -qint64 AudioDeviceBuffer::blockSize() const -{ - return this->m_blockSize; -} - -qint64 AudioDeviceBuffer::maxBufferSize() const -{ - return this->m_maxBufferSize; -} - -bool AudioDeviceBuffer::atEnd() const -{ - return !this->isOpen(); -} - -qint64 AudioDeviceBuffer::bytesAvailable() const -{ - return this->m_blockSize; -} - -qint64 AudioDeviceBuffer::bytesToWrite() const -{ - return 0; -} - -bool AudioDeviceBuffer::canReadLine() const -{ - return false; -} - -void AudioDeviceBuffer::close() -{ - this->m_isOpen = false; - - this->m_mutex.lock(); - this->m_buffer.clear(); - this->m_mutex.unlock(); - QIODevice::close(); -} - -bool AudioDeviceBuffer::isSequential() const -{ - return true; -} - -bool AudioDeviceBuffer::open(QIODevice::OpenMode mode) -{ - this->m_mutex.lock(); - this->m_buffer.clear(); - this->m_isOpen = QIODevice::open(mode); - this->m_mutex.unlock(); - - return this->m_isOpen; -} - -qint64 AudioDeviceBuffer::pos() const -{ - return 0; -} - -bool AudioDeviceBuffer::reset() -{ - return false; -} - -bool AudioDeviceBuffer::seek(qint64 pos) -{ - Q_UNUSED(pos) - - return false; -} - -qint64 AudioDeviceBuffer::size() const -{ - return this->bytesAvailable(); -} - -bool AudioDeviceBuffer::waitForBytesWritten(int msecs) -{ - Q_UNUSED(msecs); - - return true; -} - -bool AudioDeviceBuffer::waitForReadyRead(int msecs) -{ - Q_UNUSED(msecs); - - return true; -} - -qint64 AudioDeviceBuffer::readData(char *data, qint64 maxSize) -{ - if (!this->m_isOpen) - return 0; - - memset(data, 0, size_t(maxSize)); - - this->m_mutex.lock(); - auto copyBytes = qMin(this->m_buffer.size(), maxSize); - memcpy(data, this->m_buffer.constData(), size_t(copyBytes)); - this->m_buffer.remove(0, int(copyBytes)); - - if (this->m_buffer.size() < this->m_maxBufferSize) - this->m_bufferNotFull.wakeAll(); - - this->m_mutex.unlock(); - - return maxSize; -} - -qint64 AudioDeviceBuffer::writeData(const char *data, qint64 maxSize) -{ - qint64 writenSize = 0; - - this->m_mutex.lock(); - - while (this->m_isOpen) { - if (this->m_buffer.size() >= this->m_maxBufferSize) - if (!this->m_bufferNotFull.wait(&this->m_mutex, TIME_OUT)) - continue; - - this->m_buffer.append(QByteArray::fromRawData(data, int(maxSize))); - writenSize = maxSize; - - break; - } - - this->m_mutex.unlock(); - - return writenSize; -} - -void AudioDeviceBuffer::setBlockSize(qint64 blockSize) -{ - if (this->m_blockSize == blockSize) - return; - - this->m_blockSize = blockSize; - emit this->blockSizeChanged(blockSize); -} - -void AudioDeviceBuffer::setMaxBufferSize(qint64 maxBufferSize) -{ - if (this->m_maxBufferSize == maxBufferSize) - return; - - this->m_maxBufferSize = maxBufferSize; - emit this->maxBufferSizeChanged(maxBufferSize); -} - -void AudioDeviceBuffer::resetBlockSize() -{ - this->setBlockSize(BLOCK_SIZE); -} - -void AudioDeviceBuffer::resetMaxBufferSize() -{ - this->setMaxBufferSize(4 * BLOCK_SIZE); -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevicebuffer.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevicebuffer.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevicebuffer.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevicebuffer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef AUDIODEVICEBUFFER_H -#define AUDIODEVICEBUFFER_H - -#include -#include -#include - -class AudioDeviceBuffer: public QIODevice -{ - Q_OBJECT - Q_PROPERTY(qint64 blockSize - READ blockSize - WRITE setBlockSize - RESET resetBlockSize - NOTIFY blockSizeChanged) - Q_PROPERTY(qint64 maxBufferSize - READ maxBufferSize - WRITE setMaxBufferSize - RESET resetMaxBufferSize - NOTIFY maxBufferSizeChanged) - - public: - AudioDeviceBuffer(QObject *parent=nullptr); - ~AudioDeviceBuffer(); - - Q_INVOKABLE qint64 blockSize() const; - Q_INVOKABLE qint64 maxBufferSize() const; - - bool atEnd() const; - qint64 bytesAvailable() const; - qint64 bytesToWrite() const; - bool canReadLine() const; - void close(); - bool isSequential() const; - bool open(OpenMode mode); - qint64 pos() const; - bool reset(); - bool seek(qint64 pos); - qint64 size() const; - bool waitForBytesWritten(int msecs); - bool waitForReadyRead(int msecs); - - private: - QByteArray m_buffer; - qint64 m_blockSize; - qint64 m_maxBufferSize; - QMutex m_mutex; - QWaitCondition m_bufferNotFull; - bool m_isOpen; - - protected: - qint64 readData(char *data, qint64 maxSize); - qint64 writeData(const char *data, qint64 maxSize); - - signals: - void blockSizeChanged(qint64 blockSize); - void maxBufferSizeChanged(qint64 maxBufferSize); - - public slots: - void setBlockSize(qint64 blockSize); - void setMaxBufferSize(qint64 maxBufferSize); - void resetBlockSize(); - void resetMaxBufferSize(); -}; - -#endif // AUDIODEVICEBUFFER_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevqtaudio.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevqtaudio.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevqtaudio.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevqtaudio.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,371 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include -#include -#include -#include -#include -#include - -#include "audiodevqtaudio.h" -#include "audiodevicebuffer.h" - -#define BUFFER_SIZE 1024 // In samples - -inline bool operator <(const QAudioDeviceInfo &info1, - const QAudioDeviceInfo &info2) -{ - return info1.deviceName() < info2.deviceName(); -} - -class AudioDevQtAudioPrivate -{ - public: - QString m_error; - QString m_defaultSink; - QString m_defaultSource; - QMap m_sinks; - QMap m_sources; - QMap m_pinCapsMap; - QMap m_pinDescriptionMap; - QMap> m_supportedFormats; - QMap> m_supportedChannels; - QMap> m_supportedSampleRates; - AudioDeviceBuffer m_outputDeviceBuffer; - QIODevice *m_inputDeviceBuffer {nullptr}; - QAudioInput *m_input {nullptr}; - QAudioOutput *m_output {nullptr}; - QMutex m_mutex; - - AkAudioCaps::SampleFormat qtFormatToAk(const QAudioFormat &format) const; - QAudioFormat qtFormatFromCaps(const AkAudioCaps &caps) const; -}; - -AudioDevQtAudio::AudioDevQtAudio(QObject *parent): - AudioDev(parent) -{ - this->d = new AudioDevQtAudioPrivate; - this->updateDevices(); -} - -AudioDevQtAudio::~AudioDevQtAudio() -{ - this->uninit(); - delete this->d; -} - -QString AudioDevQtAudio::error() const -{ - return this->d->m_error; -} - -QString AudioDevQtAudio::defaultInput() -{ - return this->d->m_defaultSource; -} - -QString AudioDevQtAudio::defaultOutput() -{ - return this->d->m_defaultSink; -} - -QStringList AudioDevQtAudio::inputs() -{ - return this->d->m_sources.values(); -} - -QStringList AudioDevQtAudio::outputs() -{ - return this->d->m_sinks.values(); -} - -QString AudioDevQtAudio::description(const QString &device) -{ - return this->d->m_pinDescriptionMap.value(device); -} - -AkAudioCaps AudioDevQtAudio::preferredFormat(const QString &device) -{ - return this->d->m_pinCapsMap.value(device); -} - -QList AudioDevQtAudio::supportedFormats(const QString &device) -{ - return this->d->m_supportedFormats.value(device); -} - -QList AudioDevQtAudio::supportedChannels(const QString &device) -{ - return this->d->m_supportedChannels.value(device); -} - -QList AudioDevQtAudio::supportedSampleRates(const QString &device) -{ - return this->d->m_supportedSampleRates.value(device); -} - -bool AudioDevQtAudio::init(const QString &device, const AkAudioCaps &caps) -{ - int blockSize = BUFFER_SIZE - * caps.channels() - * caps.bps() - / 8; - - this->d->m_mutex.lock(); - this->d->m_outputDeviceBuffer.setBlockSize(blockSize); - this->d->m_outputDeviceBuffer.setMaxBufferSize(4 * blockSize); - this->d->m_outputDeviceBuffer.open(QIODevice::ReadWrite); - - if (device.endsWith(":Output")) { - auto deviceInfo = this->d->m_sinks.key(device); - auto format = this->d->qtFormatFromCaps(caps); - this->d->m_output = new QAudioOutput(deviceInfo, format); - this->d->m_output->start(&this->d->m_outputDeviceBuffer); - - if (this->d->m_output->error() != QAudio::NoError) { - this->d->m_mutex.unlock(); - this->uninit(); - - return false; - } - } else if (device.endsWith(":Input")) { - auto deviceInfo = this->d->m_sources.key(device); - auto format = this->d->qtFormatFromCaps(caps); - this->d->m_input = new QAudioInput(deviceInfo, format); - this->d->m_inputDeviceBuffer = this->d->m_input->start(); - - if (!this->d->m_inputDeviceBuffer - || this->d->m_input->error() != QAudio::NoError) { - this->d->m_mutex.unlock(); - this->uninit(); - - return false; - } - } else { - this->d->m_mutex.unlock(); - this->uninit(); - - return false; - } - - this->d->m_mutex.unlock(); - - return true; -} - -QByteArray AudioDevQtAudio::read(int samples) -{ - if (samples < 1) - return {}; - - QByteArray buffer; - - this->d->m_mutex.lock(); - - if (this->d->m_inputDeviceBuffer) { - auto format = this->d->m_input->format(); - auto bufferSize = format.channelCount() - * format.sampleSize() - * samples - / 8; - auto readBytes = bufferSize; - - while (buffer.size() < bufferSize) { - auto data = this->d->m_inputDeviceBuffer->read(readBytes); - buffer.append(data); - readBytes -= data.size(); - } - } - - this->d->m_mutex.unlock(); - - return buffer; -} - -bool AudioDevQtAudio::write(const AkAudioPacket &packet) -{ - this->d->m_mutex.lock(); - this->d->m_outputDeviceBuffer.write(packet.buffer()); - this->d->m_mutex.unlock(); - - return true; -} - -bool AudioDevQtAudio::uninit() -{ - this->d->m_mutex.lock(); - - this->d->m_outputDeviceBuffer.close(); - - if (this->d->m_input) { - this->d->m_input->stop(); - delete this->d->m_input; - this->d->m_input = nullptr; - } - - if (this->d->m_output) { - this->d->m_output->stop(); - delete this->d->m_output; - this->d->m_output = nullptr; - } - - this->d->m_inputDeviceBuffer = nullptr; - this->d->m_mutex.unlock(); - - return true; -} - -AkAudioCaps::SampleFormat AudioDevQtAudioPrivate::qtFormatToAk(const QAudioFormat &format) const -{ - return AkAudioCaps::sampleFormatFromProperties( - format.sampleType() == QAudioFormat::SignedInt? - AkAudioCaps::SampleType_int: - format.sampleType() == QAudioFormat::UnSignedInt? - AkAudioCaps::SampleType_uint: - format.sampleType() == QAudioFormat::Float? - AkAudioCaps::SampleType_float: - AkAudioCaps::SampleType_unknown, - format.sampleSize(), - format.byteOrder() == QAudioFormat::LittleEndian? - Q_LITTLE_ENDIAN: Q_BIG_ENDIAN, - false); -} - -QAudioFormat AudioDevQtAudioPrivate::qtFormatFromCaps(const AkAudioCaps &caps) const -{ - QAudioFormat audioFormat; - audioFormat.setByteOrder(AkAudioCaps::endianness(caps.format()) == Q_LITTLE_ENDIAN? - QAudioFormat::LittleEndian: QAudioFormat::BigEndian); - audioFormat.setChannelCount(caps.channels()); - audioFormat.setCodec("audio/pcm"); - audioFormat.setSampleRate(caps.rate()); - audioFormat.setSampleSize(caps.bps()); - auto sampleType = AkAudioCaps::sampleType(caps.format()); - audioFormat.setSampleType(sampleType == AkAudioCaps::SampleType_int? - QAudioFormat::SignedInt: - sampleType == AkAudioCaps::SampleType_uint? - QAudioFormat::UnSignedInt: - sampleType == AkAudioCaps::SampleType_float? - QAudioFormat::Float: - QAudioFormat::Unknown); - - return audioFormat; -} - -void AudioDevQtAudio::updateDevices() -{ - decltype(this->d->m_defaultSink) defaultSink; - decltype(this->d->m_defaultSource) defaultSource; - decltype(this->d->m_sinks) sinks; - decltype(this->d->m_sources) sources; - decltype(this->d->m_pinCapsMap) pinCapsMap; - decltype(this->d->m_pinDescriptionMap) pinDescriptionMap; - decltype(this->d->m_supportedFormats) supportedFormats; - decltype(this->d->m_supportedChannels) supportedChannels; - decltype(this->d->m_supportedSampleRates) supportedSampleRates; - - for (auto &mode: QVector {QAudio::AudioInput, - QAudio::AudioOutput}) { - for (auto &device: QAudioDeviceInfo::availableDevices(mode)) { - auto description = device.deviceName(); - auto deviceName = description; - - if (mode == QAudio::AudioInput) { - deviceName += ":Input"; - sources[device] = deviceName; - } else { - deviceName += ":Output"; - sinks[device] = deviceName; - } - - auto preferredFormat = device.preferredFormat(); - - pinCapsMap[deviceName] = - AkAudioCaps(this->d->qtFormatToAk(preferredFormat), - preferredFormat.channelCount(), - preferredFormat.sampleRate()); - pinDescriptionMap[deviceName] = description; - QList _supportedFormats; - QAudioFormat audioFormat; - audioFormat.setChannelCount(2); - audioFormat.setCodec("audio/pcm"); - audioFormat.setSampleRate(44100); - - for (auto &endianness: device.supportedByteOrders()) - for (auto &sampleSize: device.supportedSampleSizes()) - for (auto &sampleType: device.supportedSampleTypes()) { - audioFormat.setByteOrder(endianness); - audioFormat.setSampleSize(sampleSize); - audioFormat.setSampleType(sampleType); - auto format = this->d->qtFormatToAk(audioFormat); - - if (format != AkAudioCaps::SampleFormat_none) - _supportedFormats << format; - } - - supportedFormats[deviceName] = _supportedFormats; - supportedChannels[deviceName] = device.supportedChannelCounts(); - supportedSampleRates[deviceName] = device.supportedSampleRates(); - } - } - - defaultSource = QAudioDeviceInfo::defaultInputDevice().deviceName() + ":Input"; - defaultSink = QAudioDeviceInfo::defaultOutputDevice().deviceName() + ":Output"; - - if (this->d->m_pinCapsMap != pinCapsMap) - this->d->m_pinCapsMap = pinCapsMap; - - if (this->d->m_supportedFormats != supportedFormats) - this->d->m_supportedFormats = supportedFormats; - - if (this->d->m_supportedChannels != supportedChannels) - this->d->m_supportedChannels = supportedChannels; - - if (this->d->m_supportedSampleRates != supportedSampleRates) - this->d->m_supportedSampleRates = supportedSampleRates; - - if (this->d->m_pinDescriptionMap != pinDescriptionMap) - this->d->m_pinDescriptionMap = pinDescriptionMap; - - if (this->d->m_sources != sources) { - this->d->m_sources = sources; - emit this->inputsChanged(sources.values()); - } - - if (this->d->m_sinks != sinks) { - this->d->m_sinks = sinks; - emit this->outputsChanged(sinks.values()); - } - - QString defaultOutput = sinks.isEmpty()? "": defaultSink; - QString defaultInput = sources.isEmpty()? "": defaultSource; - - if (this->d->m_defaultSource != defaultInput) { - this->d->m_defaultSource = defaultInput; - emit this->defaultInputChanged(defaultInput); - } - - if (this->d->m_defaultSink != defaultOutput) { - this->d->m_defaultSink = defaultOutput; - emit this->defaultOutputChanged(defaultOutput); - } -} - -#include "moc_audiodevqtaudio.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevqtaudio.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevqtaudio.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevqtaudio.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/audiodevqtaudio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef AUDIODEVQTAUDIO_H -#define AUDIODEVQTAUDIO_H - -#include "audiodev.h" - -class AudioDevQtAudioPrivate; - -class AudioDevQtAudio: public AudioDev -{ - Q_OBJECT - - public: - AudioDevQtAudio(QObject *parent=nullptr); - ~AudioDevQtAudio(); - - Q_INVOKABLE QString error() const; - Q_INVOKABLE QString defaultInput(); - Q_INVOKABLE QString defaultOutput(); - Q_INVOKABLE QStringList inputs(); - Q_INVOKABLE QStringList outputs(); - Q_INVOKABLE QString description(const QString &device); - Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); - Q_INVOKABLE QList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); - Q_INVOKABLE QList supportedSampleRates(const QString &device); - Q_INVOKABLE bool init(const QString &device, - const AkAudioCaps &caps); - Q_INVOKABLE QByteArray read(int samples); - Q_INVOKABLE bool write(const AkAudioPacket &packet); - Q_INVOKABLE bool uninit(); - - private: - AudioDevQtAudioPrivate *d; - - private slots: - void updateDevices(); -}; - -#endif // AUDIODEVQTAUDIO_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/plugin.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "plugin.h" -#include "audiodevqtaudio.h" - -QObject *Plugin::create(const QString &key, const QString &specification) -{ - Q_UNUSED(specification) - - if (key == AK_PLUGIN_TYPE_SUBMODULE) - return new AudioDevQtAudio(); - - return nullptr; -} - -QStringList Plugin::keys() const -{ - return QStringList(); -} - -#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/plugin.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/qtaudio/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef PLUGIN_H -#define PLUGIN_H - -#include - -class Plugin: public QObject, public AkPlugin -{ - Q_OBJECT - Q_INTERFACES(AkPlugin) - Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") - - public: - QObject *create(const QString &key, const QString &specification); - QStringList keys() const; -}; - -#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/src.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/src.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/src.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/src.pro 2021-02-15 15:25:23.000000000 +0000 @@ -31,8 +31,9 @@ HEADERS = \ audiodevice.h \ audiodeviceelement.h \ - audiodev.h \ - audiodeviceglobals.h + audiodeviceelementsettings.h \ + audiodeviceglobals.h \ + audiodev.h INCLUDEPATH += \ ../../../Lib/src @@ -47,8 +48,9 @@ SOURCES = \ audiodevice.cpp \ audiodeviceelement.cpp \ - audiodev.cpp \ - audiodeviceglobals.cpp + audiodeviceelementsettings.cpp \ + audiodeviceglobals.cpp \ + audiodev.cpp DESTDIR = $${OUT_PWD}/../$${BIN_DIR} TARGET = AudioDevice diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/wasapi/src/audiodevwasapi.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/wasapi/src/audiodevwasapi.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/wasapi/src/audiodevwasapi.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/wasapi/src/audiodevwasapi.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -32,7 +32,7 @@ #define MAX_ERRORS_READ_WRITE 5 #define EVENT_TIMEOUT 1000 -typedef QMap ErrorCodesMap; +using ErrorCodesMap = QMap; inline ErrorCodesMap initErrorCodesMap() { @@ -89,11 +89,13 @@ QString m_defaultSource; QMap m_descriptionMap; QMap> m_supportedFormats; - QMap> m_supportedChannels; + QMap> m_supportedLayouts; QMap> m_supportedSampleRates; QMap m_preferredInputCaps; QMap m_preferredOutputCaps; QByteArray m_audioBuffer; + AkAudioCaps m_curCaps; + QString m_curDevice; IMMDeviceEnumerator *m_deviceEnumerator {nullptr}; IMMDevice *m_pDevice {nullptr}; IAudioClient *m_pAudioClient {nullptr}; @@ -101,20 +103,15 @@ IAudioRenderClient *m_pRenderClient {nullptr}; HANDLE m_hEvent {nullptr}; ULONG m_cRef {1}; - AkAudioCaps m_curCaps; - QString m_curDevice; - - explicit AudioDevWasapiPrivate(AudioDevWasapi *self): - self(self) - { - } + int m_samples {0}; + explicit AudioDevWasapiPrivate(AudioDevWasapi *self); bool waveFormatFromCaps(WAVEFORMATEX *wfx, const AkAudioCaps &caps) const; AkAudioCaps capsFromWaveFormat(WAVEFORMATEX *wfx) const; void fillDeviceInfo(const QString &device, QList *supportedFormats, - QList *supportedChannels, + QList *supportedLayouts, QList *supportedSampleRates) const; AkAudioCaps preferredCaps(const QString &device, EDataFlow dataFlow) const; @@ -202,9 +199,9 @@ return this->d->m_supportedFormats.value(device); } -QList AudioDevWasapi::supportedChannels(const QString &device) +QList AudioDevWasapi::supportedChannelLayouts(const QString &device) { - return this->d->m_supportedChannels.value(device); + return this->d->m_supportedLayouts.value(device); } QList AudioDevWasapi::supportedSampleRates(const QString &device) @@ -361,16 +358,14 @@ } this->d->m_curDevice = device; + this->d->m_samples = qMax(this->latency() * caps.rate() / 1000, 1); return true; } -QByteArray AudioDevWasapi::read(int samples) +QByteArray AudioDevWasapi::read() { - if (samples < 1) - return {}; - - int bufferSize = samples + int bufferSize = this->d->m_samples * this->d->m_curCaps.bps() * this->d->m_curCaps.channels() / 8; @@ -614,6 +609,11 @@ return lRef; } +AudioDevWasapiPrivate::AudioDevWasapiPrivate(AudioDevWasapi *self): + self(self) +{ +} + bool AudioDevWasapiPrivate::waveFormatFromCaps(WAVEFORMATEX *wfx, const AkAudioCaps &caps) const { @@ -644,17 +644,16 @@ auto sampleFormat = AkAudioCaps::sampleFormatFromProperties(sampleType, int(wfx->wBitsPerSample), - Q_BYTE_ORDER, - false); + Q_BYTE_ORDER); return AkAudioCaps(sampleFormat, - int(wfx->nChannels), + AkAudioCaps::defaultChannelLayout(int(wfx->nChannels)), int(wfx->nSamplesPerSec)); } void AudioDevWasapiPrivate::fillDeviceInfo(const QString &device, QList *supportedFormats, - QList *supportedChannels, + QList *supportedLayouts, QList *supportedSampleRates) const { if (!this->m_deviceEnumerator) @@ -684,11 +683,11 @@ pAudioClient = this->m_pAudioClient; } - static const QVector preferredFormats = { + static const QVector preferredFormats { AkAudioCaps::SampleFormat_flt, AkAudioCaps::SampleFormat_s32, AkAudioCaps::SampleFormat_s16, - AkAudioCaps::SampleFormat_u8 + AkAudioCaps::SampleFormat_u8, }; for (auto &format: preferredFormats) @@ -696,14 +695,16 @@ for (auto &rate: self->commonSampleRates()) { WAVEFORMATEX wfx; WAVEFORMATEX *closestWfx = nullptr; - this->waveFormatFromCaps(&wfx, - AkAudioCaps(format, channels, rate)); + AkAudioCaps audioCaps(format, + AkAudioCaps::defaultChannelLayout(channels), + rate); + this->waveFormatFromCaps(&wfx, audioCaps); if (SUCCEEDED(pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &wfx, &closestWfx))) { AkAudioCaps::SampleFormat sampleFormat; - int nchannels; + AkAudioCaps::ChannelLayout layout; int sampleRate; if (closestWfx) { @@ -714,22 +715,22 @@ sampleFormat = AkAudioCaps::sampleFormatFromProperties(sampleType, int(closestWfx->wBitsPerSample), - Q_BYTE_ORDER, - false); - nchannels = int(closestWfx->nChannels); + Q_BYTE_ORDER); + layout = AkAudioCaps::defaultChannelLayout(int(closestWfx->nChannels)); sampleRate = int(closestWfx->nSamplesPerSec); CoTaskMemFree(closestWfx); } else { sampleFormat = format; - nchannels = channels; + layout = AkAudioCaps::defaultChannelLayout(channels); sampleRate = rate; } if (!supportedFormats->contains(sampleFormat)) supportedFormats->append(sampleFormat); - if (!supportedChannels->contains(nchannels)) - supportedChannels->append(nchannels); + if (layout != AkAudioCaps::Layout_none + && !supportedLayouts->contains(layout)) + supportedLayouts->append(layout); if (!supportedSampleRates->contains(sampleRate)) supportedSampleRates->append(sampleRate); @@ -740,6 +741,8 @@ pAudioClient->Release(); pDevice->Release(); } + + std::sort(supportedFormats->begin(), supportedFormats->end()); } AkAudioCaps AudioDevWasapiPrivate::preferredCaps(const QString &device, @@ -774,10 +777,10 @@ AkAudioCaps caps = dataFlow == eCapture? AkAudioCaps(AkAudioCaps::SampleFormat_u8, - 1, + AkAudioCaps::Layout_mono, 8000): AkAudioCaps(AkAudioCaps::SampleFormat_s16, - 2, + AkAudioCaps::Layout_stereo, 44100); WAVEFORMATEX wfx; @@ -874,7 +877,7 @@ decltype(this->d->m_defaultSource) defaultSource; decltype(this->d->m_descriptionMap) descriptionMap; decltype(this->d->m_supportedFormats) supportedFormats; - decltype(this->d->m_supportedChannels) supportedChannels; + decltype(this->d->m_supportedLayouts) supportedChannels; decltype(this->d->m_supportedSampleRates) supportedSampleRates; decltype(this->d->m_preferredInputCaps) preferredInputCaps; decltype(this->d->m_preferredOutputCaps) preferredOutputCaps; @@ -926,27 +929,27 @@ auto devId = QString::fromWCharArray(deviceId); QList _supportedFormats; - QList _supportedChannels; + QList _supportedLayouts; QList _supportedSampleRates; this->d->fillDeviceInfo(devId, &_supportedFormats, - &_supportedChannels, + &_supportedLayouts, &_supportedSampleRates); if (_supportedFormats.isEmpty()) _supportedFormats = this->d->m_supportedFormats.value(devId); - if (_supportedChannels.isEmpty()) - _supportedChannels = - this->d->m_supportedChannels.value(devId); + if (_supportedLayouts.isEmpty()) + _supportedLayouts = + this->d->m_supportedLayouts.value(devId); if (_supportedSampleRates.isEmpty()) _supportedSampleRates = this->d->m_supportedSampleRates.value(devId); if (!_supportedFormats.isEmpty() - && !_supportedChannels.isEmpty() + && !_supportedLayouts.isEmpty() && !_supportedSampleRates.isEmpty()) { if (dataFlow == eCapture) { inputs << devId; @@ -963,7 +966,7 @@ descriptionMap[devId] = QString::fromWCharArray(friendlyName.pwszVal); supportedFormats[devId] = _supportedFormats; - supportedChannels[devId] = _supportedChannels; + supportedChannels[devId] = _supportedLayouts; supportedSampleRates[devId] = _supportedSampleRates; } @@ -987,8 +990,8 @@ if (this->d->m_supportedFormats != supportedFormats) this->d->m_supportedFormats = supportedFormats; - if (this->d->m_supportedChannels != supportedChannels) - this->d->m_supportedChannels = supportedChannels; + if (this->d->m_supportedLayouts != supportedChannels) + this->d->m_supportedLayouts = supportedChannels; if (this->d->m_supportedSampleRates != supportedSampleRates) this->d->m_supportedSampleRates = supportedSampleRates; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/wasapi/src/audiodevwasapi.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/wasapi/src/audiodevwasapi.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioDevice/src/wasapi/src/audiodevwasapi.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioDevice/src/wasapi/src/audiodevwasapi.h 2021-02-15 15:25:23.000000000 +0000 @@ -42,14 +42,14 @@ Q_INVOKABLE QString description(const QString &device); Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); Q_INVOKABLE QList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); + Q_INVOKABLE QList supportedChannelLayouts(const QString &device); Q_INVOKABLE QList supportedSampleRates(const QString &device); Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps); Q_INVOKABLE bool init(const QString &device, const AkAudioCaps &caps, bool justActivate); - Q_INVOKABLE QByteArray read(int samples); + Q_INVOKABLE QByteArray read(); Q_INVOKABLE bool write(const AkAudioPacket &packet); Q_INVOKABLE bool uninit(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioGen/src/audiogenelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioGen/src/audiogenelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioGen/src/audiogenelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioGen/src/audiogenelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,19 +17,20 @@ * Web-Site: http://webcamoid.github.io/ */ -#include -#include -#include -#include -#include #include +#include #include +#include +#include +#include #include +#include #include #include #include #include #include +#include #include #include @@ -67,7 +68,11 @@ class AudioGenElementPrivate { public: - AkCaps m_caps {"audio/x-raw,format=flt,bps=4,channels=1,rate=44100,layout=mono,align=false"}; + AkAudioCaps m_caps { + AkAudioCaps::SampleFormat_s16, + AkAudioCaps::Layout_mono, + 44100 + }; AkElementPtr m_audioConvert {AkElement::create("ACapsConvert")}; QThreadPool m_threadPool; QFuture m_readFramesLoopResult; @@ -101,9 +106,9 @@ delete this->d; } -QString AudioGenElement::caps() const +AkAudioCaps AudioGenElement::caps() const { - return this->d->m_caps.toString(); + return this->d->m_caps; } QString AudioGenElement::waveType() const @@ -126,7 +131,7 @@ return this->d->m_sampleDuration; } -void AudioGenElement::setCaps(const QString &caps) +void AudioGenElement::setCaps(const AkAudioCaps &caps) { if (this->d->m_caps == caps) return; @@ -136,7 +141,7 @@ this->d->m_mutex.unlock(); if (this->d->m_audioConvert) - this->d->m_audioConvert->setProperty("caps", caps); + this->d->m_audioConvert->setProperty("caps", QVariant::fromValue(caps)); emit this->capsChanged(caps); } @@ -184,7 +189,9 @@ void AudioGenElement::resetCaps() { - this->setCaps("audio/x-raw,format=flt,bps=4,channels=1,rate=44100,layout=mono,align=false"); + this->setCaps({AkAudioCaps::SampleFormat_s16, + AkAudioCaps::Layout_mono, + 44100}); } void AudioGenElement::resetWaveType() @@ -302,6 +309,14 @@ qreal avgDiff = 0; int frameCount = 0; + this->m_mutex.lock(); + int rate = this->m_caps.rate(); + qreal sampleDuration = this->m_sampleDuration; + AkAudioCaps audioCaps(AkAudioCaps::SampleFormat_s32, + AkAudioCaps::Layout_mono, + rate); + this->m_mutex.unlock(); + while (this->m_readFramesLoop) { if (this->m_pause) { QThread::msleep(PAUSE_TIMEOUT); @@ -309,25 +324,19 @@ continue; } - this->m_mutex.lock(); - AkCaps oCaps = this->m_caps; - qreal sampleDuration = this->m_sampleDuration; - this->m_mutex.unlock(); - - AkAudioCaps oAudioCaps(oCaps); qreal clock = 0.; qreal diff = 0.; for (int i = 0; i < 2; i++) { clock = 1.e-3 * (QTime::currentTime().msecsSinceStartOfDay() - t0); - diff = qreal(pts) / oAudioCaps.rate() - clock; + diff = qreal(pts) / audioCaps.rate() - clock; // Sleep until the moment of sending the frame. if (!i && diff < 0) QThread::usleep(ulong(1e6 * qAbs(diff))); } - int nSamples = qRound(oAudioCaps.rate() * sampleDuration / 1.e3); + int nSamples = qRound(audioCaps.rate() * sampleDuration / 1.e3); if (qAbs(diff) < AV_NOSYNC_THRESHOLD) { avgDiff = avgDiff * (1. - coeff) + qAbs(diff) * coeff; @@ -335,40 +344,36 @@ if (frameCount < AUDIO_DIFF_AVG_NB) { frameCount++; } else { - qreal diffThreshold = 2. * nSamples / oAudioCaps.rate(); + qreal diffThreshold = 2. * nSamples / audioCaps.rate(); if (avgDiff >= diffThreshold) { - int wantedSamples = qRound(nSamples + diff * oAudioCaps.rate()); + int wantedSamples = qRound(nSamples + diff * audioCaps.rate()); int minSamples = nSamples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100; int maxSamples = nSamples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100; nSamples = qBound(minSamples, wantedSamples, maxSamples); } } } else { - pts = qRound(clock * oAudioCaps.rate()); + pts = qRound(clock * audioCaps.rate()); avgDiff = 0.; frameCount = 0; } - size_t bufferSize = sizeof(qint32) * size_t(nSamples); - - QByteArray iBuffer(int(bufferSize), 0); + audioCaps.setSamples(nSamples); + AkAudioPacket iPacket(audioCaps); qreal time = QTime::currentTime().msecsSinceStartOfDay() / 1.e3; - qreal tdiff = 1. / oAudioCaps.rate(); + qreal tdiff = 1. / audioCaps.rate(); if (this->m_waveType == AudioGenElement::WaveTypeSilence) { - iBuffer.fill(0); + iPacket.buffer().fill(0); } else if (this->m_waveType == AudioGenElement::WaveTypeWhiteNoise) { - static std::default_random_engine engine; - static std::uniform_int_distribution distribution(-128, 127); - - for (auto &c: iBuffer) - c = char(distribution(engine)); + for (auto &c: iPacket.buffer()) + c = char(QRandomGenerator::global()->bounded(-128, 127)); } else { auto ampMax = qint32(this->m_volume * std::numeric_limits::max()); auto ampMin = qint32(this->m_volume * std::numeric_limits::min()); auto t = time; - auto buff = reinterpret_cast(iBuffer.data()); + auto buff = reinterpret_cast(iPacket.buffer().data()); if (this->m_waveType == AudioGenElement::WaveTypeSine) { for (int i = 0; i < nSamples; i++, time += tdiff) @@ -378,7 +383,7 @@ buff[i] = (qRound(2 * this->m_frequency * t) & 0x1)? ampMin: ampMax; } else { - qint32 mod = qRound(oAudioCaps.rate() / this->m_frequency); + qint32 mod = qRound(audioCaps.rate() / this->m_frequency); if (this->m_waveType == AudioGenElement::WaveTypeSawtooth) { qreal k = (qreal(ampMax) - ampMin) / (mod - 1); @@ -402,20 +407,12 @@ } } - AkAudioCaps iAudioCaps(oAudioCaps); - iAudioCaps.format() = AkAudioCaps::SampleFormat_s32; - iAudioCaps.bps() = AkAudioCaps::bitsPerSample(iAudioCaps.format()); - iAudioCaps.channels() = 1; - iAudioCaps.layout() = AkAudioCaps::Layout_mono; - iAudioCaps.samples() = nSamples; - - AkAudioPacket iPacket(iAudioCaps, iBuffer); iPacket.pts() = pts; - iPacket.timeBase() = AkFrac(1, iAudioCaps.rate()); + iPacket.timeBase() = AkFrac(1, audioCaps.rate()); iPacket.index() = 0; iPacket.id() = this->m_id; - (*this->m_audioConvert)(iPacket.toPacket()); + (*this->m_audioConvert)(iPacket); pts += nSamples; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioGen/src/audiogenelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioGen/src/audiogenelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/AudioGen/src/audiogenelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/AudioGen/src/audiogenelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -23,12 +23,13 @@ #include class AudioGenElementPrivate; +class AkAudioCaps; class AudioGenElement: public AkElement { Q_OBJECT Q_ENUMS(WaveType) - Q_PROPERTY(QString caps + Q_PROPERTY(AkAudioCaps caps READ caps WRITE setCaps RESET resetCaps @@ -68,7 +69,7 @@ AudioGenElement(); ~AudioGenElement(); - Q_INVOKABLE QString caps() const; + Q_INVOKABLE AkAudioCaps caps() const; Q_INVOKABLE QString waveType() const; Q_INVOKABLE qreal frequency() const; Q_INVOKABLE qreal volume() const; @@ -78,14 +79,14 @@ AudioGenElementPrivate *d; signals: - void capsChanged(const QString &caps); + void capsChanged(const AkAudioCaps &caps); void waveTypeChanged(const QString &waveType); void frequencyChanged(qreal frequency); void volumeChanged(qreal volume); void sampleDurationChanged(qreal sampleDuration); public slots: - void setCaps(const QString &caps); + void setCaps(const AkAudioCaps &caps); void setWaveType(const QString &waveType); void setFrequency(qreal frequency); void setVolume(qreal volume); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/Bin.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/Bin.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/Bin.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/Bin.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -# Webcamoid, webcam capture application. -# Copyright (C) 2016 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -exists(akcommons.pri) { - include(akcommons.pri) -} else { - exists(../../akcommons.pri) { - include(../../akcommons.pri) - } else { - error("akcommons.pri file not found.") - } -} - -CONFIG += plugin - -HEADERS = \ - src/bin.h \ - src/binelement.h \ - src/pipeline.h - -INCLUDEPATH += \ - ../../Lib/src - -LIBS += -L$${OUT_PWD}/../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} - -OTHER_FILES += \ - pspec.json - -QT += qml - -SOURCES = \ - src/bin.cpp \ - src/binelement.cpp \ - src/pipeline.cpp - -DESTDIR = $${OUT_PWD}/$${BIN_DIR} -android: TARGET = $${COMMONS_TARGET}_lib$${TARGET} - -TEMPLATE = lib - -INSTALLS += target -target.path = $${INSTALLPLUGINSDIR} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/pspec.json 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/pspec.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -{ - "pluginType": "Ak.Element" -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/bin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/bin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/bin.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/bin.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "bin.h" -#include "binelement.h" - -QObject *Bin::create(const QString &key, const QString &specification) -{ - Q_UNUSED(specification) - - if (key == AK_PLUGIN_TYPE_ELEMENT) - return new BinElement(); - - return nullptr; -} - -QStringList Bin::keys() const -{ - return QStringList(); -} - -#include "moc_bin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/binelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/binelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/binelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/binelement.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,206 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include -#include -#include - -#include "binelement.h" -#include "pipeline.h" - -class BinElementPrivate -{ - public: - QString m_description; - QMap m_elements; - QList m_inputs; - QList m_outputs; - Pipeline m_pipelineDescription; - bool m_blocking {false}; -}; - -BinElement::BinElement(): - AkElement() -{ - this->d = new BinElementPrivate; - this->d->m_pipelineDescription.setParent(this); -} - -BinElement::~BinElement() -{ - delete this->d; -} - -QString BinElement::description() const -{ - return this->d->m_description; -} - -bool BinElement::blocking() const -{ - return this->d->m_blocking; -} - -AkElementPtr BinElement::element(const QString &elementName) -{ - return this->d->m_elements[elementName]; -} - -void BinElement::add(const AkElementPtr &element) -{ - this->d->m_pipelineDescription.addElement(element); -} - -void BinElement::remove(const QString &elementName) -{ - this->d->m_pipelineDescription.removeElement(elementName); -} - -void BinElement::setDescription(const QString &description) -{ - if (this->d->m_description == description) - return; - - ElementState preState = this->state(); - - this->setState(ElementStateNull); - - if (this->d->m_description.isEmpty()) { - this->d->m_pipelineDescription.parse(description); - QString error = this->d->m_pipelineDescription.error(); - - if (error.isEmpty()) { - this->d->m_description = description; - - this->d->m_elements = this->d->m_pipelineDescription.elements(); - this->d->m_inputs = this->d->m_pipelineDescription.inputs(); - this->d->m_outputs = this->d->m_pipelineDescription.outputs(); - this->connectOutputs(); - } else { - this->d->m_pipelineDescription.cleanAll(); - - qDebug() << error; - } - } else if (description.isEmpty()) { - this->d->m_pipelineDescription.cleanAll(); - this->d->m_description = description; - } else { - for (auto &element: this->d->m_outputs) - QObject::disconnect(element.data(), - &AkElement::oStream, - this, - &BinElement::oStream); - - this->d->m_pipelineDescription.cleanAll(); - this->d->m_pipelineDescription.parse(description); - QString error = this->d->m_pipelineDescription.error(); - - if (error.isEmpty()) { - this->d->m_description = description; - this->d->m_elements = this->d->m_pipelineDescription.elements(); - this->d->m_inputs = this->d->m_pipelineDescription.inputs(); - this->d->m_outputs = this->d->m_pipelineDescription.outputs(); - this->connectOutputs(); - } else { - this->d->m_pipelineDescription.cleanAll(); - this->d->m_description = ""; - - qDebug() << error; - } - } - - this->setState(preState); - emit this->descriptionChanged(description); -} - -void BinElement::setBlocking(bool blocking) -{ - if (this->d->m_blocking == blocking) - return; - - this->d->m_blocking = blocking; - emit this->blockingChanged(blocking); -} - -void BinElement::resetDescription() -{ - this->setDescription(""); -} - -void BinElement::resetBlocking() -{ - this->setBlocking(false); -} - -AkPacket BinElement::iStream(const AkPacket &packet) -{ - if (!this->d->m_description.isEmpty()) - for (auto &element: this->d->m_inputs) - element->iStream(packet); - else if (!this->d->m_blocking) - akSend(packet) - - return AkPacket(); -} - -bool BinElement::setState(AkElement::ElementState state) -{ - AkElement::setState(state); - bool ok = true; - - for (auto &element: this->d->m_elements) { - bool ret = false; - QMetaObject::invokeMethod(element.data(), - "setState", - Q_RETURN_ARG(bool, ret), - Q_ARG(AkElement::ElementState, - this->state())); - ok &= ret; - } - - return ok; -} - -void BinElement::connectOutputs() -{ - auto connectionTypes = - this->d->m_pipelineDescription.outputConnectionTypes(); - int i = 0; - - for (auto &element: this->d->m_outputs) { - QObject::connect(element.data(), - SIGNAL(oStream(const AkPacket &)), - this, - SIGNAL(oStream(const AkPacket &)), - connectionTypes[i]); - - i++; - } -} - -void BinElement::disconnectOutputs() -{ - for (auto &element: this->d->m_outputs) - QObject::disconnect(element.data(), - &AkElement::oStream, - this, - &BinElement::oStream); -} - -#include "moc_binelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/binelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/binelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/binelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/binelement.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef BINELEMENT_H -#define BINELEMENT_H - -#include - -class BinElementPrivate; - -class BinElement: public AkElement -{ - Q_OBJECT - Q_PROPERTY(QString description - READ description - WRITE setDescription - RESET resetDescription - NOTIFY descriptionChanged) - Q_PROPERTY(bool blocking - READ blocking - WRITE setBlocking - RESET resetBlocking - NOTIFY blockingChanged) - - public: - BinElement(); - ~BinElement(); - - Q_INVOKABLE QString description() const; - Q_INVOKABLE bool blocking() const; - Q_INVOKABLE AkElementPtr element(const QString &elementName); - Q_INVOKABLE void add(const AkElementPtr &element); - Q_INVOKABLE void remove(const QString &elementName); - - private: - BinElementPrivate *d; - - signals: - void descriptionChanged(const QString &description); - void blockingChanged(bool blocking); - - public slots: - void setDescription(const QString &description); - void setBlocking(bool blocking); - void resetDescription(); - void resetBlocking(); - - AkPacket iStream(const AkPacket &packet); - bool setState(AkElement::ElementState state); - - private slots: - void connectOutputs(); - void disconnectOutputs(); -}; - -#endif // BINELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/bin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/bin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/bin.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/bin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef BIN_H -#define BIN_H - -#include - -class Bin: public QObject, public AkPlugin -{ - Q_OBJECT - Q_INTERFACES(AkPlugin) - Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") - - public: - QObject *create(const QString &key, const QString &specification); - QStringList keys() const; -}; - -#endif // BIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/pipeline.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/pipeline.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/pipeline.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/pipeline.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,929 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pipeline.h" - -class PipelinePrivate -{ - public: - QMap m_elements; - QList m_links; - QList m_connections; - QVariantMap m_properties; - QString m_error; - - QMetaMethod methodByName(QObject *object, - const QString &methodName, - QMetaMethod::MethodType methodType); - QVariant solveProperty(const QVariant &property) const; -}; - -Pipeline::Pipeline(QObject *parent): - QObject(parent) -{ - this->d = new PipelinePrivate; -} - -Pipeline::~Pipeline() -{ - delete this->d; -} - -bool Pipeline::parse(const QString &description) -{ - this->cleanAll(); - auto jsonFile = QJsonDocument::fromJson(description.toUtf8()); - - if (!jsonFile.isArray()) { - this->d->m_error = - "Error: This is not a parseable input, " - "must be an array of arrays."; - - return false; - } - - // Parse main array. - for (auto pipe: jsonFile.array()) { - if (pipe.isArray()) { - auto pipeArray = pipe.toArray(); - QStringList pipeStr; - - // parse a pipe. - for (int element = 0; element < pipeArray.size(); element++) - if (pipeArray[element].isObject()) { - auto elementObject = pipeArray[element].toObject(); - - if (elementObject.contains("pluginId")) { - if (!elementObject["pluginId"].isString()) { - QString error; - QDebug debug(&error); - - debug.nospace() << "Error: 'pluginId' must be a " - "string: " - << elementObject["alias"]; - - this->d->m_error = error; - - return false; - } - - auto element = AkElement::create(elementObject["pluginId"].toString()); - - if (!element) { - this->d->m_error = - QString("Error: Element '%1' doesn't exist.") - .arg(elementObject["pluginId"].toString()); - - return false; - } - - if (elementObject.contains("properties")) { - if (!elementObject["properties"].isObject()) { - QString error; - QDebug debug(&error); - - debug.nospace() << "Error: 'properties' must " - "be an object: " - << elementObject["properties"]; - - this->d->m_error = error; - - return false; - } - - auto properties = elementObject["properties"] - .toObject() - .toVariantMap(); - - for (auto it = properties.begin(); - it != properties.end(); - it++) - element->setProperty(it.key().toStdString().c_str(), - this->d->solveProperty(it.value())); - } - - auto objectName = this->addElement(element); - - if (elementObject.contains("connections")) { - if (!elementObject["connections"].isArray()) { - QString error; - QDebug debug(&error); - - debug.nospace() << "Error: 'connections' must " - "be an array of arrays: " - << elementObject["connections"]; - - this->d->m_error = error; - - return false; - } - - auto connections = elementObject["connections"] - .toArray() - .toVariantList(); - - for (auto &connection: connections) { - auto connectionStr = connection.toStringList(); - - if (connectionStr.size() != 4) { - QString error; - QDebug debug(&error); - - debug.nospace() << "Error: A connection must " - "contains four strings: " - << connection; - - this->d->m_error = error; - - return false; - } - - for (int i = 0; i < connectionStr.size(); i++) - if (connectionStr[i] == "") - connectionStr[i] = objectName; - - this->d->m_connections.append(connectionStr); - } - } - - pipeStr << objectName; - } - else if (elementObject.contains("alias")) { - if (!elementObject["alias"].isString()) { - QString error; - QDebug debug(&error); - - debug.nospace() << "Error: 'alias' must be a " - "string: " - << elementObject["alias"]; - - this->d->m_error = error; - - return false; - } - - auto ref = elementObject["alias"].toString(); - - if (ref == "IN") { - if (element != 0) { - this->d->m_error = - "Error: 'IN' alias must be at " - "the start of a pipe."; - - return false; - } - - pipeStr << ref + "."; - } else if (ref == "OUT") { - if (element != pipeArray.size() - 1) { - this->d->m_error = - "Error: 'OUT' alias must be " - "at the end of a pipe."; - - return false; - } - - pipeStr << ref + "."; - } else - pipeStr << ref; - } else { - QString error; - QDebug debug(&error); - - debug.nospace() << "Error: Malformed element, " - "must contain 'pluginId' or " - "'alias' key: " << elementObject; - - this->d->m_error = error; - - return false; - } - } else if (pipeArray[element].isString()) { - auto connectionType = pipeArray[element].toString(); - - if (element == pipeArray.size() - 1) { - this->d->m_error = - QString("Error: Connection type to nothing: %1") - .arg(connectionType); - - return false; - } - - pipeStr << connectionType + "?"; - } else { - this->d->m_error = - QString("Error: Must be an object or a" - " connection type: %1") - .arg(pipeArray[element].toString()); - - return false; - } - - this->addLinks(pipeStr); - } else { - this->d->m_error = - "Error: An pipe must be constructed as an array of objects."; - - return false; - } - } - - if (this->linkAll()) { - if (this->connectAll()) - return true; - - this->d->m_error = "Error connecting signals and slots."; - - return false; - } - - this->d->m_error = "Error linking pipeline."; - - return false; -} - -QMap Pipeline::elements() const -{ - return this->d->m_elements; -} - -QList Pipeline::links() const -{ - return this->d->m_links; -} - -QList Pipeline::connections() const -{ - return this->d->m_connections; -} - -QVariantMap Pipeline::properties() const -{ - return this->d->m_properties; -} - -QString Pipeline::error() const -{ - return this->d->m_error; -} - -QString Pipeline::addElement(const AkElementPtr &element) -{ - QString name; - - if (element->objectName().isEmpty()) - name = QString("&%1").arg(quint64(element.data())); - else - name = element->objectName(); - - this->d->m_elements[name] = element; - - return name; -} - -void Pipeline::removeElement(const QString &elementName) -{ - auto connections = this->d->m_connections; - - for (auto &connection: connections) - if (connection[0] == elementName - || connection[2] == elementName) { - auto sender = this->d->m_elements[connection[0]].data(); - auto receiver = this->d->m_elements[connection[2]].data(); - - auto signal = this->d->methodByName(sender, - connection[1], - QMetaMethod::Signal); - auto slot = this->d->methodByName(receiver, - connection[3], - QMetaMethod::Slot); - - QObject::disconnect(sender, signal, receiver, slot); - this->d->m_connections.removeOne(connection); - } - - auto links = this->d->m_links; - - for (auto &link: links) - if (link[0] == elementName - || link[1] == elementName) { - this->d->m_elements[link[0]]->unlink(this->d->m_elements[link[1]]); - this->d->m_links.removeOne(link); - } - - this->d->m_elements.remove(elementName); -} - -QList Pipeline::inputs() const -{ - QList inputs; - - for (auto &link: this->d->m_links) - if (link[0] == "IN.") - inputs << this->d->m_elements[link[1]]; - - return inputs; -} - -QList Pipeline::outputs() const -{ - QList outputs; - - for (auto &link: this->d->m_links) - if (link[1] == "OUT.") - outputs << this->d->m_elements[link[0]]; - - return outputs; -} - -QList Pipeline::outputConnectionTypes() const -{ - QList outputoutputConnectionTypes; - - int index = Pipeline::staticQtMetaObject.indexOfEnumerator("ConnectionType"); - auto enumerator = Pipeline::staticQtMetaObject.enumerator(index); - - for (auto &link: this->d->m_links) - if (link[1] == "OUT.") { - QString connectionTypeString; - - if (link.length() > 2) - connectionTypeString = link[2]; - else - connectionTypeString = "AutoConnection"; - - int value = enumerator.keyToValue(connectionTypeString.toStdString().c_str()); - - Qt::ConnectionType connectionType; - - if (value < 0) - connectionType = Qt::AutoConnection; - else - connectionType = static_cast(value); - - outputoutputConnectionTypes << connectionType; - } - - return outputoutputConnectionTypes; -} - -QMetaMethod PipelinePrivate::methodByName(QObject *object, - const QString &methodName, - QMetaMethod::MethodType methodType) -{ - QMetaMethod rMethod; - - for (int i = 0; i < object->metaObject()->methodCount(); i++) { - QMetaMethod method = object->metaObject()->method(i); - QString name(method.name()); - - if (method.methodType() == methodType - && name == methodName) { - rMethod = method; - - break; - } - } - - return rMethod; -} - -QVariant PipelinePrivate::solveProperty(const QVariant &property) const -{ - if (property.type() != QVariant::List) - return property; - - auto propList = property.toList(); - - if (propList.isEmpty()) - return QVariant(QVariantList()); - - auto type = propList[0].toString(); - - if (type.isEmpty()) { - QVariantList list; - - for (int i = 1; i < propList.size(); i++) - list << this->solveProperty(propList[i]); - - return QVariant(list); - } - - if (type == "frac") { - if (propList.size() < 3) - return QVariant::fromValue(AkFrac()); - - return QVariant::fromValue(AkFrac(qint64(propList[1].toDouble()), - qint64(propList[2].toDouble()))); - } - - if (type == "size") { - if (propList.size() < 3) - return QVariant::fromValue(QSize()); - - return QVariant::fromValue(QSize(int(propList[1].toDouble()), - int(propList[2].toDouble()))); - } - - if (type == "sizeF") { - if (propList.size() < 3) - return QVariant::fromValue(QSizeF()); - - return QVariant::fromValue(QSizeF(propList[1].toDouble(), - propList[2].toDouble())); - } - - if (type == "point") { - if (propList.size() < 3) - return QVariant::fromValue(QPoint()); - - return QVariant::fromValue(QPoint(int(propList[1].toDouble()), - int(propList[2].toDouble()))); - } - - if (type == "pointF") { - if (propList.size() < 3) - return QVariant::fromValue(QPointF()); - - return QVariant::fromValue(QPointF(propList[1].toDouble(), - propList[2].toDouble())); - } - - if (type == "rect") { - if (propList.size() < 3) - return QVariant::fromValue(QRect()); - - if (propList.size() == 3) { - QVariant arg1 = this->solveProperty(propList[1]); - - if (arg1.type() != QVariant::Point) - return QVariant::fromValue(QRect()); - - QVariant arg2 = this->solveProperty(propList[2]); - - if (arg2.type() == QVariant::Point) - return QVariant::fromValue(QRect(arg1.toPoint(), - arg2.toPoint())); - - if (arg2.type() == QVariant::Size) - return QVariant::fromValue(QRect(arg1.toPoint(), - arg2.toSize())); - - return QVariant::fromValue(QRect()); - } - - if (propList.size() > 4) - return QVariant::fromValue(QRect(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()), - int(propList[4].toDouble()))); - - return QVariant::fromValue(QRect()); - } - - if (type == "rectF") { - if (propList.size() < 3) - return QVariant::fromValue(QRectF()); - - if (propList.size() == 3) { - QVariant arg1 = this->solveProperty(propList[1]); - - if (arg1.type() != QVariant::PointF) - return QVariant::fromValue(QRectF()); - - QVariant arg2 = this->solveProperty(propList[2]); - - if (arg2.type() == QVariant::PointF) - return QVariant::fromValue(QRectF(arg1.toPointF(), - arg2.toPointF())); - - if (arg2.type() == QVariant::SizeF) - return QVariant::fromValue(QRectF(arg1.toPointF(), - arg2.toSizeF())); - - return QVariant::fromValue(QRectF()); - } - - if (propList.size() > 4) - return QVariant::fromValue(QRectF(propList[1].toDouble(), - propList[2].toDouble(), - propList[3].toDouble(), - propList[4].toDouble())); - - return QVariant::fromValue(QRectF()); - } - - if (type == "line") { - if (propList.size() < 3) - return QVariant::fromValue(QLine()); - - if (propList.size() == 3) { - QVariant arg1 = this->solveProperty(propList[1]); - - if (arg1.type() != QVariant::Point) - return QVariant::fromValue(QLine()); - - QVariant arg2 = this->solveProperty(propList[2]); - - if (arg2.type() == QVariant::Point) - return QVariant::fromValue(QLine(arg1.toPoint(), - arg2.toPoint())); - - return QVariant::fromValue(QLine()); - } - - if (propList.size() > 4) - return QVariant::fromValue(QLine(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()), - int(propList[4].toDouble()))); - - return QVariant::fromValue(QLine()); - } - - if (type == "lineF") { - if (propList.size() < 3) - return QVariant::fromValue(QLineF()); - - if (propList.size() == 3) { - QVariant arg1 = this->solveProperty(propList[1]); - - if (arg1.type() != QVariant::PointF) - return QVariant::fromValue(QLineF()); - - QVariant arg2 = this->solveProperty(propList[2]); - - if (arg2.type() == QVariant::PointF) - return QVariant::fromValue(QLineF(arg1.toPointF(), - arg2.toPointF())); - - return QVariant::fromValue(QLineF()); - } - - if (propList.size() > 4) - return QVariant::fromValue(QLineF(propList[1].toDouble(), - propList[2].toDouble(), - propList[3].toDouble(), - propList[4].toDouble())); - - return QVariant::fromValue(QLineF()); - } - - if (type == "date") { - if (propList.size() < 4) - return QVariant::fromValue(QDate()); - - return QVariant::fromValue(QDate(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()))); - } - - if (type == "time") { - if (propList.size() < 3) - return QVariant::fromValue(QTime()); - - if (propList.size() == 3) - return QVariant::fromValue(QTime(int(propList[1].toDouble()), - int(propList[2].toDouble()))); - - if (propList.size() == 4) - return QVariant::fromValue(QTime(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()))); - - if (propList.size() > 4) - return QVariant::fromValue(QTime(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()), - int(propList[4].toDouble()))); - - return QVariant::fromValue(QTime()); - } - - if (type == "dateTime") { - if (propList.size() < 2) - return QVariant::fromValue(QDateTime()); - - QVariant arg1 = this->solveProperty(propList[1]); - - if (propList.size() == 2) - return QVariant::fromValue(QDateTime(arg1.toDate())); - - QVariant arg2 = this->solveProperty(propList[2]); - - return QVariant::fromValue(QDateTime(arg1.toDate(), - arg2.toTime())); - } - - if (type == "rgb") { - if (propList.size() < 2) - return QVariant::fromValue(qRgba(0, 0, 0, 0)); - - if (propList.size() == 2) - return QVariant::fromValue(QColor(propList[1].toString()).rgba()); - - if (propList.size() == 4) - return QVariant::fromValue(qRgb(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()))); - - if (propList.size() > 4) - return QVariant::fromValue(qRgba(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()), - int(propList[4].toDouble()))); - - return QVariant::fromValue(qRgba(0, 0, 0, 0)); - } - - if (type == "color") { - if (propList.size() < 2) - return QVariant::fromValue(QColor()); - - if (propList.size() == 2) - return QVariant::fromValue(QColor(propList[1].toString())); - - if (propList.size() == 4) - return QVariant::fromValue(QColor(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()))); - - if (propList.size() > 4) - return QVariant::fromValue(QColor(int(propList[1].toDouble()), - int(propList[2].toDouble()), - int(propList[3].toDouble()), - int(propList[4].toDouble()))); - - return QVariant::fromValue(QColor()); - } - - if (type == "bits") { - if (propList.size() < 2) - return QVariant::fromValue(QBitArray()); - - QString bitsString = propList[1].toString(); - QBitArray bits; - - bitsString.replace(QRegExp("\\s+"), ""); - - if (bitsString.length() > 0) { - bits.resize(bitsString.length()); - - for (int i = 0; i < bitsString.length(); i++) - bits.setBit(i, bitsString[i] != '0'); - } - - return QVariant::fromValue(bits); - } - - if (type == "bytes") - return QVariant::fromValue(propList[1].toByteArray()); - - if (type == "url") - return QVariant::fromValue(propList[1].toUrl()); - - return QVariant(QVariantList()); -} - -void Pipeline::addLinks(const QStringList &links) -{ - QStringList link; - QString connectionType = "AutoConnection"; - - for (auto element: links) { - if (element.endsWith("?")) - connectionType = element.remove("?"); - else - link << element; - - if (link.length() == 2) { - link << connectionType; - this->d->m_links << link; - link.removeFirst(); - link.removeLast(); - } - } -} - -bool Pipeline::linkAll() -{ - for (auto &link: this->d->m_links) - if (link[0] != "IN." && link[1] != "OUT.") { - if (!this->d->m_elements.contains(link[0])) { - this->d->m_error = - QString("No element named '%1'").arg(link[0]); - - return false; - } - - if (!this->d->m_elements.contains(link[1])) { - this->d->m_error = - QString("No element named '%1'").arg(link[1]); - - return false; - } - - QString connectionTypeString; - - if (link.length() > 2) - connectionTypeString = link[2]; - else - connectionTypeString = "AutoConnection"; - - int index = Pipeline::staticQtMetaObject.indexOfEnumerator("ConnectionType"); - auto enumerator = Pipeline::staticQtMetaObject.enumerator(index); - - int value = enumerator.keyToValue(connectionTypeString.toStdString().c_str()); - - if (value < 0) { - this->d->m_error = - QString("Invalid connection type: '%1'") - .arg(connectionTypeString); - - return false; - } - - auto connectionType = static_cast(value); - - this->d->m_elements[link[0]]->link(this->d->m_elements[link[1]], - connectionType); - } - - return true; -} - -bool Pipeline::unlinkAll() -{ - for (auto &link: this->d->m_links) - if (link[0] != "IN." - && link[1] != "OUT.") { - if (!this->d->m_elements.contains(link[0])) { - this->d->m_error = - QString("No element named '%1'").arg(link[0]); - - return false; - } - - if (!this->d->m_elements.contains(link[1])) { - this->d->m_error = - QString("No element named '%1'").arg(link[1]); - - return false; - } - - this->d->m_elements[link[0]]->unlink(this->d->m_elements[link[1]]); - } - - return true; -} - -bool Pipeline::connectAll() -{ - for (auto &connection: this->d->m_connections) { - auto sender = this->d->m_elements[connection[0]].data(); - auto receiver = this->d->m_elements[connection[2]].data(); - - if (!sender) { - this->d->m_error = - QString("No element named '%1'").arg(connection[0]); - - return false; - } - - if (!receiver) { - this->d->m_error = QString("No element named '%1'").arg(connection[2]); - - return false; - } - - auto signal = this->d->methodByName(sender, - connection[1], - QMetaMethod::Signal); - auto slot = this->d->methodByName(receiver, - connection[3], - QMetaMethod::Slot); - - QObject::connect(sender, signal, receiver, slot); - } - - return true; -} - -bool Pipeline::disconnectAll() -{ - for (auto &connection: this->d->m_connections) { - auto sender = this->d->m_elements[connection[0]].data(); - auto receiver = this->d->m_elements[connection[2]].data(); - - if (!sender) { - this->d->m_error = - QString("No element named '%1'.").arg(connection[0]); - - return false; - } - - if (!receiver) { - this->d->m_error = - QString("No element named '%1'.").arg(connection[2]); - - return false; - } - - auto signal = this->d->methodByName(sender, - connection[1], - QMetaMethod::Signal); - auto slot = this->d->methodByName(receiver, - connection[3], - QMetaMethod::Slot); - - QObject::disconnect(sender, signal, receiver, slot); - } - - return true; -} - -void Pipeline::cleanAll() -{ - this->unlinkAll(); - this->disconnectAll(); - this->resetElements(); - this->resetLinks(); - this->d->m_connections.clear(); - this->resetProperties(); - this->resetError(); -} - -void Pipeline::setElements(const QMap &elements) -{ - this->d->m_elements = elements; -} - -void Pipeline::setLinks(const QList &links) -{ - this->d->m_links = links; -} - -void Pipeline::setProperties(const QVariantMap &properties) -{ - this->d->m_properties = properties; -} - -void Pipeline::setError(const QString &error) -{ - this->d->m_error = error; -} - -void Pipeline::resetElements() -{ - this->setElements({}); -} - -void Pipeline::resetLinks() -{ - this->setLinks({}); -} - -void Pipeline::resetProperties() -{ - this->setProperties({}); -} - -void Pipeline::resetError() -{ - this->setError({}); -} - -#include "moc_pipeline.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/pipeline.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/pipeline.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Bin/src/pipeline.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Bin/src/pipeline.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef PIPELINE_H -#define PIPELINE_H - -#include - -typedef QMap ElementMap; -class PipelinePrivate; - -class Pipeline: public QObject -{ - Q_OBJECT - - Q_PROPERTY(ElementMap elements - READ elements - WRITE setElements - RESET resetElements) - Q_PROPERTY(QList links - READ links - WRITE setLinks - RESET resetLinks) - Q_PROPERTY(QList connections - READ connections) - Q_PROPERTY(QVariantMap properties - READ properties - WRITE setProperties - RESET resetProperties) - Q_PROPERTY(QString error - READ error - WRITE setError - RESET resetError) - Q_PROPERTY(QList inputs - READ inputs) - Q_PROPERTY(QList outputs - READ outputs) - - public: - Pipeline(QObject *parent=nullptr); - ~Pipeline(); - - Q_INVOKABLE bool parse(const QString &description); - Q_INVOKABLE QMap elements() const; - Q_INVOKABLE QList links() const; - Q_INVOKABLE QList connections() const; - Q_INVOKABLE QVariantMap properties() const; - Q_INVOKABLE QString error() const; - Q_INVOKABLE QString addElement(const AkElementPtr &element); - Q_INVOKABLE void removeElement(const QString &elementName); - Q_INVOKABLE QList inputs() const; - Q_INVOKABLE QList outputs() const; - Q_INVOKABLE QList outputConnectionTypes() const; - Q_INVOKABLE bool linkAll(); - Q_INVOKABLE bool unlinkAll(); - Q_INVOKABLE bool connectAll(); - Q_INVOKABLE bool disconnectAll(); - - private: - PipelinePrivate *d; - - public slots: - void addLinks(const QStringList &links); - void cleanAll(); - void setElements(const QMap &elements); - void setLinks(const QList &links); - void setProperties(const QVariantMap &properties); - void setError(const QString &error); - void resetElements(); - void resetLinks(); - void resetProperties(); - void resetError(); -}; - -#endif // PIPELINE_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Blur/src/blurelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Blur/src/blurelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Blur/src/blurelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Blur/src/blurelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include "blurelement.h" @@ -95,24 +96,9 @@ context->setContextProperty("controlId", this->objectName()); } -void BlurElement::setRadius(int radius) -{ - if (this->d->m_radius == radius) - return; - - this->d->m_radius = radius; - emit this->radiusChanged(radius); -} - -void BlurElement::resetRadius() -{ - this->setRadius(5); -} - -AkPacket BlurElement::iStream(const AkPacket &packet) +AkPacket BlurElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -145,8 +131,22 @@ delete [] integral; - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void BlurElement::setRadius(int radius) +{ + if (this->d->m_radius == radius) + return; + + this->d->m_radius = radius; + emit this->radiusChanged(radius); +} + +void BlurElement::resetRadius() +{ + this->setRadius(5); +} + #include "moc_blurelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Blur/src/blurelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Blur/src/blurelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Blur/src/blurelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Blur/src/blurelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void radiusChanged(int radius); @@ -53,7 +54,6 @@ public slots: void setRadius(int radius); void resetRadius(); - AkPacket iStream(const AkPacket &packet); }; #endif // BLURELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Blur/src/pixel.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Blur/src/pixel.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Blur/src/pixel.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Blur/src/pixel.h 2021-02-15 15:25:23.000000000 +0000 @@ -98,7 +98,7 @@ return *p0 + *p3 - *p1 - *p2; } -typedef Pixel PixelU32; -typedef Pixel PixelReal; +using PixelU32 = Pixel; +using PixelReal = Pixel; #endif // INTEGRAL_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Cartoon/src/cartoonelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Cartoon/src/cartoonelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Cartoon/src/cartoonelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Cartoon/src/cartoonelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "cartoonelement.h" @@ -320,6 +321,60 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket CartoonElement::iVideoStream(const AkVideoPacket &packet) +{ + this->d->m_mutex.lock(); + QSize scanSize(this->d->m_scanSize); + this->d->m_mutex.unlock(); + + if (scanSize.isEmpty()) + akSend(packet) + + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + if (this->d->m_id != packet.id()) { + this->d->m_id = packet.id(); + this->d->m_palette.clear(); + this->d->m_lastTime = QDateTime::currentMSecsSinceEpoch(); + } + + // Palettize image. + QVector palette = + this->d->palette(src.scaled(scanSize, Qt::KeepAspectRatio), + this->d->m_ncolors, + this->d->m_colorDiff); + + for (int y = 0; y < src.height(); y++) { + const QRgb *srcLine = reinterpret_cast(src.constScanLine(y)); + QRgb *dstLine = reinterpret_cast(oFrame.scanLine(y)); + + for (int x = 0; x < src.width(); x++) + dstLine[x] = palette[this->d->rgb24Torgb16(srcLine[x])]; + } + + // Draw the edges. + if (this->d->m_showEdges) { + QPainter painter; + painter.begin(&oFrame); + QImage edges = + this->d->edges(src, + this->d->m_thresholdLow, + this->d->m_thresholdHi, + this->d->m_lineColor); + painter.drawImage(0, 0, edges); + painter.end(); + } + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void CartoonElement::setNColors(int ncolors) { if (this->d->m_ncolors == ncolors) @@ -420,59 +475,4 @@ this->setScanSize(QSize(320, 240)); } -AkPacket CartoonElement::iStream(const AkPacket &packet) -{ - this->d->m_mutex.lock(); - QSize scanSize(this->d->m_scanSize); - this->d->m_mutex.unlock(); - - if (scanSize.isEmpty()) - akSend(packet) - - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - if (this->d->m_id != packet.id()) { - this->d->m_id = packet.id(); - this->d->m_palette.clear(); - this->d->m_lastTime = QDateTime::currentMSecsSinceEpoch(); - } - - // Palettize image. - QVector palette = - this->d->palette(src.scaled(scanSize, Qt::KeepAspectRatio), - this->d->m_ncolors, - this->d->m_colorDiff); - - for (int y = 0; y < src.height(); y++) { - const QRgb *srcLine = reinterpret_cast(src.constScanLine(y)); - QRgb *dstLine = reinterpret_cast(oFrame.scanLine(y)); - - for (int x = 0; x < src.width(); x++) - dstLine[x] = palette[this->d->rgb24Torgb16(srcLine[x])]; - } - - // Draw the edges. - if (this->d->m_showEdges) { - QPainter painter; - painter.begin(&oFrame); - QImage edges = - this->d->edges(src, - this->d->m_thresholdLow, - this->d->m_thresholdHi, - this->d->m_lineColor); - painter.drawImage(0, 0, edges); - painter.end(); - } - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_cartoonelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Cartoon/src/cartoonelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Cartoon/src/cartoonelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Cartoon/src/cartoonelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Cartoon/src/cartoonelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -83,6 +83,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void ncolorsChanged(int ncolors); @@ -108,7 +109,6 @@ void resetThresholdHi(); void resetLineColor(); void resetScanSize(); - AkPacket iStream(const AkPacket &packet); }; #endif // CARTOONELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ChangeHSL/src/changehslelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ChangeHSL/src/changehslelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ChangeHSL/src/changehslelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ChangeHSL/src/changehslelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "changehslelement.h" @@ -72,38 +73,12 @@ context->setContextProperty("controlId", this->objectName()); } -void ChangeHSLElement::setKernel(const QVariantList &kernel) -{ - QVector k; - - for (const QVariant &e: kernel) - k << e.toReal(); - - if (this->d->m_kernel == k) - return; - - this->d->m_kernel = k; - emit this->kernelChanged(kernel); -} - -void ChangeHSLElement::resetKernel() -{ - static const QVariantList kernel = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0 - }; - - this->setKernel(kernel); -} - -AkPacket ChangeHSLElement::iStream(const AkPacket &packet) +AkPacket ChangeHSLElement::iVideoStream(const AkVideoPacket &packet) { if (this->d->m_kernel.size() < 12) akSend(packet) - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -139,8 +114,33 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void ChangeHSLElement::setKernel(const QVariantList &kernel) +{ + QVector k; + + for (const QVariant &e: kernel) + k << e.toReal(); + + if (this->d->m_kernel == k) + return; + + this->d->m_kernel = k; + emit this->kernelChanged(kernel); +} + +void ChangeHSLElement::resetKernel() +{ + static const QVariantList kernel = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0 + }; + + this->setKernel(kernel); +} + #include "moc_changehslelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ChangeHSL/src/changehslelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ChangeHSL/src/changehslelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ChangeHSL/src/changehslelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ChangeHSL/src/changehslelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void kernelChanged(const QVariantList &kernel); @@ -53,7 +54,6 @@ public slots: void setKernel(const QVariantList &kernel); void resetKernel(); - AkPacket iStream(const AkPacket &packet); }; #endif // CHANGEHSLELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/Charify.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/Charify.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/Charify.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/Charify.pro 2021-02-15 15:25:23.000000000 +0000 @@ -52,7 +52,8 @@ SOURCES = \ src/charify.cpp \ - src/charifyelement.cpp + src/charifyelement.cpp \ + src/character.cpp lupdate_only { SOURCES += $$files(share/qml/*.qml) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/src/character.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/src/character.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/src/character.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/src/character.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,97 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include + +#include "character.h" + +class CharacterPrivate +{ + public: + QChar chr; + QImage image; + int weight {0}; +}; + +Character::Character() +{ + this->d = new CharacterPrivate; +} + +Character::Character(const QChar &chr, const QImage &image, int weight) +{ + this->d = new CharacterPrivate; + this->d->chr = chr; + this->d->image = image; + this->d->weight = weight; +} + +Character::Character(const Character &other) +{ + this->d = new CharacterPrivate; + this->d->chr = other.d->chr; + this->d->image = other.d->image; + this->d->weight = other.d->weight; +} + +Character::~Character() +{ + delete this->d; +} + +Character &Character::operator =(const Character &other) +{ + if (this != &other) { + this->d->chr = other.d->chr; + this->d->image = other.d->image; + this->d->weight = other.d->weight; + } + + return *this; +} + +QChar &Character::chr() +{ + return this->d->chr; +} + +QChar Character::chr() const +{ + return this->d->chr; +} + +QImage &Character::image() +{ + return this->d->image; +} + +QImage Character::image() const +{ + return this->d->image; +} + +int &Character::weight() +{ + return this->d->weight; +} + +int Character::weight() const +{ + return this->d->weight; +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/src/character.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/src/character.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/src/character.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/src/character.h 2021-02-15 15:25:23.000000000 +0000 @@ -20,29 +20,28 @@ #ifndef CHARACTER_H #define CHARACTER_H -#include +class CharacterPrivate; +class QChar; +class QImage; class Character { public: - Character(): - weight(0) - { - } + Character(); + Character(const QChar &chr, const QImage &image, int weight); + Character(const Character &other); + ~Character(); + Character &operator =(const Character &other); + + QChar &chr(); + QChar chr() const; + QImage &image(); + QImage image() const; + int &weight(); + int weight() const; - Character(const QChar &chr, const QImage &image, int weight): - chr(chr), image(image), weight(weight) - { - } - - Character(const Character &other): - chr(other.chr), image(other.image), weight(other.weight) - { - } - - QChar chr; - QImage image; - int weight; + private: + CharacterPrivate *d; }; #endif // CHARACTER_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/src/charifyelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/src/charifyelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/src/charifyelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/src/charifyelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "charifyelement.h" @@ -216,6 +217,66 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket CharifyElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + + this->d->m_mutex.lock(); + QSize fontSize = this->d->m_fontSize; + QVector characters = this->d->m_characters; + this->d->m_mutex.unlock(); + + int textWidth = src.width() / fontSize.width(); + int textHeight = src.height() / fontSize.height(); + + int outWidth = textWidth * fontSize.width(); + int outHeight = textHeight * fontSize.height(); + + QImage oFrame(outWidth, outHeight, src.format()); + + if (characters.isEmpty()) { + oFrame.fill(qRgb(0, 0, 0)); + auto oPacket = AkVideoPacket::fromImage(oFrame.scaled(src.size()), + packet); + akSend(oPacket) + } + + QImage textImage = src.scaled(textWidth, textHeight); + const QRgb *textImageBits = reinterpret_cast(textImage.constBits()); + int textArea = textImage.width() * textImage.height(); + QPainter painter; + + painter.begin(&oFrame); + + for (int i = 0; i < textArea; i++) { + int x = fontSize.width() * (i % textWidth); + int y = fontSize.height() * (i / textWidth); + + if (this->d->m_mode == ColorModeFixed) + painter.drawImage(x, y, characters[qGray(textImageBits[i])].image()); + else { + QChar chr = characters[qGray(textImageBits[i])].chr(); + QRgb foreground = textImageBits[i]; + auto image = this->d->drawChar(chr, + this->d->m_font, + fontSize, + foreground, + this->d->m_backgroundColor); + painter.drawImage(x, y, image); + } + } + + painter.end(); + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void CharifyElement::setMode(const QString &mode) { ColorMode modeEnum = colorModeToStr->key(mode, ColorModeNatural); @@ -352,67 +413,6 @@ this->setReversed(false); } -AkPacket CharifyElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - - this->d->m_mutex.lock(); - QSize fontSize = this->d->m_fontSize; - QVector characters = this->d->m_characters; - this->d->m_mutex.unlock(); - - int textWidth = src.width() / fontSize.width(); - int textHeight = src.height() / fontSize.height(); - - int outWidth = textWidth * fontSize.width(); - int outHeight = textHeight * fontSize.height(); - - QImage oFrame(outWidth, outHeight, src.format()); - - if (characters.isEmpty()) { - oFrame.fill(qRgb(0, 0, 0)); - auto oPacket = AkVideoPacket::fromImage(oFrame.scaled(src.size()), - videoPacket).toPacket(); - akSend(oPacket) - } - - QImage textImage = src.scaled(textWidth, textHeight); - const QRgb *textImageBits = reinterpret_cast(textImage.constBits()); - int textArea = textImage.width() * textImage.height(); - QPainter painter; - - painter.begin(&oFrame); - - for (int i = 0; i < textArea; i++) { - int x = fontSize.width() * (i % textWidth); - int y = fontSize.height() * (i / textWidth); - - if (this->d->m_mode == ColorModeFixed) - painter.drawImage(x, y, characters[qGray(textImageBits[i])].image); - else { - QChar chr = characters[qGray(textImageBits[i])].chr; - QRgb foreground = textImageBits[i]; - auto image = this->d->drawChar(chr, - this->d->m_font, - fontSize, - foreground, - this->d->m_backgroundColor); - painter.drawImage(x, y, image); - } - } - - painter.end(); - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - void CharifyElement::updateCharTable() { QList characters; @@ -451,7 +451,7 @@ std::sort(characters.begin(), characters.end(), [] (const Character &chr1, const Character &chr2) { - return chr1.weight < chr2.weight; + return chr1.weight() < chr2.weight(); }); for (int i = 0; i < 256; i++) { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/src/charifyelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/src/charifyelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Charify/src/charifyelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Charify/src/charifyelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -96,6 +96,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void modeChanged(const QString &mode); @@ -125,8 +126,6 @@ void resetBackgroundColor(); void resetReversed(); - AkPacket iStream(const AkPacket &packet); - private slots: void updateCharTable(); }; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Cinema/src/cinemaelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Cinema/src/cinemaelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Cinema/src/cinemaelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Cinema/src/cinemaelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "cinemaelement.h" @@ -67,38 +68,9 @@ context->setContextProperty("controlId", this->objectName()); } -void CinemaElement::setStripSize(qreal stripSize) -{ - if (qFuzzyCompare(this->d->m_stripSize, stripSize)) - return; - - this->d->m_stripSize = stripSize; - emit this->stripSizeChanged(stripSize); -} - -void CinemaElement::setStripColor(QRgb hideColor) -{ - if (this->d->m_stripColor == hideColor) - return; - - this->d->m_stripColor = hideColor; - emit this->stripColorChanged(hideColor); -} - -void CinemaElement::resetStripSize() -{ - this->setStripSize(0.5); -} - -void CinemaElement::resetStripColor() -{ - this->setStripColor(qRgb(0, 0, 0)); -} - -AkPacket CinemaElement::iStream(const AkPacket &packet) +AkPacket CinemaElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -126,8 +98,36 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void CinemaElement::setStripSize(qreal stripSize) +{ + if (qFuzzyCompare(this->d->m_stripSize, stripSize)) + return; + + this->d->m_stripSize = stripSize; + emit this->stripSizeChanged(stripSize); +} + +void CinemaElement::setStripColor(QRgb hideColor) +{ + if (this->d->m_stripColor == hideColor) + return; + + this->d->m_stripColor = hideColor; + emit this->stripColorChanged(hideColor); +} + +void CinemaElement::resetStripSize() +{ + this->setStripSize(0.5); +} + +void CinemaElement::resetStripColor() +{ + this->setStripColor(qRgb(0, 0, 0)); +} + #include "moc_cinemaelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Cinema/src/cinemaelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Cinema/src/cinemaelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Cinema/src/cinemaelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Cinema/src/cinemaelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -53,6 +53,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void stripSizeChanged(qreal stripSize); @@ -63,8 +64,6 @@ void setStripColor(QRgb stripColor); void resetStripSize(); void resetStripColor(); - - AkPacket iStream(const AkPacket &packet); }; #endif // CINEMAELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorFilter/src/colorfilterelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorFilter/src/colorfilterelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorFilter/src/colorfilterelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorFilter/src/colorfilterelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "colorfilterelement.h" @@ -79,6 +80,62 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket ColorFilterElement::iVideoStream(const AkVideoPacket &packet) +{ + if (this->d->m_disable) + akSend(packet) + + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + for (int y = 0; y < src.height(); y++) { + auto srcLine = reinterpret_cast(src.constScanLine(y)); + auto dstLine = reinterpret_cast(oFrame.scanLine(y)); + + for (int x = 0; x < src.width(); x++) { + int r = qRed(srcLine[x]); + int g = qGreen(srcLine[x]); + int b = qBlue(srcLine[x]); + + int rf = qRed(this->d->m_color); + int gf = qGreen(this->d->m_color); + int bf = qBlue(this->d->m_color); + + int rd = r - rf; + int gd = g - gf; + int bd = b - bf; + + qreal k = sqrt(rd * rd + gd * gd + bd * bd); + + if (k <= this->d->m_radius) { + if (this->d->m_soft) { + qreal p = k / this->d->m_radius; + + int gray = qGray(srcLine[x]); + + r = int(p * (gray - r) + r); + g = int(p * (gray - g) + g); + b = int(p * (gray - b) + b); + + dstLine[x] = qRgba(r, g, b, qAlpha(srcLine[x])); + } else + dstLine[x] = srcLine[x]; + } else { + int gray = qGray(srcLine[x]); + dstLine[x] = qRgba(gray, gray, gray, qAlpha(srcLine[x])); + } + } + } + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void ColorFilterElement::setColor(QRgb color) { if (this->d->m_color == color) @@ -135,61 +192,4 @@ this->setDisable(false); } -AkPacket ColorFilterElement::iStream(const AkPacket &packet) -{ - if (this->d->m_disable) - akSend(packet) - - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - for (int y = 0; y < src.height(); y++) { - auto srcLine = reinterpret_cast(src.constScanLine(y)); - auto dstLine = reinterpret_cast(oFrame.scanLine(y)); - - for (int x = 0; x < src.width(); x++) { - int r = qRed(srcLine[x]); - int g = qGreen(srcLine[x]); - int b = qBlue(srcLine[x]); - - int rf = qRed(this->d->m_color); - int gf = qGreen(this->d->m_color); - int bf = qBlue(this->d->m_color); - - int rd = r - rf; - int gd = g - gf; - int bd = b - bf; - - qreal k = sqrt(rd * rd + gd * gd + bd * bd); - - if (k <= this->d->m_radius) { - if (this->d->m_soft) { - qreal p = k / this->d->m_radius; - - int gray = qGray(srcLine[x]); - - r = int(p * (gray - r) + r); - g = int(p * (gray - g) + g); - b = int(p * (gray - b) + b); - - dstLine[x] = qRgba(r, g, b, qAlpha(srcLine[x])); - } else - dstLine[x] = srcLine[x]; - } else { - int gray = qGray(srcLine[x]); - dstLine[x] = qRgba(gray, gray, gray, qAlpha(srcLine[x])); - } - } - } - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_colorfilterelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorFilter/src/colorfilterelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorFilter/src/colorfilterelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorFilter/src/colorfilterelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorFilter/src/colorfilterelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -65,6 +65,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void colorChanged(QRgb color); @@ -81,7 +82,6 @@ void resetRadius(); void resetSoft(); void resetDisable(); - AkPacket iStream(const AkPacket &packet); }; #endif // COLORFILTERELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorReplace/src/colorreplaceelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorReplace/src/colorreplaceelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorReplace/src/colorreplaceelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorReplace/src/colorreplaceelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "colorreplaceelement.h" @@ -79,6 +80,59 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket ColorReplaceElement::iVideoStream(const AkVideoPacket &packet) +{ + if (this->d->m_disable) + akSend(packet) + + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + for (int y = 0; y < src.height(); y++) { + const QRgb *srcLine = reinterpret_cast(src.constScanLine(y)); + QRgb *dstLine = reinterpret_cast(oFrame.scanLine(y)); + + for (int x = 0; x < src.width(); x++) { + int r = qRed(srcLine[x]); + int g = qGreen(srcLine[x]); + int b = qBlue(srcLine[x]); + + int rf = qRed(this->d->m_from); + int gf = qGreen(this->d->m_from); + int bf = qBlue(this->d->m_from); + + int rd = r - rf; + int gd = g - gf; + int bd = b - bf; + + qreal k = sqrt(rd * rd + gd * gd + bd * bd); + + if (k <= this->d->m_radius) { + qreal p = k / this->d->m_radius; + + int rt = qRed(this->d->m_to); + int gt = qGreen(this->d->m_to); + int bt = qBlue(this->d->m_to); + + r = int(p * (r - rt) + rt); + g = int(p * (g - gt) + gt); + b = int(p * (b - bt) + bt); + + dstLine[x] = qRgba(r, g, b, qAlpha(srcLine[x])); + } else + dstLine[x] = srcLine[x]; + } + } + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void ColorReplaceElement::setFrom(QRgb from) { if (this->d->m_from == from) @@ -135,58 +189,4 @@ this->setDisable(false); } -AkPacket ColorReplaceElement::iStream(const AkPacket &packet) -{ - if (this->d->m_disable) - akSend(packet) - - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - for (int y = 0; y < src.height(); y++) { - const QRgb *srcLine = reinterpret_cast(src.constScanLine(y)); - QRgb *dstLine = reinterpret_cast(oFrame.scanLine(y)); - - for (int x = 0; x < src.width(); x++) { - int r = qRed(srcLine[x]); - int g = qGreen(srcLine[x]); - int b = qBlue(srcLine[x]); - - int rf = qRed(this->d->m_from); - int gf = qGreen(this->d->m_from); - int bf = qBlue(this->d->m_from); - - int rd = r - rf; - int gd = g - gf; - int bd = b - bf; - - qreal k = sqrt(rd * rd + gd * gd + bd * bd); - - if (k <= this->d->m_radius) { - qreal p = k / this->d->m_radius; - - int rt = qRed(this->d->m_to); - int gt = qGreen(this->d->m_to); - int bt = qBlue(this->d->m_to); - - r = int(p * (r - rt) + rt); - g = int(p * (g - gt) + gt); - b = int(p * (b - bt) + bt); - - dstLine[x] = qRgba(r, g, b, qAlpha(srcLine[x])); - } else - dstLine[x] = srcLine[x]; - } - } - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_colorreplaceelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorReplace/src/colorreplaceelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorReplace/src/colorreplaceelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorReplace/src/colorreplaceelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorReplace/src/colorreplaceelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -65,6 +65,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void fromChanged(QRgb from); @@ -81,7 +82,6 @@ void resetTo(); void resetRadius(); void resetDisable(); - AkPacket iStream(const AkPacket &packet); }; #endif // COLORREPLACEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorTap/src/colortapelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorTap/src/colortapelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorTap/src/colortapelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorTap/src/colortapelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "colortapelement.h" @@ -69,39 +70,7 @@ context->setContextProperty("picturesPath", picturesPath[0]); } -void ColorTapElement::setTable(const QString &table) -{ - if (this->d->m_tableName == table) - return; - - QString tableName; - QImage tableImg; - - if (!table.isEmpty()) { - tableImg = QImage(table); - - if (tableImg.isNull()) { - if (this->d->m_tableName.isNull()) - return; - } else { - tableName = table; - tableImg = tableImg.scaled(16, 16); - } - } - - this->d->m_tableName = tableName; - this->d->m_mutex.lock(); - this->d->m_table = tableImg; - this->d->m_mutex.unlock(); - emit this->tableChanged(this->d->m_tableName); -} - -void ColorTapElement::resetTable() -{ - this->setTable(":/ColorTap/share/tables/base.bmp"); -} - -AkPacket ColorTapElement::iStream(const AkPacket &packet) +AkPacket ColorTapElement::iVideoStream(const AkVideoPacket &packet) { this->d->m_mutex.lock(); @@ -110,8 +79,7 @@ akSend(packet) } - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) { this->d->m_mutex.unlock(); @@ -142,8 +110,40 @@ this->d->m_mutex.unlock(); - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void ColorTapElement::setTable(const QString &table) +{ + if (this->d->m_tableName == table) + return; + + QString tableName; + QImage tableImg; + + if (!table.isEmpty()) { + tableImg = QImage(table); + + if (tableImg.isNull()) { + if (this->d->m_tableName.isNull()) + return; + } else { + tableName = table; + tableImg = tableImg.scaled(16, 16); + } + } + + this->d->m_tableName = tableName; + this->d->m_mutex.lock(); + this->d->m_table = tableImg; + this->d->m_mutex.unlock(); + emit this->tableChanged(this->d->m_tableName); +} + +void ColorTapElement::resetTable() +{ + this->setTable(":/ColorTap/share/tables/base.bmp"); +} + #include "moc_colortapelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorTap/src/colortapelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorTap/src/colortapelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorTap/src/colortapelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorTap/src/colortapelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void tableChanged(const QString &table); @@ -53,7 +54,6 @@ public slots: void setTable(const QString &table); void resetTable(); - AkPacket iStream(const AkPacket &packet); }; #endif // COLORTAPELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorTransform/src/colortransformelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorTransform/src/colortransformelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorTransform/src/colortransformelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorTransform/src/colortransformelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "colortransformelement.h" @@ -72,38 +73,12 @@ context->setContextProperty("controlId", this->objectName()); } -void ColorTransformElement::setKernel(const QVariantList &kernel) -{ - QVector k; - - for (const QVariant &e: kernel) - k << e.toReal(); - - if (this->d->m_kernel == k) - return; - - this->d->m_kernel = k; - emit this->kernelChanged(kernel); -} - -void ColorTransformElement::resetKernel() -{ - QVariantList kernel = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0 - }; - - this->setKernel(kernel); -} - -AkPacket ColorTransformElement::iStream(const AkPacket &packet) +AkPacket ColorTransformElement::iVideoStream(const AkVideoPacket &packet) { if (this->d->m_kernel.size() < 12) akSend(packet) - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -133,8 +108,33 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void ColorTransformElement::setKernel(const QVariantList &kernel) +{ + QVector k; + + for (const QVariant &e: kernel) + k << e.toReal(); + + if (this->d->m_kernel == k) + return; + + this->d->m_kernel = k; + emit this->kernelChanged(kernel); +} + +void ColorTransformElement::resetKernel() +{ + QVariantList kernel = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0 + }; + + this->setKernel(kernel); +} + #include "moc_colortransformelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorTransform/src/colortransformelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorTransform/src/colortransformelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ColorTransform/src/colortransformelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ColorTransform/src/colortransformelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void kernelChanged(const QVariantList &kernel); @@ -53,7 +54,6 @@ public slots: void setKernel(const QVariantList &kernel); void resetKernel(); - AkPacket iStream(const AkPacket &packet); }; #endif // COLORTRANSFORMELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Convolve/src/convolveelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Convolve/src/convolveelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Convolve/src/convolveelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Convolve/src/convolveelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "convolveelement.h" @@ -94,81 +95,9 @@ context->setContextProperty("controlId", this->objectName()); } -void ConvolveElement::setKernel(const QVariantList &kernel) -{ - QVector k; - - for (const QVariant &e: kernel) - k << e.toInt(); - - if (this->d->m_kernel == k) - return; - - QMutexLocker locker(&this->d->m_mutex); - this->d->m_kernel = k; - emit this->kernelChanged(kernel); -} - -void ConvolveElement::setKernelSize(const QSize &kernelSize) -{ - if (this->d->m_kernelSize == kernelSize) - return; - - QMutexLocker locker(&this->d->m_mutex); - this->d->m_kernelSize = kernelSize; - emit this->kernelSizeChanged(kernelSize); -} - -void ConvolveElement::setFactor(const AkFrac &factor) -{ - if (this->d->m_factor == factor) - return; - - QMutexLocker locker(&this->d->m_mutex); - this->d->m_factor = factor; - emit this->factorChanged(factor); -} - -void ConvolveElement::setBias(int bias) +AkPacket ConvolveElement::iVideoStream(const AkVideoPacket &packet) { - if (this->d->m_bias == bias) - return; - - QMutexLocker locker(&this->d->m_mutex); - this->d->m_bias = bias; - emit this->biasChanged(bias); -} - -void ConvolveElement::resetKernel() -{ - static const QVariantList kernel = { - 0, 0, 0, - 0, 1, 0, - 0, 0, 0 - }; - - this->setKernel(kernel); -} - -void ConvolveElement::resetKernelSize() -{ - this->setKernelSize(QSize(3, 3)); -} - -void ConvolveElement::resetFactor() -{ - this->setFactor(AkFrac(1, 1)); -} - -void ConvolveElement::resetBias() -{ - this->setBias(0); -} - -AkPacket ConvolveElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -233,8 +162,83 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void ConvolveElement::setKernel(const QVariantList &kernel) +{ + QVector k; + + for (const QVariant &e: kernel) + k << e.toInt(); + + if (this->d->m_kernel == k) + return; + + this->d->m_mutex.lock(); + this->d->m_kernel = k; + this->d->m_mutex.unlock(); + emit this->kernelChanged(kernel); +} + +void ConvolveElement::setKernelSize(const QSize &kernelSize) +{ + if (this->d->m_kernelSize == kernelSize) + return; + + this->d->m_mutex.lock(); + this->d->m_kernelSize = kernelSize; + this->d->m_mutex.unlock(); + emit this->kernelSizeChanged(kernelSize); +} + +void ConvolveElement::setFactor(const AkFrac &factor) +{ + if (this->d->m_factor == factor) + return; + + this->d->m_mutex.lock(); + this->d->m_factor = factor; + this->d->m_mutex.unlock(); + emit this->factorChanged(factor); +} + +void ConvolveElement::setBias(int bias) +{ + if (this->d->m_bias == bias) + return; + + this->d->m_mutex.lock(); + this->d->m_bias = bias; + this->d->m_mutex.unlock(); + emit this->biasChanged(bias); +} + +void ConvolveElement::resetKernel() +{ + static const QVariantList kernel = { + 0, 0, 0, + 0, 1, 0, + 0, 0, 0 + }; + + this->setKernel(kernel); +} + +void ConvolveElement::resetKernelSize() +{ + this->setKernelSize(QSize(3, 3)); +} + +void ConvolveElement::resetFactor() +{ + this->setFactor(AkFrac(1, 1)); +} + +void ConvolveElement::resetBias() +{ + this->setBias(0); +} + #include "moc_convolveelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Convolve/src/convolveelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Convolve/src/convolveelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Convolve/src/convolveelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Convolve/src/convolveelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -65,6 +65,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void kernelChanged(const QVariantList &kernel); @@ -81,7 +82,6 @@ void resetKernelSize(); void resetFactor(); void resetBias(); - AkPacket iStream(const AkPacket &packet); }; #endif // CONVOLVEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DelayGrab/src/delaygrabelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/DelayGrab/src/delaygrabelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DelayGrab/src/delaygrabelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DelayGrab/src/delaygrabelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,13 +17,15 @@ * Web-Site: http://webcamoid.github.io/ */ -#include +#include +#include #include -#include #include -#include #include +#include +#include #include +#include #include #include "delaygrabelement.h" @@ -44,7 +46,6 @@ Q_GLOBAL_STATIC_WITH_ARGS(DelayGrabModeMap, modeToStr, (initDelayGrabModeMap())) - class DelayGrabElementPrivate { public: @@ -115,57 +116,9 @@ context->setContextProperty("controlId", this->objectName()); } -void DelayGrabElement::setMode(const QString &mode) -{ - DelayGrabMode modeEnum = modeToStr->key(mode, DelayGrabModeRingsIncrease); - - if (this->d->m_mode == modeEnum) - return; - - QMutexLocker locker(&this->d->m_mutex); - this->d->m_mode = modeEnum; - emit this->modeChanged(mode); -} - -void DelayGrabElement::setBlockSize(int blockSize) -{ - if (this->d->m_blockSize == blockSize) - return; - - QMutexLocker locker(&this->d->m_mutex); - this->d->m_blockSize = blockSize; - emit this->blockSizeChanged(blockSize); -} - -void DelayGrabElement::setNFrames(int nFrames) -{ - if (this->d->m_nFrames == nFrames) - return; - - QMutexLocker locker(&this->d->m_mutex); - this->d->m_nFrames = nFrames; - emit this->nFramesChanged(nFrames); -} - -void DelayGrabElement::resetMode() -{ - this->setMode("RingsIncrease"); -} - -void DelayGrabElement::resetBlockSize() -{ - this->setBlockSize(2); -} - -void DelayGrabElement::resetNFrames() -{ - this->setNFrames(71); -} - -AkPacket DelayGrabElement::iStream(const AkPacket &packet) +AkPacket DelayGrabElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -226,10 +179,60 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void DelayGrabElement::setMode(const QString &mode) +{ + DelayGrabMode modeEnum = modeToStr->key(mode, DelayGrabModeRingsIncrease); + + if (this->d->m_mode == modeEnum) + return; + + this->d->m_mutex.lock(); + this->d->m_mode = modeEnum; + this->d->m_mutex.unlock(); + emit this->modeChanged(mode); +} + +void DelayGrabElement::setBlockSize(int blockSize) +{ + if (this->d->m_blockSize == blockSize) + return; + + this->d->m_mutex.lock(); + this->d->m_blockSize = blockSize; + this->d->m_mutex.unlock(); + emit this->blockSizeChanged(blockSize); +} + +void DelayGrabElement::setNFrames(int nFrames) +{ + if (this->d->m_nFrames == nFrames) + return; + + this->d->m_mutex.lock(); + this->d->m_nFrames = nFrames; + this->d->m_mutex.unlock(); + emit this->nFramesChanged(nFrames); +} + +void DelayGrabElement::resetMode() +{ + this->setMode("RingsIncrease"); +} + +void DelayGrabElement::resetBlockSize() +{ + this->setBlockSize(2); +} + +void DelayGrabElement::resetNFrames() +{ + this->setNFrames(71); +} + void DelayGrabElement::updateDelaymap() { QMutexLocker locker(&this->d->m_mutex); @@ -255,7 +258,7 @@ if (this->d->m_mode == DelayGrabModeRandomSquare) { // Random delay with square distribution - qreal d = qreal(qrand()) / RAND_MAX; + auto d = QRandomGenerator::global()->bounded(RAND_MAX); value = 16.0 * d * d; } else if (this->d->m_mode == DelayGrabModeVerticalIncrease) { value = qAbs(x) / 2.0; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DelayGrab/src/delaygrabelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/DelayGrab/src/delaygrabelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DelayGrab/src/delaygrabelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DelayGrab/src/delaygrabelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -71,6 +71,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void modeChanged(const QString &mode); @@ -85,7 +86,6 @@ void resetMode(); void resetBlockSize(); void resetNFrames(); - AkPacket iStream(const AkPacket &packet); private slots: void updateDelaymap(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Denoise/src/denoiseelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Denoise/src/denoiseelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Denoise/src/denoiseelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Denoise/src/denoiseelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "denoiseelement.h" @@ -208,71 +209,14 @@ context->setContextProperty("controlId", this->objectName()); } -void DenoiseElement::setRadius(int radius) -{ - if (this->d->m_radius == radius) - return; - - this->d->m_radius = radius; - emit this->radiusChanged(radius); -} - -void DenoiseElement::setFactor(int factor) -{ - if (this->d->m_factor == factor) - return; - - this->d->m_factor = factor; - emit this->factorChanged(factor); -} - -void DenoiseElement::setMu(int mu) -{ - if (this->d->m_mu == mu) - return; - - this->d->m_mu = mu; - emit this->muChanged(mu); -} - -void DenoiseElement::setSigma(qreal sigma) -{ - if (qFuzzyCompare(this->d->m_sigma, sigma)) - return; - - this->d->m_sigma = sigma; - emit this->sigmaChanged(sigma); -} - -void DenoiseElement::resetRadius() -{ - this->setRadius(1); -} - -void DenoiseElement::resetFactor() -{ - this->setFactor(1024); -} - -void DenoiseElement::resetMu() -{ - this->setMu(0); -} - -void DenoiseElement::resetSigma() -{ - this->setSigma(1.0); -} - -AkPacket DenoiseElement::iStream(const AkPacket &packet) +AkPacket DenoiseElement::iVideoStream(const AkVideoPacket &packet) { int radius = this->d->m_radius; if (radius < 1) akSend(packet) - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -347,8 +291,64 @@ delete [] integral; delete [] integral2; - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void DenoiseElement::setRadius(int radius) +{ + if (this->d->m_radius == radius) + return; + + this->d->m_radius = radius; + emit this->radiusChanged(radius); +} + +void DenoiseElement::setFactor(int factor) +{ + if (this->d->m_factor == factor) + return; + + this->d->m_factor = factor; + emit this->factorChanged(factor); +} + +void DenoiseElement::setMu(int mu) +{ + if (this->d->m_mu == mu) + return; + + this->d->m_mu = mu; + emit this->muChanged(mu); +} + +void DenoiseElement::setSigma(qreal sigma) +{ + if (qFuzzyCompare(this->d->m_sigma, sigma)) + return; + + this->d->m_sigma = sigma; + emit this->sigmaChanged(sigma); +} + +void DenoiseElement::resetRadius() +{ + this->setRadius(1); +} + +void DenoiseElement::resetFactor() +{ + this->setFactor(1024); +} + +void DenoiseElement::resetMu() +{ + this->setMu(0); +} + +void DenoiseElement::resetSigma() +{ + this->setSigma(1.0); +} + #include "moc_denoiseelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Denoise/src/denoiseelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Denoise/src/denoiseelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Denoise/src/denoiseelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Denoise/src/denoiseelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -64,6 +64,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void radiusChanged(int radius); @@ -80,7 +81,6 @@ void resetFactor(); void resetMu(); void resetSigma(); - AkPacket iStream(const AkPacket &packet); }; #endif // DENOISEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Denoise/src/pixel.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Denoise/src/pixel.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Denoise/src/pixel.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Denoise/src/pixel.h 2021-02-15 15:25:23.000000000 +0000 @@ -128,19 +128,17 @@ T b; }; -typedef Pixel PixelI8; -typedef Pixel PixelU8; -typedef Pixel PixelI32; -typedef Pixel PixelU32; -typedef Pixel PixelI64; -typedef Pixel PixelU64; -typedef Pixel PixelReal; +using PixelI8 = Pixel; +using PixelU8 = Pixel; +using PixelI32 = Pixel; +using PixelU32 = Pixel; +using PixelI64 = Pixel; +using PixelU64 = Pixel; +using PixelReal = Pixel; template inline Pixel mult(R c, const Pixel &pixel) { - return Pixel(c * pixel.r, - c * pixel.g, - c * pixel.b); + return Pixel(c * pixel.r, c * pixel.g, c * pixel.b); } inline PixelU64 pow2(QRgb pixel) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/DesktopCapture.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/DesktopCapture.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/DesktopCapture.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/DesktopCapture.pro 2021-02-15 15:25:23.000000000 +0000 @@ -20,5 +20,7 @@ CONFIG(debug, debug|release): CONFIG += ordered -SUBDIRS = src src/qtscreen +SUBDIRS = src +!android: SUBDIRS += src/qtscreen +android: SUBDIRS += src/androidscreen CONFIG(config_avfoundation): SUBDIRS += src/avfoundation diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/androidscreen.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/androidscreen.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/androidscreen.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/androidscreen.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,20 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +TEMPLATE = subdirs +SUBDIRS = jar src diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/jar/jar.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/jar/jar.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/jar/jar.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/jar/jar.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,45 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../../akcommons.pri) { + include(../../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +AK_PLUGIN = DesktopCapture +AK_SUBMODULE = androidscreen + +TARGET = Ak$${AK_PLUGIN}_$${AK_SUBMODULE} + +CONFIG += java +DESTDIR = $${PWD}/../../../../../../StandAlone/share/android/libs + +JAVACLASSPATH += \ + src + +JAVASOURCES += \ + src/org/webcamoid/plugins/$${AK_PLUGIN}/submodules/$${AK_SUBMODULE}/AkAndroidScreenCallbacks.java + +# install +target.path = $${JARDIR} +INSTALLS += target diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/jar/src/org/webcamoid/plugins/DesktopCapture/submodules/androidscreen/AkAndroidScreenCallbacks.java webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/jar/src/org/webcamoid/plugins/DesktopCapture/submodules/androidscreen/AkAndroidScreenCallbacks.java --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/jar/src/org/webcamoid/plugins/DesktopCapture/submodules/androidscreen/AkAndroidScreenCallbacks.java 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/jar/src/org/webcamoid/plugins/DesktopCapture/submodules/androidscreen/AkAndroidScreenCallbacks.java 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,96 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +package org.webcamoid.plugins.DesktopCapture.submodules.androidscreen; + +import java.nio.ByteBuffer; +import android.media.Image; +import android.media.ImageReader; +import android.media.projection.MediaProjection; + +public class AkAndroidScreenCallbacks implements ImageReader.OnImageAvailableListener +{ + private long m_userPtr = 0; + + public AkAndroidScreenCallbacks(long userPtr) + { + m_userPtr = userPtr; + } + + public MediaProjectionCallback mediaProjectionCallback() + { + return new MediaProjectionCallback(); + } + + // ImageReader.OnImageAvailableListener + + @Override + public void onImageAvailable(ImageReader imageReader) + { + Image image = imageReader.acquireLatestImage(); + Image.Plane[] planes = image.getPlanes(); + byte[] data = new byte[0]; + + for (Image.Plane plane: planes) { + ByteBuffer buffer = plane.getBuffer(); + buffer.rewind(); + byte[] newData = new byte[buffer.remaining()]; + buffer.get(newData); + byte[] concatData = new byte[data.length + newData.length]; + System.arraycopy(data, 0, concatData, 0, data.length); + System.arraycopy(newData, 0, concatData, data.length, newData.length); + data = concatData; + } + + int format = image.getFormat(); + int width = image.getWidth(); + int height = image.getHeight(); + long timestampNs = image.getTimestamp(); + image.close(); + + if (data.length < 1) + return; + + imageAvailable(m_userPtr, + format, + width, + height, + timestampNs, + data); + } + + // MediaProjection.Callback + + private class MediaProjectionCallback extends MediaProjection.Callback + { + @Override + public void onStop() + { + captureStopped(m_userPtr); + } + } + + private static native void imageAvailable(long userPtr, + int format, + int width, + int height, + long timestampNs, + byte[] data); + private static native void captureStopped(long userPtr); +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/androidscreendev.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/androidscreendev.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/androidscreendev.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/androidscreendev.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,567 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "androidscreendev.h" + +#define JNAMESPACE "org/webcamoid/plugins/DesktopCapture/submodules/androidscreen" +#define JCLASS(jclass) JNAMESPACE "/" #jclass +#define JLCLASS(jclass) "L" JNAMESPACE "/" jclass ";" + +#define MEDIA_PROJECTION_SERVICE "media_projection" +#define SCREEN_CAPTURE_REQUEST_CODE 0 +#define RESULT_OK -1 +#define BUFFER_SIZE 4 + +#define VIRTUAL_DISPLAY_FLAG_PUBLIC (1 << 0) +#define VIRTUAL_DISPLAY_FLAG_PRESENTATION (1 << 1) +#define VIRTUAL_DISPLAY_FLAG_SECURE (1 << 2) +#define VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY (1 << 3) +#define VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR (1 << 4) + +enum ImageFormat +{ + TRANSLUCENT = -3, + TRANSPARENT = -2, + OPAQUE = -1, + UNKNOWN = AK_FOURCC_NULL, + RGBA_8888 = 1, + RGBX_8888 = 2, + RGB_888 = 3, + RGB_565 = 4, + RGBA_5551 = 6, + RGBA_4444 = 7, + A_8 = 8, + L_8 = 9, + LA_88 = 10, + RGB_332 = 11, + NV16 = 16, + NV21 = 17, + YUY2 = 20, + RGBA_F16 = 22, + RAW_SENSOR = 32, + YUV_420_888 = 35, + PRIVATE = 34, + RAW_PRIVATE = 36, + RAW10 = 37, + RAW12 = 38, + YUV_422_888 = 39, + FLEX_RGB_888 = 41, + FLEX_RGBA_8888 = 42, + RGBA_1010102 = 43, + JPEG = 256, + DEPTH_POINT_CLOUD = 257, + Y8 = AkFourCCR('Y', '8', ' ', ' '), + YV12 = AkFourCCR('Y', 'V', '1', '2'), + DEPTH16 = AkFourCCR('Y', '1', '6', 'D'), + DEPTH_JPEG = AkFourCCR('c', 'i', 'e', 'i'), +}; + +class AndroidScreenDevPrivate: public QAndroidActivityResultReceiver +{ + public: + AndroidScreenDev *self; + AkFrac m_fps {30000, 1001}; + QString m_curScreen; + qint64 m_id {-1}; + QTimer m_timer; + QThreadPool m_threadPool; + QFuture m_threadStatus; + QWaitCondition m_captureSetupReady; + QWaitCondition m_packetReady; + QMutex m_mutex; + AkPacket m_curPacket; + QAndroidJniEnvironment m_jenv; + QAndroidJniObject m_activity; + QAndroidJniObject m_service; + QAndroidJniObject m_mediaProjection; + QAndroidJniObject m_virtualDisplay; + QAndroidJniObject m_imageReader; + QAndroidJniObject m_callbacks; + int m_curScreenNumber {-1}; + bool m_threadedRead {true}; + bool m_canCapture {false}; + + explicit AndroidScreenDevPrivate(AndroidScreenDev *self); + void registerNatives(); + void sendPacket(const AkPacket &packet); + void handleActivityResult(int requestCode, + int resultCode, + const QAndroidJniObject &intent); + static void imageAvailable(JNIEnv *env, + jobject obj, + jlong userPtr, + jint format, + jint width, + jint height, + jlong timestampNs, + jbyteArray data); + static void captureStopped(JNIEnv *env, jobject obj, jlong userPtr); +}; + +AndroidScreenDev::AndroidScreenDev(): + ScreenDev() +{ + this->d = new AndroidScreenDevPrivate(this); + this->d->m_activity = QtAndroid::androidActivity(); + this->d->m_timer.setInterval(qRound(1.e3 * + this->d->m_fps.invert().value())); + + QObject::connect(&this->d->m_timer, + &QTimer::timeout, + this, + &AndroidScreenDev::readFrame); +} + +AndroidScreenDev::~AndroidScreenDev() +{ + this->uninit(); + delete this->d; +} + +AkFrac AndroidScreenDev::fps() const +{ + return this->d->m_fps; +} + +QStringList AndroidScreenDev::medias() +{ + QStringList screens; + + for (int i = 0; i < QGuiApplication::screens().size(); i++) + screens << QString("screen://%1").arg(i); + + return screens; +} + +QString AndroidScreenDev::media() const +{ + if (!this->d->m_curScreen.isEmpty()) + return this->d->m_curScreen; + + int screen = QGuiApplication::screens().indexOf(QGuiApplication::primaryScreen()); + + return QString("screen://%1").arg(screen); +} + +QList AndroidScreenDev::streams() const +{ + QList streams; + streams << 0; + + return streams; +} + +int AndroidScreenDev::defaultStream(const QString &mimeType) +{ + if (mimeType == "video/x-raw") + return 0; + + return -1; +} + +QString AndroidScreenDev::description(const QString &media) +{ + for (int i = 0; i < QGuiApplication::screens().size(); i++) + if (QString("screen://%1").arg(i) == media) + return QString("Screen %1").arg(i); + + return QString(); +} + +AkCaps AndroidScreenDev::caps(int stream) +{ + if (this->d->m_curScreenNumber < 0 + || stream != 0) + return AkCaps(); + + auto screens = QGuiApplication::screens(); + auto screen = screens[this->d->m_curScreenNumber]; + + if (!screen) + return {}; + + return AkVideoCaps(AkVideoCaps::Format_rgb24, + screen->size().width(), + screen->size().height(), + this->d->m_fps); +} + +AndroidScreenDevPrivate::AndroidScreenDevPrivate(AndroidScreenDev *self): + self(self) +{ + this->registerNatives(); + this->m_callbacks = + QAndroidJniObject(JCLASS(AkAndroidScreenCallbacks), + "(J)V", + this); +} + +void AndroidScreenDevPrivate::registerNatives() +{ + static bool ready = false; + + if (ready) + return; + + QAndroidJniEnvironment jenv; + + if (auto jclass = jenv.findClass(JCLASS(AkAndroidScreenCallbacks))) { + QVector methods { + {"imageAvailable", "(JIIIJ[B)V", reinterpret_cast(AndroidScreenDevPrivate::imageAvailable)}, + {"captureStopped", "(J)V" , reinterpret_cast(AndroidScreenDevPrivate::captureStopped)}, + }; + + jenv->RegisterNatives(jclass, methods.data(), methods.size()); + } + + ready = true; +} + +void AndroidScreenDevPrivate::sendPacket(const AkPacket &packet) +{ + emit self->oStream(packet); +} + +void AndroidScreenDevPrivate::handleActivityResult(int requestCode, + int resultCode, + const QAndroidJniObject &intent) +{ + if (requestCode != SCREEN_CAPTURE_REQUEST_CODE) + return; + + QAndroidJniObject mediaProjectionCallback; + QAndroidJniObject resources; + QAndroidJniObject metrics; + QAndroidJniObject surface; + auto displayName = QAndroidJniObject::fromString("VirtualDisplay"); + jint width; + jint height; + jint density; + + if (resultCode != RESULT_OK) + goto handleActivityResult_fail; + + this->m_mediaProjection = + this->m_service.callObjectMethod("getMediaProjection", + "(ILandroid/content/Intent;)Landroid/media/projection/MediaProjection;", + resultCode, + intent.object()); + + if (!this->m_mediaProjection.isValid()) + goto handleActivityResult_fail; + + mediaProjectionCallback = this->m_callbacks.callObjectMethod("mediaProjectionCallback", + "()" + JLCLASS("AkAndroidScreenCallbacks$MediaProjectionCallback")); + this->m_mediaProjection.callMethod("registerCallback", + "(Landroid/media/projection/MediaProjection$Callback;" + "Landroid/os/Handler;)V", + mediaProjectionCallback.object(), + nullptr); + resources = + this->m_activity.callObjectMethod("getResources", + "()Landroid/content/res/Resources;"); + metrics = resources.callObjectMethod("getDisplayMetrics", + "()Landroid/util/DisplayMetrics;"); + width = metrics.getField("widthPixels"); + height = metrics.getField("heightPixels"); + density = metrics.getField("densityDpi"); + + this->m_imageReader = + QAndroidJniObject::callStaticObjectMethod("android/media/ImageReader", + "newInstance", + "(IIII)Landroid/media/ImageReader;", + width, + height, + ImageFormat::RGBA_8888, + BUFFER_SIZE); + + if (!this->m_imageReader.isValid()) + goto handleActivityResult_fail; + + surface = + this->m_imageReader.callObjectMethod("getSurface", + "()Landroid/view/Surface;"); + + if (!surface.isValid()) + goto handleActivityResult_fail; + + this->m_imageReader.callMethod("setOnImageAvailableListener", + "(Landroid/media/ImageReader$OnImageAvailableListener;" + "Landroid/os/Handler;)V", + this->m_callbacks.object(), + nullptr); + + this->m_virtualDisplay = + this->m_mediaProjection.callObjectMethod("createVirtualDisplay", + "(Ljava/lang/String;" + "IIII" + "Landroid/view/Surface;" + "Landroid/hardware/display/VirtualDisplay$Callback;" + "Landroid/os/Handler;)" + "Landroid/hardware/display/VirtualDisplay;", + displayName.object(), + width, + height, + density, + VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, + surface.object(), + nullptr, + nullptr); + + if (!this->m_virtualDisplay.isValid()) + goto handleActivityResult_fail; + + this->m_canCapture = true; + +handleActivityResult_fail: + this->m_mutex.lock(); + this->m_captureSetupReady.wakeAll(); + this->m_mutex.unlock(); +} + +void AndroidScreenDevPrivate::imageAvailable(JNIEnv *env, + jobject obj, + jlong userPtr, + jint format, + jint width, + jint height, + jlong timestampNs, + jbyteArray data) +{ + Q_UNUSED(env) + Q_UNUSED(obj) + Q_UNUSED(format) + + auto dataSize = env->GetArrayLength(data); + + if (dataSize < 1) + return; + + QByteArray oBuffer(dataSize, Qt::Uninitialized); + env->GetByteArrayRegion(data, + 0, + dataSize, + reinterpret_cast(oBuffer.data())); + + auto self = reinterpret_cast(userPtr); + AkVideoCaps caps(AkVideoCaps::Format_0bgr, + width, + height, + self->m_fps); + auto pts = qint64(timestampNs * self->m_fps.value() / 1e9); + + AkVideoPacket packet; + packet.caps() = caps; + packet.buffer() = oBuffer; + packet.setPts(pts); + packet.setTimeBase(self->m_fps.invert()); + packet.setIndex(0); + packet.setId(self->m_id); + packet = packet.convert(AkVideoCaps::Format_rgb24); + + self->m_mutex.lock(); + self->m_curPacket = packet; + self->m_packetReady.wakeAll(); + self->m_mutex.unlock(); +} + +void AndroidScreenDevPrivate::captureStopped(JNIEnv *env, + jobject obj, + jlong userPtr) +{ + Q_UNUSED(env) + Q_UNUSED(obj) + Q_UNUSED(userPtr) +} + +void AndroidScreenDev::setFps(const AkFrac &fps) +{ + if (this->d->m_fps == fps) + return; + + this->d->m_mutex.lock(); + this->d->m_fps = fps; + this->d->m_mutex.unlock(); + emit this->fpsChanged(fps); + this->d->m_timer.setInterval(qRound(1.e3 * + this->d->m_fps.invert().value())); +} + +void AndroidScreenDev::resetFps() +{ + this->setFps(AkFrac(30000, 1001)); +} + +void AndroidScreenDev::setMedia(const QString &media) +{ + for (int i = 0; i < QGuiApplication::screens().size(); i++) { + auto screen = QString("screen://%1").arg(i); + + if (screen == media) { + if (this->d->m_curScreenNumber == i) + break; + + this->d->m_curScreen = screen; + this->d->m_curScreenNumber = i; + emit this->mediaChanged(media); + + break; + } + } +} + +void AndroidScreenDev::resetMedia() +{ + int screen = QGuiApplication::screens().indexOf(QGuiApplication::primaryScreen()); + + if (this->d->m_curScreenNumber == screen) + return; + + this->d->m_curScreen = QString("screen://%1").arg(screen); + this->d->m_curScreenNumber = screen; + + emit this->mediaChanged(this->d->m_curScreen); +} + +void AndroidScreenDev::setStreams(const QList &streams) +{ + Q_UNUSED(streams) +} + +void AndroidScreenDev::resetStreams() +{ + +} + +bool AndroidScreenDev::init() +{ + this->uninit(); + + this->d->m_canCapture = false; + auto serviceName = QAndroidJniObject::fromString(MEDIA_PROJECTION_SERVICE); + this->d->m_service = + this->d->m_activity.callObjectMethod("getSystemService", + "(Ljava/lang/String;)Ljava/lang/Object;", + serviceName.object()); + + if (!this->d->m_service.isValid()) + return false; + + auto intent = + this->d->m_service.callObjectMethod("createScreenCaptureIntent", + "()Landroid/content/Intent;"); + + if (!intent.isValid()) + return false; + + QtAndroid::startActivity(intent, + SCREEN_CAPTURE_REQUEST_CODE, + this->d); + + this->d->m_mutex.lock(); + this->d->m_captureSetupReady.wait(&this->d->m_mutex); + this->d->m_mutex.unlock(); + + if (!this->d->m_canCapture) + return false; + + this->d->m_id = Ak::id(); + this->d->m_timer.setInterval(qRound(1.e3 * + this->d->m_fps.invert().value())); + this->d->m_timer.start(); + + return true; +} + +bool AndroidScreenDev::uninit() +{ + this->d->m_timer.stop(); + this->d->m_threadStatus.waitForFinished(); + + if (this->d->m_mediaProjection.isValid()) { + this->d->m_mediaProjection.callMethod("stop"); + this->d->m_mediaProjection = {}; + } + + if (this->d->m_virtualDisplay.isValid()) { + this->d->m_virtualDisplay.callMethod("release"); + this->d->m_virtualDisplay = {}; + } + + if (this->d->m_imageReader.isValid()) { + this->d->m_imageReader.callMethod("close"); + this->d->m_imageReader = {}; + } + + this->d->m_service = {}; + + return true; +} + +void AndroidScreenDev::readFrame() +{ + this->d->m_mutex.lock(); + + if (!this->d->m_curPacket) + if (!this->d->m_packetReady.wait(&this->d->m_mutex, 1000)) { + this->d->m_mutex.unlock(); + + return; + } + + auto packet = this->d->m_curPacket; + this->d->m_curPacket = {}; + this->d->m_mutex.unlock(); + + if (!this->d->m_threadedRead) { + emit this->oStream(packet); + + return; + } + + if (!this->d->m_threadStatus.isRunning()) { + this->d->m_threadStatus = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &AndroidScreenDevPrivate::sendPacket, + packet); + } +} + +#include "moc_androidscreendev.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/androidscreendev.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/androidscreendev.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/androidscreendev.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/androidscreendev.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,87 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef ANDROIDSCREENDEV_H +#define ANDROIDSCREENDEV_H + +#include "screendev.h" + +class AndroidScreenDevPrivate; + +class AndroidScreenDev: public ScreenDev +{ + Q_OBJECT + Q_PROPERTY(QStringList medias + READ medias + NOTIFY mediasChanged) + Q_PROPERTY(QString media + READ media + WRITE setMedia + RESET resetMedia + NOTIFY mediaChanged) + Q_PROPERTY(QList streams + READ streams + WRITE setStreams + RESET resetStreams + NOTIFY streamsChanged) + Q_PROPERTY(AkFrac fps + READ fps + WRITE setFps + RESET resetFps + NOTIFY fpsChanged) + + public: + AndroidScreenDev(); + ~AndroidScreenDev(); + + Q_INVOKABLE AkFrac fps() const; + Q_INVOKABLE QStringList medias(); + Q_INVOKABLE QString media() const; + Q_INVOKABLE QList streams() const; + Q_INVOKABLE int defaultStream(const QString &mimeType); + Q_INVOKABLE QString description(const QString &media); + Q_INVOKABLE AkCaps caps(int stream); + + private: + AndroidScreenDevPrivate *d; + + signals: + void mediasChanged(const QStringList &medias); + void mediaChanged(const QString &media); + void streamsChanged(const QList &streams); + void loopChanged(bool loop); + void fpsChanged(const AkFrac &fps); + void sizeChanged(const QString &media, const QSize &size); + void error(const QString &message); + + public slots: + void setFps(const AkFrac &fps); + void resetFps(); + void setMedia(const QString &media); + void resetMedia(); + void setStreams(const QList &streams); + void resetStreams(); + bool init(); + bool uninit(); + + private slots: + void readFrame(); +}; + +#endif // ANDROIDSCREENDEV_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "androidscreendev.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new AndroidScreenDev(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return QStringList(); +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,4 @@ +{ + "pluginType": "Ak.SubModule", + "type": "capture" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/src.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/src.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/src.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/androidscreen/src/src.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,66 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../../akcommons.pri) { + include(../../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +TARGET = androidscreen + +CONFIG += plugin + +HEADERS = \ + plugin.h \ + androidscreendev.h \ + ../../screendev.h + +INCLUDEPATH += \ + ../../../../../Lib/src \ + ../../ + +LIBS += -L$${OUT_PWD}/../../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} + +OTHER_FILES += pspec.json + +QT += qml concurrent widgets +android: QT += androidextras + +SOURCES = \ + plugin.cpp \ + androidscreendev.cpp \ + ../../screendev.cpp + +akModule = DesktopCapture +DESTDIR = $${OUT_PWD}/../../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/avfoundation/src/avfoundationscreendev.mm webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/avfoundation/src/avfoundationscreendev.mm --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/avfoundation/src/avfoundationscreendev.mm 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/avfoundation/src/avfoundationscreendev.mm 2021-02-15 15:25:23.000000000 +0000 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -128,22 +129,17 @@ { if (this->d->m_curScreenNumber < 0 || stream != 0) - return AkCaps(); + return {}; auto screen = QGuiApplication::screens()[this->d->m_curScreenNumber]; if (!screen) - return QString(); + return {}; - AkVideoCaps caps; - caps.isValid() = true; - caps.format() = AkVideoCaps::Format_argb; - caps.bpp() = AkVideoCaps::bitsPerPixel(caps.format()); - caps.width() = screen->size().width(); - caps.height() = screen->size().height(); - caps.fps() = this->d->m_fps; - - return caps.toCaps(); + return AkVideoCaps(AkVideoCaps::Format_argb, + screen->size().width(), + screen->size().height(), + this->d->m_fps); } void AVFoundationScreenDev::frameReceived(CGDirectDisplayID screen, @@ -154,21 +150,18 @@ { CGImageRef image = CGDisplayCreateImage(screen); - AkVideoCaps caps; - caps.isValid() = true; - caps.format() = AkVideoCaps::Format_argb; - caps.bpp() = AkVideoCaps::bitsPerPixel(caps.format()); - caps.width() = int(CGImageGetWidth(image)); - caps.height() = int(CGImageGetHeight(image)); - caps.fps() = fps; - - AkVideoPacket videoPacket(caps, buffer); - videoPacket.setPts(pts); - videoPacket.setTimeBase(fps.invert()); - videoPacket.setIndex(0); - videoPacket.setId(id); + AkVideoPacket videoPacket; + videoPacket.caps() = {AkVideoCaps::Format_argb, + int(CGImageGetWidth(image)), + int(CGImageGetHeight(image)), + fps}; + videoPacket.buffer() = buffer; + videoPacket.pts() = pts; + videoPacket.timeBase() = fps.invert(); + videoPacket.index() = 0; + videoPacket.id() = id; - emit this->oStream(videoPacket.toPacket()); + emit this->oStream(videoPacket); } void AVFoundationScreenDev::sendPacket(const AkPacket &packet) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcapture.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcapture.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcapture.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcapture.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include "desktopcapture.h" #include "desktopcaptureelement.h" +#include "desktopcaptureelementsettings.h" QObject *DesktopCapture::create(const QString &key, const QString &specification) { @@ -26,13 +27,16 @@ if (key == AK_PLUGIN_TYPE_ELEMENT) return new DesktopCaptureElement(); + else if (key == AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + return new DesktopCaptureElementSettings(); return nullptr; } QStringList DesktopCapture::keys() const { - return QStringList(); + return {AK_PLUGIN_TYPE_ELEMENT, + AK_PLUGIN_TYPE_ELEMENT_SETTINGS}; } #include "moc_desktopcapture.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -24,11 +24,9 @@ #include #include "desktopcaptureelement.h" -#include "desktopcaptureglobals.h" +#include "desktopcaptureelementsettings.h" #include "screendev.h" -Q_GLOBAL_STATIC(DesktopCaptureGlobals, globalDesktopCapture) - template inline QSharedPointer ptr_cast(QObject *obj=nullptr) { @@ -40,24 +38,25 @@ class DesktopCaptureElementPrivate { public: + DesktopCaptureElement *self; + DesktopCaptureElementSettings m_settings; ScreenDevPtr m_screenCapture; + + explicit DesktopCaptureElementPrivate(DesktopCaptureElement *self); + void captureLibUpdated(const QString &captureLib); }; DesktopCaptureElement::DesktopCaptureElement(): AkMultimediaSourceElement() { - this->d = new DesktopCaptureElementPrivate; - - QObject::connect(globalDesktopCapture, - SIGNAL(captureLibChanged(const QString &)), - this, - SIGNAL(captureLibChanged(const QString &))); - QObject::connect(globalDesktopCapture, - SIGNAL(captureLibChanged(const QString &)), - this, - SLOT(captureLibUpdated(const QString &))); + this->d = new DesktopCaptureElementPrivate(this); + QObject::connect(&this->d->m_settings, + &DesktopCaptureElementSettings::captureLibChanged, + [this] (const QString &captureLib) { + this->d->captureLibUpdated(captureLib); + }); - this->captureLibUpdated(globalDesktopCapture->captureLib()); + this->d->captureLibUpdated(this->d->m_settings.captureLib()); } DesktopCaptureElement::~DesktopCaptureElement() @@ -122,11 +121,6 @@ return this->d->m_screenCapture->caps(stream); } -QString DesktopCaptureElement::captureLib() const -{ - return globalDesktopCapture->captureLib(); -} - QString DesktopCaptureElement::controlInterfaceProvide(const QString &controlId) const { Q_UNUSED(controlId) @@ -174,16 +168,6 @@ this->d->m_screenCapture->resetMedia(); } -void DesktopCaptureElement::setCaptureLib(const QString &captureLib) -{ - globalDesktopCapture->setCaptureLib(captureLib); -} - -void DesktopCaptureElement::resetCaptureLib() -{ - globalDesktopCapture->resetCaptureLib(); -} - bool DesktopCaptureElement::setState(AkElement::ElementState state) { if (!this->d->m_screenCapture) @@ -240,63 +224,69 @@ return false; } -void DesktopCaptureElement::captureLibUpdated(const QString &captureLib) +DesktopCaptureElementPrivate::DesktopCaptureElementPrivate(DesktopCaptureElement *self): + self(self) { - auto state = this->state(); - this->setState(AkElement::ElementStateNull); - this->d->m_screenCapture = +} + +void DesktopCaptureElementPrivate::captureLibUpdated(const QString &captureLib) +{ + auto state = self->state(); + self->setState(AkElement::ElementStateNull); + + this->m_screenCapture = ptr_cast(DesktopCaptureElement::loadSubModule("DesktopCapture", captureLib)); - if (!this->d->m_screenCapture) + if (!this->m_screenCapture) return; QSettings settings; settings.beginGroup("DesktopCapture"); auto fps = settings.value("fps", 30).toString(); - this->d->m_screenCapture->setFps(AkFrac(fps)); + this->m_screenCapture->setFps(AkFrac(fps)); settings.endGroup(); - QObject::connect(this->d->m_screenCapture.data(), + QObject::connect(this->m_screenCapture.data(), &ScreenDev::mediasChanged, - this, + self, &DesktopCaptureElement::mediasChanged); - QObject::connect(this->d->m_screenCapture.data(), + QObject::connect(this->m_screenCapture.data(), &ScreenDev::mediaChanged, - this, + self, &DesktopCaptureElement::mediaChanged); - QObject::connect(this->d->m_screenCapture.data(), + QObject::connect(this->m_screenCapture.data(), &ScreenDev::streamsChanged, - this, + self, &DesktopCaptureElement::streamsChanged); - QObject::connect(this->d->m_screenCapture.data(), + QObject::connect(this->m_screenCapture.data(), &ScreenDev::streamsChanged, - this, + self, &DesktopCaptureElement::streamsChanged); - QObject::connect(this->d->m_screenCapture.data(), + QObject::connect(this->m_screenCapture.data(), &ScreenDev::fpsChanged, - this, + self, &DesktopCaptureElement::fpsChanged); - QObject::connect(this->d->m_screenCapture.data(), + QObject::connect(this->m_screenCapture.data(), &ScreenDev::sizeChanged, - this, + self, &DesktopCaptureElement::sizeChanged); - QObject::connect(this->d->m_screenCapture.data(), + QObject::connect(this->m_screenCapture.data(), &ScreenDev::oStream, - this, + self, &DesktopCaptureElement::oStream, Qt::DirectConnection); - emit this->mediasChanged(this->medias()); - emit this->streamsChanged(this->streams()); + emit self->mediasChanged(self->medias()); + emit self->streamsChanged(self->streams()); - auto medias = this->medias(); + auto medias = self->medias(); if (!medias.isEmpty()) - this->setMedia(medias.first()); + self->setMedia(medias.first()); - this->setState(state); + self->setState(state); } #include "moc_desktopcaptureelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -51,11 +51,6 @@ WRITE setFps RESET resetFps NOTIFY fpsChanged) - Q_PROPERTY(QString captureLib - READ captureLib - WRITE setCaptureLib - RESET resetCaptureLib - NOTIFY captureLibChanged) public: DesktopCaptureElement(); @@ -68,7 +63,6 @@ Q_INVOKABLE int defaultStream(const QString &mimeType); Q_INVOKABLE QString description(const QString &media); Q_INVOKABLE AkCaps caps(int stream); - Q_INVOKABLE QString captureLib() const; private: DesktopCaptureElementPrivate *d; @@ -86,19 +80,13 @@ void fpsChanged(const AkFrac &fps); void sizeChanged(const QString &media, const QSize &size); void error(const QString &message); - void captureLibChanged(const QString &captureLib); public slots: void setFps(const AkFrac &fps); void resetFps(); void setMedia(const QString &media); void resetMedia(); - void setCaptureLib(const QString &captureLib); - void resetCaptureLib(); bool setState(AkElement::ElementState state); - - private slots: - void captureLibUpdated(const QString &captureLib); }; #endif // DESKTOPCAPTUREELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelementsettings.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelementsettings.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelementsettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelementsettings.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,54 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2017 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "desktopcaptureelementsettings.h" +#include "desktopcaptureglobals.h" + +Q_GLOBAL_STATIC(DesktopCaptureGlobals, globalDesktopCapture) + +DesktopCaptureElementSettings::DesktopCaptureElementSettings(QObject *parent): + QObject(parent) +{ + QObject::connect(globalDesktopCapture, + &DesktopCaptureGlobals::captureLibChanged, + this, + &DesktopCaptureElementSettings::captureLibChanged); +} + +QString DesktopCaptureElementSettings::captureLib() const +{ + return globalDesktopCapture->captureLib(); +} + +QStringList DesktopCaptureElementSettings::subModules() const +{ + return globalDesktopCapture->subModules(); +} + +void DesktopCaptureElementSettings::setCaptureLib(const QString &captueLib) +{ + globalDesktopCapture->setCaptureLib(captueLib); +} + +void DesktopCaptureElementSettings::resetCaptureLib() +{ + globalDesktopCapture->resetCaptureLib(); +} + +#include "moc_desktopcaptureelementsettings.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelementsettings.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelementsettings.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelementsettings.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureelementsettings.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,52 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2017 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef DESKTOPCAPTUREELEMENTSETTINGS_H +#define DESKTOPCAPTUREELEMENTSETTINGS_H + +#include + +class DesktopCaptureElementSettings: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString captureLib + READ captureLib + WRITE setCaptureLib + RESET resetCaptureLib + NOTIFY captureLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules + NOTIFY subModulesChanged) + + public: + DesktopCaptureElementSettings(QObject *parent=nullptr); + + Q_INVOKABLE QString captureLib() const; + Q_INVOKABLE QStringList subModules() const; + + signals: + void captureLibChanged(const QString &captureLib); + void subModulesChanged(const QStringList &subModules); + + public slots: + void setCaptureLib(const QString &captueLib); + void resetCaptureLib(); +}; + +#endif // DESKTOPCAPTUREELEMENTSETTINGS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureglobals.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureglobals.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureglobals.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureglobals.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,44 +21,70 @@ #include "desktopcaptureglobals.h" +class DesktopCaptureGlobalsPrivate +{ + public: + QString m_captureLib; + QStringList m_preferredLibrary; + + DesktopCaptureGlobalsPrivate(); +}; + DesktopCaptureGlobals::DesktopCaptureGlobals(QObject *parent): QObject(parent) { - this->m_preferredLibrary = QStringList { - "avfoundation", - "qtscreen", - }; - + this->d = new DesktopCaptureGlobalsPrivate; this->resetCaptureLib(); } +DesktopCaptureGlobals::~DesktopCaptureGlobals() +{ + delete this->d; +} + QString DesktopCaptureGlobals::captureLib() const { - return this->m_captureLib; + return this->d->m_captureLib; } -void DesktopCaptureGlobals::setCaptureLib(const QString &audioLib) +QStringList DesktopCaptureGlobals::subModules() const { - if (this->m_captureLib == audioLib) + return AkElement::listSubModules("DesktopCapture"); +} + +void DesktopCaptureGlobals::setCaptureLib(const QString &captureLib) +{ + if (this->d->m_captureLib == captureLib) return; - this->m_captureLib = audioLib; - emit this->captureLibChanged(audioLib); + this->d->m_captureLib = captureLib; + emit this->captureLibChanged(captureLib); } void DesktopCaptureGlobals::resetCaptureLib() { auto subModules = AkElement::listSubModules("DesktopCapture"); - for (auto &framework: this->m_preferredLibrary) + for (auto &framework: this->d->m_preferredLibrary) if (subModules.contains(framework)) { this->setCaptureLib(framework); return; } - if (this->m_captureLib.isEmpty() && !subModules.isEmpty()) + if (this->d->m_captureLib.isEmpty() && !subModules.isEmpty()) this->setCaptureLib(subModules.first()); else this->setCaptureLib(""); } + +DesktopCaptureGlobalsPrivate::DesktopCaptureGlobalsPrivate() +{ + this->m_preferredLibrary = QStringList { + "avfoundation", + "androidscreen", + "qtscreen", + }; +} + +#include "moc_desktopcaptureglobals.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureglobals.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureglobals.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureglobals.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/desktopcaptureglobals.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,8 @@ #include +class DesktopCaptureGlobalsPrivate; + class DesktopCaptureGlobals: public QObject { Q_OBJECT @@ -30,15 +32,18 @@ WRITE setCaptureLib RESET resetCaptureLib NOTIFY captureLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules) public: DesktopCaptureGlobals(QObject *parent=nullptr); + ~DesktopCaptureGlobals(); Q_INVOKABLE QString captureLib() const; + Q_INVOKABLE QStringList subModules() const; private: - QString m_captureLib; - QStringList m_preferredLibrary; + DesktopCaptureGlobalsPrivate *d; signals: void captureLibChanged(const QString &captureLib); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -151,15 +151,10 @@ if (!screen) return {}; - AkVideoCaps caps; - caps.isValid() = true; - caps.format() = AkVideoCaps::Format_rgb24; - caps.bpp() = AkVideoCaps::bitsPerPixel(caps.format()); - caps.width() = screen->size().width(); - caps.height() = screen->size().height(); - caps.fps() = this->d->m_fps; - - return caps.toCaps(); + return AkVideoCaps(AkVideoCaps::Format_rgb24, + screen->size().width(), + screen->size().height(), + this->d->m_fps); } QtScreenDevPrivate::QtScreenDevPrivate(QtScreenDev *self): @@ -193,7 +188,7 @@ void QtScreenDev::setMedia(const QString &media) { for (int i = 0; i < QGuiApplication::screens().size(); i++) { - QString screen = QString("screen://%1").arg(i); + auto screen = QString("screen://%1").arg(i); if (screen == media) { if (this->d->m_curScreenNumber == i) @@ -258,13 +253,11 @@ auto fps = this->d->m_fps; this->d->m_mutex.unlock(); - AkVideoCaps caps; - caps.isValid() = true; - caps.format() = AkVideoCaps::Format_rgb24; - caps.bpp() = AkVideoCaps::bitsPerPixel(caps.format()); - caps.width() = screen->size().width(); - caps.height() = screen->size().height(); - caps.fps() = fps; + AkVideoPacket packet; + packet.caps() = {AkVideoCaps::Format_rgb24, + screen->size().width(), + screen->size().height(), + fps}; auto frame = screen->grabWindow(QApplication::desktop()->winId(), @@ -272,14 +265,14 @@ screen->geometry().y(), screen->geometry().width(), screen->geometry().height()); - QImage frameImg = frame.toImage().convertToFormat(QImage::Format_RGB888); - auto packet = AkVideoPacket::fromImage(frameImg, caps).toPacket(); + auto frameImg = frame.toImage().convertToFormat(QImage::Format_RGB888); + packet = AkVideoPacket::fromImage(frameImg, packet); if (!packet) return; - qint64 pts = qint64(QTime::currentTime().msecsSinceStartOfDay() - * fps.value() / 1e3); + auto pts = qint64(QTime::currentTime().msecsSinceStartOfDay() + * fps.value() / 1e3); packet.setPts(pts); packet.setTimeBase(fps.invert()); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/src.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/src.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/DesktopCapture/src/src.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/DesktopCapture/src/src.pro 2021-02-15 15:25:23.000000000 +0000 @@ -36,6 +36,7 @@ HEADERS = \ desktopcapture.h \ desktopcaptureelement.h \ + desktopcaptureelementsettings.h \ desktopcaptureglobals.h \ screendev.h @@ -55,6 +56,7 @@ SOURCES = \ desktopcapture.cpp \ desktopcaptureelement.cpp \ + desktopcaptureelementsettings.cpp \ desktopcaptureglobals.cpp \ screendev.cpp diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Dice/src/diceelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Dice/src/diceelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Dice/src/diceelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Dice/src/diceelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,11 +17,14 @@ * Web-Site: http://webcamoid.github.io/ */ +#include #include +#include #include #include -#include +#include #include +#include #include #include "diceelement.h" @@ -66,24 +69,9 @@ context->setContextProperty("controlId", this->objectName()); } -void DiceElement::setDiceSize(int diceSize) -{ - if (this->d->m_diceSize == diceSize) - return; - - this->d->m_diceSize = diceSize; - emit this->diceSizeChanged(diceSize); -} - -void DiceElement::resetDiceSize() -{ - this->setDiceSize(24); -} - -AkPacket DiceElement::iStream(const AkPacket &packet) +AkPacket DiceElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -135,22 +123,35 @@ painter.end(); - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void DiceElement::setDiceSize(int diceSize) +{ + if (this->d->m_diceSize == diceSize) + return; + + this->d->m_diceSize = diceSize; + emit this->diceSizeChanged(diceSize); +} + +void DiceElement::resetDiceSize() +{ + this->setDiceSize(24); +} + void DiceElement::updateDiceMap() { int width = qCeil(this->d->m_frameSize.width() / qreal(this->d->m_diceSize)); int height = qCeil(this->d->m_frameSize.height() / qreal(this->d->m_diceSize)); - QImage diceMap(width, height, QImage::Format_Grayscale8); for (int y = 0; y < diceMap.height(); y++) { auto oLine = reinterpret_cast(diceMap.scanLine(y)); for (int x = 0; x < diceMap.width(); x++) - oLine[x] = qrand() % 4; + oLine[x] = quint8(QRandomGenerator::global()->bounded(4)); } this->d->m_diceMap = diceMap; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Dice/src/diceelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Dice/src/diceelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Dice/src/diceelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Dice/src/diceelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void diceSizeChanged(int diceSize); @@ -54,7 +55,6 @@ public slots: void setDiceSize(int diceSize); void resetDiceSize(); - AkPacket iStream(const AkPacket &packet); private slots: void updateDiceMap(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Distort/src/distortelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Distort/src/distortelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Distort/src/distortelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Distort/src/distortelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include "distortelement.h" @@ -119,52 +121,9 @@ context->setContextProperty("controlId", this->objectName()); } -void DistortElement::setAmplitude(qreal amplitude) -{ - if (qFuzzyCompare(this->d->m_amplitude, amplitude)) - return; - - this->d->m_amplitude = amplitude; - emit this->amplitudeChanged(amplitude); -} - -void DistortElement::setFrequency(qreal frequency) -{ - if (qFuzzyCompare(this->d->m_frequency, frequency)) - return; - - this->d->m_frequency = frequency; - emit this->frequencyChanged(frequency); -} - -void DistortElement::setGridSizeLog(int gridSizeLog) -{ - if (this->d->m_gridSizeLog == gridSizeLog) - return; - - this->d->m_gridSizeLog = gridSizeLog; - emit this->gridSizeLogChanged(gridSizeLog); -} - -void DistortElement::resetAmplitude() -{ - this->setAmplitude(1.0); -} - -void DistortElement::resetFrequency() -{ - this->setFrequency(1.0); -} - -void DistortElement::resetGridSizeLog() -{ - this->setGridSizeLog(1); -} - -AkPacket DistortElement::iStream(const AkPacket &packet) +AkPacket DistortElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -237,8 +196,50 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void DistortElement::setAmplitude(qreal amplitude) +{ + if (qFuzzyCompare(this->d->m_amplitude, amplitude)) + return; + + this->d->m_amplitude = amplitude; + emit this->amplitudeChanged(amplitude); +} + +void DistortElement::setFrequency(qreal frequency) +{ + if (qFuzzyCompare(this->d->m_frequency, frequency)) + return; + + this->d->m_frequency = frequency; + emit this->frequencyChanged(frequency); +} + +void DistortElement::setGridSizeLog(int gridSizeLog) +{ + if (this->d->m_gridSizeLog == gridSizeLog) + return; + + this->d->m_gridSizeLog = gridSizeLog; + emit this->gridSizeLogChanged(gridSizeLog); +} + +void DistortElement::resetAmplitude() +{ + this->setAmplitude(1.0); +} + +void DistortElement::resetFrequency() +{ + this->setFrequency(1.0); +} + +void DistortElement::resetGridSizeLog() +{ + this->setGridSizeLog(1); +} + #include "moc_distortelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Distort/src/distortelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Distort/src/distortelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Distort/src/distortelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Distort/src/distortelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -58,6 +58,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void amplitudeChanged(qreal amplitude); @@ -71,7 +72,6 @@ void resetAmplitude(); void resetFrequency(); void resetGridSizeLog(); - AkPacket iStream(const AkPacket &packet); }; #endif // DISTORTELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Dizzy/src/dizzyelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Dizzy/src/dizzyelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Dizzy/src/dizzyelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Dizzy/src/dizzyelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include "dizzyelement.h" @@ -80,6 +82,49 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket DizzyElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + oFrame.fill(0); + + if (this->d->m_prevFrame.isNull()) { + this->d->m_prevFrame = QImage(src.size(), src.format()); + this->d->m_prevFrame.fill(0); + } + + qreal pts = 2 * M_PI * packet.pts() * packet.timeBase().value() + / this->d->m_speed; + + qreal angle = (2 * M_PI / 180) * sin(pts) + (M_PI / 180) * sin(pts + 2.5); + qreal scale = 1.0 + this->d->m_zoomRate; + + QTransform transform; + transform.scale(scale, scale); + transform.rotateRadians(angle); + this->d->m_prevFrame = this->d->m_prevFrame.transformed(transform); + + QRect rect(this->d->m_prevFrame.rect()); + rect.moveCenter(oFrame.rect().center()); + + QPainter painter; + painter.begin(&oFrame); + painter.drawImage(rect, this->d->m_prevFrame); + painter.setOpacity(1.0 - this->d->m_strength); + painter.drawImage(0, 0, src); + painter.end(); + + this->d->m_prevFrame = oFrame; + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void DizzyElement::setSpeed(qreal speed) { if (qFuzzyCompare(this->d->m_speed, speed)) @@ -122,48 +167,4 @@ this->setStrength(0.15); } -AkPacket DizzyElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - oFrame.fill(0); - - if (this->d->m_prevFrame.isNull()) { - this->d->m_prevFrame = QImage(src.size(), src.format()); - this->d->m_prevFrame.fill(0); - } - - qreal pts = 2 * M_PI * packet.pts() * packet.timeBase().value() - / this->d->m_speed; - - qreal angle = (2 * M_PI / 180) * sin(pts) + (M_PI / 180) * sin(pts + 2.5); - qreal scale = 1.0 + this->d->m_zoomRate; - - QTransform transform; - transform.scale(scale, scale); - transform.rotateRadians(angle); - this->d->m_prevFrame = this->d->m_prevFrame.transformed(transform); - - QRect rect(this->d->m_prevFrame.rect()); - rect.moveCenter(oFrame.rect().center()); - - QPainter painter; - painter.begin(&oFrame); - painter.drawImage(rect, this->d->m_prevFrame); - painter.setOpacity(1.0 - this->d->m_strength); - painter.drawImage(0, 0, src); - painter.end(); - - this->d->m_prevFrame = oFrame; - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_dizzyelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Dizzy/src/dizzyelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Dizzy/src/dizzyelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Dizzy/src/dizzyelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Dizzy/src/dizzyelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -58,6 +58,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void speedChanged(qreal speed); @@ -71,7 +72,6 @@ void resetSpeed(); void resetZoomRate(); void resetStrength(); - AkPacket iStream(const AkPacket &packet); }; #endif // DIZZYELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Edge/src/edgeelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Edge/src/edgeelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Edge/src/edgeelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Edge/src/edgeelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "edgeelement.h" @@ -109,6 +110,72 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket EdgeElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_Grayscale8); + QImage oFrame(src.size(), src.format()); + + QVector in; + + if (this->d->m_equalize) + in = this->d->equalize(src); + else { + int videoArea = src.width() * src.height(); + in.resize(videoArea); + memcpy(in.data(), src.constBits(), size_t(videoArea)); + } + + QVector gradient; + QVector direction; + this->d->sobel(src.width(), src.height(), in, gradient, direction); + + if (this->d->m_canny) { + auto thinned = this->d->thinning(src.width(), + src.height(), + gradient, + direction); + + QVector thresholds(2); + thresholds[0] = this->d->m_thLow; + thresholds[1] = this->d->m_thHi; + + QVector colors {0, 127, 255}; + auto thresholded = this->d->threshold(src.width(), + src.height(), + thinned, + thresholds, + colors); + auto canny = this->d->hysteresisThresholding(src.width(), + src.height(), + thresholded); + + for (int y = 0; y < src.height(); y++) { + const quint8 *srcLine = canny.constData() + y * src.width(); + quint8 *dstLine = oFrame.scanLine(y); + + for (int x = 0; x < src.width(); x++) + dstLine[x] = this->d->m_invert? 255 - srcLine[x]: srcLine[x]; + } + } else + for (int y = 0; y < src.height(); y++) { + const quint16 *srcLine = gradient.constData() + y * src.width(); + quint8 *dstLine = oFrame.scanLine(y); + + for (int x = 0; x < src.width(); x++) { + int gray = qBound(0, srcLine[x], 255); + dstLine[x] = this->d->m_invert? quint8(255 - gray): quint8(gray); + } + } + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void EdgeElement::setCanny(bool canny) { if (this->d->m_canny == canny) @@ -179,76 +246,6 @@ this->setInvert(false); } -AkPacket EdgeElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_Grayscale8); - QImage oFrame(src.size(), src.format()); - - QVector in; - - if (this->d->m_equalize) - in = this->d->equalize(src); - else { - int videoArea = src.width() * src.height(); - in.resize(videoArea); - memcpy(in.data(), src.constBits(), size_t(videoArea)); - } - - QVector gradient; - QVector direction; - this->d->sobel(src.width(), src.height(), in, gradient, direction); - - if (this->d->m_canny) { - auto thinned = this->d->thinning(src.width(), - src.height(), - gradient, - direction); - - QVector thresholds(2); - thresholds[0] = this->d->m_thLow; - thresholds[1] = this->d->m_thHi; - - QVector colors(3); - colors[0] = 0; - colors[1] = 127; - colors[2] = 255; - auto thresholded = this->d->threshold(src.width(), - src.height(), - thinned, - thresholds, - colors); - auto canny = this->d->hysteresisThresholding(src.width(), - src.height(), - thresholded); - - for (int y = 0; y < src.height(); y++) { - const quint8 *srcLine = canny.constData() + y * src.width(); - quint8 *dstLine = oFrame.scanLine(y); - - for (int x = 0; x < src.width(); x++) - dstLine[x] = this->d->m_invert? 255 - srcLine[x]: srcLine[x]; - } - } else - for (int y = 0; y < src.height(); y++) { - const quint16 *srcLine = gradient.constData() + y * src.width(); - quint8 *dstLine = oFrame.scanLine(y); - - for (int x = 0; x < src.width(); x++) { - int gray = qBound(0, srcLine[x], 255); - dstLine[x] = this->d->m_invert? quint8(255 - gray): quint8(gray); - } - } - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - QVector EdgeElementPrivate::equalize(const QImage &image) { int videoArea = image.width() * image.height(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Edge/src/edgeelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Edge/src/edgeelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Edge/src/edgeelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Edge/src/edgeelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -70,6 +70,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void cannyChanged(bool canny); @@ -89,7 +90,6 @@ void resetThHi(); void resetEqualize(); void resetInvert(); - AkPacket iStream(const AkPacket &packet); }; #endif // EDGEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Emboss/src/embosselement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Emboss/src/embosselement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Emboss/src/embosselement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Emboss/src/embosselement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "embosselement.h" @@ -67,38 +68,9 @@ context->setContextProperty("controlId", this->objectName()); } -void EmbossElement::setFactor(qreal factor) -{ - if (qFuzzyCompare(this->d->m_factor, factor)) - return; - - this->d->m_factor = factor; - emit this->factorChanged(factor); -} - -void EmbossElement::setBias(qreal bias) -{ - if (qFuzzyCompare(this->d->m_bias, bias)) - return; - - this->d->m_bias = bias; - emit this->biasChanged(bias); -} - -void EmbossElement::resetFactor() -{ - this->setFactor(1); -} - -void EmbossElement::resetBias() -{ - this->setBias(128); -} - -AkPacket EmbossElement::iStream(const AkPacket &packet) +AkPacket EmbossElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -143,8 +115,36 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void EmbossElement::setFactor(qreal factor) +{ + if (qFuzzyCompare(this->d->m_factor, factor)) + return; + + this->d->m_factor = factor; + emit this->factorChanged(factor); +} + +void EmbossElement::setBias(qreal bias) +{ + if (qFuzzyCompare(this->d->m_bias, bias)) + return; + + this->d->m_bias = bias; + emit this->biasChanged(bias); +} + +void EmbossElement::resetFactor() +{ + this->setFactor(1); +} + +void EmbossElement::resetBias() +{ + this->setBias(128); +} + #include "moc_embosselement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Emboss/src/embosselement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Emboss/src/embosselement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Emboss/src/embosselement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Emboss/src/embosselement.h 2021-02-15 15:25:23.000000000 +0000 @@ -52,6 +52,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void factorChanged(qreal factor); @@ -62,7 +63,6 @@ void setBias(qreal bias); void resetFactor(); void resetBias(); - AkPacket iStream(const AkPacket &packet); }; #endif // EmbossELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Equalize/src/equalizeelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Equalize/src/equalizeelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Equalize/src/equalizeelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Equalize/src/equalizeelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include "equalizeelement.h" @@ -37,21 +38,20 @@ { } -AkPacket EqualizeElement::iStream(const AkPacket &packet) +AkPacket EqualizeElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); src = src.convertToFormat(QImage::Format_ARGB32); QImage oFrame(src.size(), src.format()); - QVector equTable = EqualizeElementPrivate::equalizationTable(src); + auto equTable = EqualizeElementPrivate::equalizationTable(src); for (int y = 0; y < src.height(); y++) { - const QRgb *srcLine = reinterpret_cast(src.constScanLine(y)); - QRgb *dstLine = reinterpret_cast(oFrame.scanLine(y)); + auto srcLine = reinterpret_cast(src.constScanLine(y)); + auto dstLine = reinterpret_cast(oFrame.scanLine(y)); for (int x = 0; x < src.width(); x++){ int r = equTable[qRed(srcLine[x])]; @@ -63,7 +63,7 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } @@ -72,7 +72,7 @@ QVector histogram(256, 0); for (int y = 0; y < img.height(); y++) { - const QRgb *srcLine = reinterpret_cast(img.constScanLine(y)); + auto srcLine = reinterpret_cast(img.constScanLine(y)); for (int x = 0; x < img.width(); x++) histogram[qGray(srcLine[x])]++; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Equalize/src/equalizeelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Equalize/src/equalizeelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Equalize/src/equalizeelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Equalize/src/equalizeelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -29,8 +29,8 @@ public: EqualizeElement(); - public slots: - AkPacket iStream(const AkPacket &packet); + protected: + AkPacket iVideoStream(const AkVideoPacket &packet); }; #endif // EQUALIZEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Equalize/src/pixelstructs.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Equalize/src/pixelstructs.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Equalize/src/pixelstructs.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Equalize/src/pixelstructs.h 2021-02-15 15:25:23.000000000 +0000 @@ -25,17 +25,17 @@ template struct Pixel { - Pixel(): - r(0), g(0), b(0), a(0) - { - } + T r; + T g; + T b; + T a; - Pixel(T red, T green, T blue, T alpha): + inline Pixel(T red=0, T green=0, T blue=0, T alpha=0): r(red), g(green), b(blue), a(alpha) { } - Pixel operator +(const Pixel &other) + inline Pixel operator +(const Pixel &other) { return Pixel(this->r + other.r, this->g + other.g, @@ -43,25 +43,20 @@ this->a + other.a); } - void clear() + inline void clear() { this->r = 0; this->g = 0; this->b = 0; this->a = 0; } - - T r; - T g; - T b; - T a; }; // These are used as accumulators -typedef struct Pixel Integer64Pixel; -typedef struct Pixel IntegerPixel; -typedef struct Pixel ShortPixel; -typedef struct Pixel CharPixel; +typedef Pixel Integer64Pixel; +typedef Pixel IntegerPixel; +typedef Pixel ShortPixel; +typedef Pixel CharPixel; typedef IntegerPixel HistogramListItem; #endif // PIXELSTRUCTS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/share/qml/main.qml webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/share/qml/main.qml --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/share/qml/main.qml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/share/qml/main.qml 2021-02-15 15:25:23.000000000 +0000 @@ -108,6 +108,7 @@ // Haar file. Label { + //: https://en.wikipedia.org/wiki/Haar-like_feature text: qsTr("Haar file") } ComboBox { @@ -216,6 +217,8 @@ } TextField { text: FaceDetect.scanSize.width + "x" + FaceDetect.scanSize.height + placeholderText: qsTr("Scan block") + selectByMouse: true validator: RegExpValidator { regExp: /\d+x\d+/ } @@ -255,6 +258,10 @@ text: qsTr("Blur") markerType: "blur" } + ListElement { + text: qsTr("Blur Outer") + markerType: "blurouter" + } } onCurrentIndexChanged: FaceDetect.markerType = cbxMarkerType.model.get(currentIndex).markerType @@ -314,12 +321,14 @@ } TextField { text: FaceDetect.markerWidth + placeholderText: qsTr("Marker width") + selectByMouse: true validator: RegExpValidator { regExp: /\d+/ } Layout.fillWidth: true - onTextChanged: FaceDetect.markerWidth = text + onTextChanged: FaceDetect.markerWidth = Number(text) } // Marker picture. @@ -504,7 +513,8 @@ TextField { id: txtTable text: FaceDetect.markerImage - placeholderText: qsTr("Replace face with this picture.") + placeholderText: qsTr("Replace face with this picture") + selectByMouse: true Layout.fillWidth: true onTextChanged: { @@ -536,6 +546,8 @@ } TextField { text: FaceDetect.pixelGridSize.width + "x" + FaceDetect.pixelGridSize.height + placeholderText: qsTr("Pixel grid size") + selectByMouse: true validator: RegExpValidator { regExp: /\d+x\d+/ } @@ -550,12 +562,14 @@ } TextField { text: FaceDetect.blurRadius + placeholderText: qsTr("Blur radius") + selectByMouse: true validator: RegExpValidator { regExp: /\d+/ } Layout.fillWidth: true - onTextChanged: FaceDetect.blurRadius = text + onTextChanged: FaceDetect.blurRadius = Number(text) } FileDialog { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/facedetectelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/facedetectelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/facedetectelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/facedetectelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "facedetectelement.h" @@ -37,7 +38,8 @@ {FaceDetectElement::MarkerTypeEllipse , "ellipse" }, {FaceDetectElement::MarkerTypeImage , "image" }, {FaceDetectElement::MarkerTypePixelate , "pixelate" }, - {FaceDetectElement::MarkerTypeBlur , "blur" } + {FaceDetectElement::MarkerTypeBlur , "blur" }, + {FaceDetectElement::MarkerTypeBlurOuter, "blurouter"} }; return markerTypeToStr; @@ -145,6 +147,23 @@ return this->d->m_scanSize; } +QVector FaceDetectElement::detectFaces(const AkVideoPacket &packet) +{ + QSize scanSize(this->d->m_scanSize); + + if (this->d->m_haarFile.isEmpty() || scanSize.isEmpty()) + return {}; + + auto src = packet.toImage(); + + if (src.isNull()) + return {}; + + QImage scanFrame(src.scaled(scanSize, Qt::KeepAspectRatio)); + + return this->d->m_cascadeClassifier.detect(scanFrame); +} + QString FaceDetectElement::controlInterfaceProvide(const QString &controlId) const { Q_UNUSED(controlId) @@ -164,6 +183,95 @@ context->setContextProperty("picturesPath", picturesPath[0]); } +AkPacket FaceDetectElement::iVideoStream(const AkVideoPacket &packet) +{ + QSize scanSize(this->d->m_scanSize); + + if (this->d->m_haarFile.isEmpty() + || scanSize.isEmpty()) + akSend(packet) + + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + QImage oFrame = src.convertToFormat(QImage::Format_ARGB32); + qreal scale = 1; + + QImage scanFrame(src.scaled(scanSize, Qt::KeepAspectRatio)); + + if (scanFrame.width() == scanSize.width()) + scale = qreal(src.width()) / scanSize.width(); + else + scale = qreal(src.height()) / scanSize.height(); + + this->d->m_cascadeClassifier.setEqualize(true); + QVector vecFaces = this->d->m_cascadeClassifier.detect(scanFrame); + + if (vecFaces.isEmpty()) + akSend(packet) + + QPainter painter; + painter.begin(&oFrame); + + /* Many users will want to blur even if no faces were detected! */ + if (this->d->m_markerType == MarkerTypeBlurOuter) { + QRect all(0, 0, src.width(), src.height()); + auto rectPacket = AkVideoPacket::fromImage(src.copy(all), packet); + AkVideoPacket blurPacket = this->d->m_blurFilter->iStream(rectPacket); + auto blurImage = blurPacket.toImage(); + painter.drawImage(all, blurImage); + /* for a better effect, we could add a second (weaker) blur */ + /* and copy this to larger boxes around all faces */ + } + + for (auto &face: vecFaces) { + QRect rect(int(scale * face.x()), + int(scale * face.y()), + int(scale * face.width()), + int(scale * face.height())); + + if (this->d->m_markerType == MarkerTypeRectangle) { + painter.setPen(this->d->m_markerPen); + painter.drawRect(rect); + } else if (this->d->m_markerType == MarkerTypeEllipse) { + painter.setPen(this->d->m_markerPen); + painter.drawEllipse(rect); + } else if (this->d->m_markerType == MarkerTypeImage) + painter.drawImage(rect, this->d->m_markerImg); + else if (this->d->m_markerType == MarkerTypePixelate) { + qreal sw = 1.0 / this->d->m_pixelGridSize.width(); + qreal sh = 1.0 / this->d->m_pixelGridSize.height(); + QImage imagePixelate = src.copy(rect); + + imagePixelate = imagePixelate.scaled(int(sw * imagePixelate.width()), + int(sh * imagePixelate.height()), + Qt::IgnoreAspectRatio, + Qt::FastTransformation) + .scaled(imagePixelate.width(), + imagePixelate.height(), + Qt::IgnoreAspectRatio, + Qt::FastTransformation); + + painter.drawImage(rect, imagePixelate); + } else if (this->d->m_markerType == MarkerTypeBlur) { + auto rectPacket = AkVideoPacket::fromImage(src.copy(rect), packet); + AkVideoPacket blurPacket = this->d->m_blurFilter->iStream(rectPacket); + auto blurImage = blurPacket.toImage(); + + painter.drawImage(rect, blurImage); + } else if (this->d->m_markerType == MarkerTypeBlurOuter) { + painter.drawImage(rect, src.copy(rect)); + } + } + + painter.end(); + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void FaceDetectElement::setHaarFile(const QString &haarFile) { if (this->d->m_haarFile == haarFile) @@ -180,7 +288,7 @@ void FaceDetectElement::setMarkerType(const QString &markerType) { - MarkerType markerTypeEnum = markerTypeToStr->key(markerType, MarkerTypeRectangle); + auto markerTypeEnum = markerTypeToStr->key(markerType, MarkerTypeRectangle); if (this->d->m_markerType == markerTypeEnum) return; @@ -303,81 +411,4 @@ this->setScanSize(QSize(160, 120)); } -AkPacket FaceDetectElement::iStream(const AkPacket &packet) -{ - QSize scanSize(this->d->m_scanSize); - - if (this->d->m_haarFile.isEmpty() - || scanSize.isEmpty()) - akSend(packet) - - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - QImage oFrame = src.convertToFormat(QImage::Format_ARGB32); - qreal scale = 1; - - QImage scanFrame(src.scaled(scanSize, Qt::KeepAspectRatio)); - - if (scanFrame.width() == scanSize.width()) - scale = qreal(src.width()) / scanSize.width(); - else - scale = qreal(src.height()) / scanSize.height(); - - this->d->m_cascadeClassifier.setEqualize(true); - QVector vecFaces = this->d->m_cascadeClassifier.detect(scanFrame); - - if (vecFaces.isEmpty()) - akSend(packet) - - QPainter painter; - painter.begin(&oFrame); - - for (const QRect &face: vecFaces) { - QRect rect(int(scale * face.x()), - int(scale * face.y()), - int(scale * face.width()), - int(scale * face.height())); - - if (this->d->m_markerType == MarkerTypeRectangle) { - painter.setPen(this->d->m_markerPen); - painter.drawRect(rect); - } else if (this->d->m_markerType == MarkerTypeEllipse) { - painter.setPen(this->d->m_markerPen); - painter.drawEllipse(rect); - } else if (this->d->m_markerType == MarkerTypeImage) - painter.drawImage(rect, this->d->m_markerImg); - else if (this->d->m_markerType == MarkerTypePixelate) { - qreal sw = 1.0 / this->d->m_pixelGridSize.width(); - qreal sh = 1.0 / this->d->m_pixelGridSize.height(); - QImage imagePixelate = src.copy(rect); - - imagePixelate = imagePixelate.scaled(int(sw * imagePixelate.width()), - int(sh * imagePixelate.height()), - Qt::IgnoreAspectRatio, - Qt::FastTransformation) - .scaled(imagePixelate.width(), - imagePixelate.height(), - Qt::IgnoreAspectRatio, - Qt::FastTransformation); - - painter.drawImage(rect, imagePixelate); - } else if (this->d->m_markerType == MarkerTypeBlur) { - auto rectPacket = AkVideoPacket::fromImage(src.copy(rect), videoPacket); - AkVideoPacket blurPacket = this->d->m_blurFilter->iStream(rectPacket.toPacket()); - auto blurImage = blurPacket.toImage(); - - painter.drawImage(rect, blurImage); - } - } - - painter.end(); - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_facedetectelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/facedetectelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/facedetectelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/facedetectelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/facedetectelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -82,7 +82,8 @@ MarkerTypeEllipse, MarkerTypeImage, MarkerTypePixelate, - MarkerTypeBlur + MarkerTypeBlur, + MarkerTypeBlurOuter }; FaceDetectElement(); @@ -97,6 +98,7 @@ Q_INVOKABLE QSize pixelGridSize() const; Q_INVOKABLE int blurRadius() const; Q_INVOKABLE QSize scanSize() const; + Q_INVOKABLE QVector detectFaces(const AkVideoPacket &packet); private: FaceDetectElementPrivate *d; @@ -105,6 +107,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void haarFileChanged(const QString &haarFile); @@ -136,7 +139,6 @@ void resetPixelGridSize(); void resetBlurRadius(); void resetScanSize(); - AkPacket iStream(const AkPacket &packet); }; #endif // FACEDETECTELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarcascade.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarcascade.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarcascade.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarcascade.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -295,7 +295,8 @@ while (!haarReader.atEnd()) { auto token = haarReader.readNext(); - if (token == QXmlStreamReader::Invalid) { + switch (token) { + case QXmlStreamReader::Invalid: { if (this->m_errorString != haarReader.errorString()) { this->m_errorString = haarReader.errorString(); emit this->errorStringChanged(haarReader.errorString()); @@ -304,7 +305,7 @@ return false; } - if (token == QXmlStreamReader::StartElement) { + case QXmlStreamReader::StartElement: { pathList << haarReader.name().toString(); if (path.isEmpty() && haarReader.name() != "opencv_storage") @@ -323,7 +324,11 @@ && haarReader.name() == "_") { this->m_stages.last().trees().last().features() << HaarFeature(); } - } else if (token == QXmlStreamReader::EndElement) { + + break; + } + + case QXmlStreamReader::EndElement: { if (path == QString("opencv_storage/%1/stages/_").arg(this->m_name)) { int parent = this->m_stages.last().parentStage(); @@ -342,7 +347,11 @@ } pathList.removeLast(); - } else if (token == QXmlStreamReader::Characters) { + + break; + } + + case QXmlStreamReader::Characters: { if (path == QString("opencv_storage/%1/size").arg(this->m_name)) { QStringList sizeStr = haarReader.text().toString().simplified().split(" "); QSize size(sizeStr[0].toInt(), sizeStr[1].toInt()); @@ -374,6 +383,12 @@ } else if (path == QString("opencv_storage/%1/stages/_/trees/_/_/feature/tilted").arg(this->m_name)) this->m_stages.last().trees().last().features().last().tilted() = haarReader.text().toInt(); + + break; + } + + default: + break; } path = pathList.join("/"); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarfeature.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarfeature.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarfeature.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarfeature.h 2021-02-15 15:25:23.000000000 +0000 @@ -28,9 +28,9 @@ class HaarFeature; -typedef QVector RectVector; -typedef QVector RealVector; -typedef QVector HaarFeatureVector; +using RectVector = QVector; +using RealVector = QVector; +using HaarFeatureVector = QVector; class HaarFeatureHID { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarstage.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarstage.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarstage.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haarstage.h 2021-02-15 15:25:23.000000000 +0000 @@ -24,7 +24,7 @@ class HaarStage; -typedef QVector HaarStageVector; +using HaarStageVector = QVector; class HaarStageHID { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haartree.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haartree.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haartree.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FaceDetect/src/haar/haartree.h 2021-02-15 15:25:23.000000000 +0000 @@ -24,7 +24,7 @@ class HaarTree; -typedef QVector HaarTreeVector; +using HaarTreeVector = QVector; class HaarTreeHID { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FalseColor/src/falsecolorelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/FalseColor/src/falsecolorelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FalseColor/src/falsecolorelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FalseColor/src/falsecolorelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include "falsecolorelement.h" @@ -77,53 +79,12 @@ context->setContextProperty("controlId", this->objectName()); } -void FalseColorElement::setTable(const QVariantList &table) -{ - QList tableRgb; - - for (const QVariant &color: table) - tableRgb << color.value(); - - if (this->d->m_table == tableRgb) - return; - - this->d->m_table = tableRgb; - emit this->tableChanged(table); -} - -void FalseColorElement::setSoft(bool soft) -{ - if (this->d->m_soft == soft) - return; - - this->d->m_soft = soft; - emit this->softChanged(soft); -} - -void FalseColorElement::resetTable() -{ - static const QVariantList table = { - qRgb(0, 0, 0), - qRgb(255, 0, 0), - qRgb(255, 255, 255), - qRgb(255, 255, 255) - }; - - this->setTable(table); -} - -void FalseColorElement::resetSoft() -{ - this->setSoft(false); -} - -AkPacket FalseColorElement::iStream(const AkPacket &packet) +AkPacket FalseColorElement::iVideoStream(const AkVideoPacket &packet) { if (this->d->m_table.isEmpty()) akSend(packet) - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -181,8 +142,48 @@ dstLine[x] = table[srcLine[x]]; } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void FalseColorElement::setTable(const QVariantList &table) +{ + QList tableRgb; + + for (const QVariant &color: table) + tableRgb << color.value(); + + if (this->d->m_table == tableRgb) + return; + + this->d->m_table = tableRgb; + emit this->tableChanged(table); +} + +void FalseColorElement::setSoft(bool soft) +{ + if (this->d->m_soft == soft) + return; + + this->d->m_soft = soft; + emit this->softChanged(soft); +} + +void FalseColorElement::resetTable() +{ + static const QVariantList table = { + qRgb(0, 0, 0), + qRgb(255, 0, 0), + qRgb(255, 255, 255), + qRgb(255, 255, 255) + }; + + this->setTable(table); +} + +void FalseColorElement::resetSoft() +{ + this->setSoft(false); +} + #include "moc_falsecolorelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FalseColor/src/falsecolorelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/FalseColor/src/falsecolorelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FalseColor/src/falsecolorelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FalseColor/src/falsecolorelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -52,6 +52,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void tableChanged(const QVariantList &table); @@ -62,7 +63,6 @@ void setSoft(bool soft); void resetTable(); void resetSoft(); - AkPacket iStream(const AkPacket &packet); }; #endif // FALSECOLORELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Fire/src/fireelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Fire/src/fireelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Fire/src/fireelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Fire/src/fireelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,11 +17,14 @@ * Web-Site: http://webcamoid.github.io/ */ -#include +#include #include #include #include +#include +#include #include +#include #include #include "fireelement.h" @@ -156,7 +159,7 @@ for (int y = 0; y < height; y++) { auto iLine1 = reinterpret_cast(img1.constScanLine(y)); auto iLine2 = reinterpret_cast(img2.constScanLine(y)); - QRgb *oLine = reinterpret_cast(diff.scanLine(y)); + auto oLine = reinterpret_cast(diff.scanLine(y)); for (int x = 0; x < width; x++) { int r1 = qRed(iLine1[x]); @@ -178,14 +181,11 @@ alpha = alpha < threshold? 0: alpha; else alpha = alpha < threshold? - 0: (256 - alphaVariation) - + qrand() % alphaVariation; + 0: QRandomGenerator::global()->bounded(255 - alphaVariation, 256); int gray = qGray(iLine2[x]); - alpha = gray < lumaThreshold? 0: alpha; - int b = (256 - colors) + qrand() % colors; - + int b = QRandomGenerator::global()->bounded(255 - colors, 256); oLine[x] = qRgba(0, 0, b, alpha); } } @@ -214,7 +214,7 @@ void FireElementPrivate::coolImage(QImage &src, int colorDiff) { for (int y = 0; y < src.height(); y++) { - QRgb *srcLine = reinterpret_cast(src.scanLine(y)); + auto srcLine = reinterpret_cast(src.scanLine(y)); for (int x = 0; x < src.width(); x++) { int b = qBound(0, qBlue(srcLine[x]) + colorDiff, 255); @@ -226,7 +226,7 @@ void FireElementPrivate::imageAlphaDiff(QImage &src, int alphaDiff) { for (int y = 0; y < src.height(); y++) { - QRgb *srcLine = reinterpret_cast(src.scanLine(y)); + auto srcLine = reinterpret_cast(src.scanLine(y)); for (int x = 0; x < src.width(); x++) { QRgb pixel = srcLine[x]; @@ -240,15 +240,14 @@ void FireElementPrivate::dissolveImage(QImage &src, qreal amount) { qint64 videoArea = src.width() * src.height(); - auto n = qint64(amount * videoArea); + auto n = qRound64(amount * videoArea); for (qint64 i = 0; i < n; i++) { - int x = qrand() % src.width(); - int y = qrand() % src.height(); + int x = QRandomGenerator::global()->bounded(src.width()); + int y = QRandomGenerator::global()->bounded(src.height()); QRgb pixel = src.pixel(x, y); int b = qBlue(pixel); - int a = qAlpha(pixel) < 1? 0: qrand() % qAlpha(pixel); - + int a = QRandomGenerator::global()->bounded(qAlpha(pixel) + 1); src.setPixel(x, y, qRgba(0, 0, b, a)); } } @@ -258,8 +257,8 @@ QImage dest(src.size(), src.format()); for (int y = 0; y < src.height(); y++) { - const QRgb *srcLine = reinterpret_cast(src.constScanLine(y)); - QRgb *dstLine = reinterpret_cast(dest.scanLine(y)); + auto srcLine = reinterpret_cast(src.constScanLine(y)); + auto dstLine = reinterpret_cast(dest.scanLine(y)); for (int x = 0; x < src.width(); x++) { int index = qBlue(srcLine[x]); @@ -307,6 +306,70 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket FireElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + if (src.size() != this->d->m_framSize) { + this->d->m_fireBuffer = QImage(); + this->d->m_prevFrame = QImage(); + this->d->m_framSize = src.size(); + } + + if (this->d->m_prevFrame.isNull()) { + oFrame = src; + this->d->m_fireBuffer = QImage(src.size(), src.format()); + this->d->m_fireBuffer.fill(qRgba(0, 0, 0, 0)); + } else { + this->d->m_fireBuffer = this->d->zoomImage(this->d->m_fireBuffer, + this->d->m_zoom); + this->d->coolImage(this->d->m_fireBuffer, this->d->m_cool); + this->d->imageAlphaDiff(this->d->m_fireBuffer, this->d->m_alphaDiff); + this->d->dissolveImage(this->d->m_fireBuffer, this->d->m_dissolve); + + int nColors = this->d->m_nColors > 0? this->d->m_nColors: 1; + + // Compute the difference between previous and current frame, + // and save it to the buffer. + QImage diff = + this->d->imageDiff(this->d->m_prevFrame, + src, + nColors, + this->d->m_threshold, + this->d->m_lumaThreshold, + this->d->m_alphaVariation, + this->d->m_mode); + + QPainter painter; + painter.begin(&this->d->m_fireBuffer); + painter.drawImage(0, 0, diff); + painter.end(); + + auto firePacket = AkVideoPacket::fromImage(this->d->m_fireBuffer, + packet); + auto blurPacket = this->d->m_blurFilter->iStream(firePacket); + this->d->m_fireBuffer = AkVideoPacket(blurPacket).toImage(); + + // Apply buffer. + painter.begin(&oFrame); + painter.drawImage(0, 0, src); + painter.drawImage(0, 0, this->d->burn(this->d->m_fireBuffer, + this->d->m_palette)); + painter.end(); + } + + this->d->m_prevFrame = src.copy(); + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void FireElement::setMode(const QString &mode) { FireMode modeEnum = fireModeToStr->key(mode, FireModeHard); @@ -445,69 +508,4 @@ this->setNColors(8); } -AkPacket FireElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - if (src.size() != this->d->m_framSize) { - this->d->m_fireBuffer = QImage(); - this->d->m_prevFrame = QImage(); - this->d->m_framSize = src.size(); - } - - if (this->d->m_prevFrame.isNull()) { - oFrame = src; - this->d->m_fireBuffer = QImage(src.size(), src.format()); - this->d->m_fireBuffer.fill(qRgba(0, 0, 0, 0)); - } else { - this->d->m_fireBuffer = this->d->zoomImage(this->d->m_fireBuffer, - this->d->m_zoom); - this->d->coolImage(this->d->m_fireBuffer, this->d->m_cool); - this->d->imageAlphaDiff(this->d->m_fireBuffer, this->d->m_alphaDiff); - this->d->dissolveImage(this->d->m_fireBuffer, this->d->m_dissolve); - - int nColors = this->d->m_nColors > 0? this->d->m_nColors: 1; - - // Compute the difference between previous and current frame, - // and save it to the buffer. - QImage diff = - this->d->imageDiff(this->d->m_prevFrame, - src, - nColors, - this->d->m_threshold, - this->d->m_lumaThreshold, - this->d->m_alphaVariation, - this->d->m_mode); - - QPainter painter; - painter.begin(&this->d->m_fireBuffer); - painter.drawImage(0, 0, diff); - painter.end(); - - auto firePacket = AkVideoPacket::fromImage(this->d->m_fireBuffer, - videoPacket); - auto blurPacket = this->d->m_blurFilter->iStream(firePacket.toPacket()); - this->d->m_fireBuffer = AkVideoPacket(blurPacket).toImage(); - - // Apply buffer. - painter.begin(&oFrame); - painter.drawImage(0, 0, src); - painter.drawImage(0, 0, this->d->burn(this->d->m_fireBuffer, - this->d->m_palette)); - painter.end(); - } - - this->d->m_prevFrame = src.copy(); - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_fireelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Fire/src/fireelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Fire/src/fireelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Fire/src/fireelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Fire/src/fireelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -107,6 +107,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void modeChanged(const QString &mode); @@ -141,7 +142,6 @@ void resetAlphaDiff(); void resetAlphaVariation(); void resetNColors(); - AkPacket iStream(const AkPacket &packet); }; #endif // FIREELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FrameOverlap/src/frameoverlapelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/FrameOverlap/src/frameoverlapelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FrameOverlap/src/frameoverlapelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FrameOverlap/src/frameoverlapelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include "frameoverlapelement.h" @@ -68,38 +69,9 @@ context->setContextProperty("controlId", this->objectName()); } -void FrameOverlapElement::setNFrames(int nFrames) -{ - if (this->d->m_nFrames == nFrames) - return; - - this->d->m_nFrames = nFrames; - emit this->nFramesChanged(nFrames); -} - -void FrameOverlapElement::setStride(int stride) -{ - if (this->d->m_stride == stride) - return; - - this->d->m_stride = stride; - emit this->strideChanged(stride); -} - -void FrameOverlapElement::resetNFrames() -{ - this->setNFrames(16); -} - -void FrameOverlapElement::resetStride() -{ - this->setStride(4); -} - -AkPacket FrameOverlapElement::iStream(const AkPacket &packet) +AkPacket FrameOverlapElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -155,8 +127,36 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void FrameOverlapElement::setNFrames(int nFrames) +{ + if (this->d->m_nFrames == nFrames) + return; + + this->d->m_nFrames = nFrames; + emit this->nFramesChanged(nFrames); +} + +void FrameOverlapElement::setStride(int stride) +{ + if (this->d->m_stride == stride) + return; + + this->d->m_stride = stride; + emit this->strideChanged(stride); +} + +void FrameOverlapElement::resetNFrames() +{ + this->setNFrames(16); +} + +void FrameOverlapElement::resetStride() +{ + this->setStride(4); +} + #include "moc_frameoverlapelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/FrameOverlap/src/frameoverlapelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/FrameOverlap/src/frameoverlapelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/FrameOverlap/src/frameoverlapelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/FrameOverlap/src/frameoverlapelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -52,6 +52,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void nFramesChanged(int nFrames); @@ -62,7 +63,6 @@ void setStride(int stride); void resetNFrames(); void resetStride(); - AkPacket iStream(const AkPacket &packet); }; #endif // FRAMEOVERLAPELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/GrayScale/src/grayscaleelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/GrayScale/src/grayscaleelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/GrayScale/src/grayscaleelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/GrayScale/src/grayscaleelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -18,6 +18,7 @@ */ #include +#include #include #include "grayscaleelement.h" @@ -26,11 +27,9 @@ { } -AkPacket GrayScaleElement::iStream(const AkPacket &packet) +AkPacket GrayScaleElement::iVideoStream(const AkVideoPacket &packet) { - auto oPacket = AkVideoPacket(packet) - .convert(AkVideoCaps::Format_gray) - .toPacket();; + auto oPacket = packet.convert(AkVideoCaps::Format_gray); akSend(oPacket) } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/GrayScale/src/grayscaleelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/GrayScale/src/grayscaleelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/GrayScale/src/grayscaleelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/GrayScale/src/grayscaleelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -29,8 +29,8 @@ public: GrayScaleElement(); - public slots: - AkPacket iStream(const AkPacket &packet); + protected: + AkPacket iVideoStream(const AkVideoPacket &packet); }; #endif // GRAYSCALEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Halftone/src/halftoneelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Halftone/src/halftoneelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Halftone/src/halftoneelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Halftone/src/halftoneelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "halftoneelement.h" @@ -106,6 +107,62 @@ context->setContextProperty("picturesPath", picturesPath[0]); } +AkPacket HalftoneElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + this->d->m_mutex.lock(); + + if (this->d->m_patternImage.isNull()) { + this->d->m_mutex.unlock(); + akSend(packet) + } + + QImage patternImage = this->d->m_patternImage.copy(); + this->d->m_mutex.unlock(); + + // filter image + for (int y = 0; y < src.height(); y++) { + const QRgb *iLine = reinterpret_cast(src.constScanLine(y)); + QRgb *oLine = reinterpret_cast(oFrame.scanLine(y)); + + for (int x = 0; x < src.width(); x++) { + int col = x % patternImage.width(); + int row = y % patternImage.height(); + + int gray = qGray(iLine[x]); + auto pattern = reinterpret_cast(patternImage.constScanLine(row)); + int threshold = pattern[col]; + threshold = int(this->d->m_slope + * threshold + + this->d->m_intercept); + threshold = qBound(0, threshold, 255); + + if (gray > threshold) + oLine[x] = iLine[x]; + else { + QColor color(iLine[x]); + + color.setHsl(color.hue(), + color.saturation(), + int(this->d->m_lightness * color.lightness()), + color.alpha()); + + oLine[x] = color.rgba(); + } + } + } + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void HalftoneElement::setPattern(const QString &pattern) { if (this->d->m_pattern == pattern) @@ -176,63 +233,6 @@ this->setIntercept(0.0); } -AkPacket HalftoneElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - this->d->m_mutex.lock(); - - if (this->d->m_patternImage.isNull()) { - this->d->m_mutex.unlock(); - akSend(packet) - } - - QImage patternImage = this->d->m_patternImage.copy(); - this->d->m_mutex.unlock(); - - // filter image - for (int y = 0; y < src.height(); y++) { - const QRgb *iLine = reinterpret_cast(src.constScanLine(y)); - QRgb *oLine = reinterpret_cast(oFrame.scanLine(y)); - - for (int x = 0; x < src.width(); x++) { - int col = x % patternImage.width(); - int row = y % patternImage.height(); - - int gray = qGray(iLine[x]); - auto pattern = reinterpret_cast(patternImage.constScanLine(row)); - int threshold = pattern[col]; - threshold = int(this->d->m_slope - * threshold - + this->d->m_intercept); - threshold = qBound(0, threshold, 255); - - if (gray > threshold) - oLine[x] = iLine[x]; - else { - QColor color(iLine[x]); - - color.setHsl(color.hue(), - color.saturation(), - int(this->d->m_lightness * color.lightness()), - color.alpha()); - - oLine[x] = color.rgba(); - } - } - } - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - void HalftoneElementPrivate::updatePattern() { if (this->m_pattern.isEmpty()) { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Halftone/src/halftoneelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Halftone/src/halftoneelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Halftone/src/halftoneelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Halftone/src/halftoneelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -70,6 +70,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void patternChanged(const QString &pattern); @@ -89,7 +90,6 @@ void resetLightness(); void resetSlope(); void resetIntercept(); - AkPacket iStream(const AkPacket &packet); }; #endif // HALFTONEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Hypnotic/src/hypnoticelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Hypnotic/src/hypnoticelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Hypnotic/src/hypnoticelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Hypnotic/src/hypnoticelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "hypnoticelement.h" @@ -181,6 +182,45 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket HypnoticElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + if (src.size() != this->d->m_frameSize) { + this->d->m_speed = 16; + this->d->m_phase = 0; + this->d->m_opticalMap = this->d->createOpticalMap(src.size()); + this->d->m_frameSize = src.size(); + } + + QImage opticalMap = + this->d->m_opticalMap.value(this->d->m_mode, + this->d->m_opticalMap[OpticModeSpiral1]); + + this->d->m_speed += this->d->m_speedInc; + this->d->m_phase -= this->d->m_speed; + + QImage diff = this->d->imageThreshold(src, this->d->m_threshold); + + for (int i = 0, y = 0; y < src.height(); y++) { + QRgb *oLine = reinterpret_cast(oFrame.scanLine(y)); + auto optLine = opticalMap.constScanLine(y); + auto diffLine = diff.constScanLine(y); + + for (int x = 0; x < src.width(); i++, x++) + oLine[x] = this->d->m_palette[((char(optLine[x] + this->d->m_phase)) ^ diffLine[x]) & 255]; + } + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void HypnoticElement::setMode(const QString &mode) { OpticMode opticMode = opticModeToStr->key(mode, OpticModeSpiral1); @@ -225,44 +265,4 @@ this->setThreshold(127); } -AkPacket HypnoticElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - if (src.size() != this->d->m_frameSize) { - this->d->m_speed = 16; - this->d->m_phase = 0; - this->d->m_opticalMap = this->d->createOpticalMap(src.size()); - this->d->m_frameSize = src.size(); - } - - QImage opticalMap = - this->d->m_opticalMap.value(this->d->m_mode, - this->d->m_opticalMap[OpticModeSpiral1]); - - this->d->m_speed += this->d->m_speedInc; - this->d->m_phase -= this->d->m_speed; - - QImage diff = this->d->imageThreshold(src, this->d->m_threshold); - - for (int i = 0, y = 0; y < src.height(); y++) { - QRgb *oLine = reinterpret_cast(oFrame.scanLine(y)); - auto optLine = opticalMap.constScanLine(y); - auto diffLine = diff.constScanLine(y); - - for (int x = 0; x < src.width(); i++, x++) - oLine[x] = this->d->m_palette[((char(optLine[x] + this->d->m_phase)) ^ diffLine[x]) & 255]; - } - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_hypnoticelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Hypnotic/src/hypnoticelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Hypnotic/src/hypnoticelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Hypnotic/src/hypnoticelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Hypnotic/src/hypnoticelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -67,6 +67,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void modeChanged(const QString &mode); @@ -80,7 +81,6 @@ void resetMode(); void resetSpeedInc(); void resetThreshold(); - AkPacket iStream(const AkPacket &packet); }; #endif // HYPNOTICELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Implode/src/implodeelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Implode/src/implodeelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Implode/src/implodeelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Implode/src/implodeelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "implodeelement.h" @@ -61,24 +62,9 @@ context->setContextProperty("controlId", this->objectName()); } -void ImplodeElement::setAmount(qreal amount) -{ - if (qFuzzyCompare(this->d->m_amount, amount)) - return; - - this->d->m_amount = amount; - emit this->amountChanged(amount); -} - -void ImplodeElement::resetAmount() -{ - this->setAmount(1.0); -} - -AkPacket ImplodeElement::iStream(const AkPacket &packet) +AkPacket ImplodeElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -116,8 +102,22 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void ImplodeElement::setAmount(qreal amount) +{ + if (qFuzzyCompare(this->d->m_amount, amount)) + return; + + this->d->m_amount = amount; + emit this->amountChanged(amount); +} + +void ImplodeElement::resetAmount() +{ + this->setAmount(1.0); +} + #include "moc_implodeelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Implode/src/implodeelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Implode/src/implodeelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Implode/src/implodeelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Implode/src/implodeelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -43,6 +43,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); private: ImplodeElementPrivate *d; @@ -53,7 +54,6 @@ public slots: void setAmount(qreal amount); void resetAmount(); - AkPacket iStream(const AkPacket &packet); }; #endif // IMPLODEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Invert/src/invertelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Invert/src/invertelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Invert/src/invertelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Invert/src/invertelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -18,6 +18,7 @@ */ #include +#include #include #include "invertelement.h" @@ -26,10 +27,9 @@ { } -AkPacket InvertElement::iStream(const AkPacket &packet) +AkPacket InvertElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -37,7 +37,7 @@ QImage oFrame = src.convertToFormat(QImage::Format_ARGB32); oFrame.invertPixels(); - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Invert/src/invertelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Invert/src/invertelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Invert/src/invertelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Invert/src/invertelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -29,8 +29,8 @@ public: InvertElement(); - public slots: - AkPacket iStream(const AkPacket &packet); + protected: + AkPacket iVideoStream(const AkVideoPacket &packet); }; #endif // INVERTELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Life/src/lifeelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Life/src/lifeelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Life/src/lifeelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Life/src/lifeelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "lifeelement.h" @@ -82,52 +83,9 @@ context->setContextProperty("controlId", this->objectName()); } -void LifeElement::setLifeColor(QRgb lifeColor) -{ - if (this->d->m_lifeColor == lifeColor) - return; - - this->d->m_lifeColor = lifeColor; - emit this->lifeColorChanged(lifeColor); -} - -void LifeElement::setThreshold(int threshold) -{ - if (this->d->m_threshold == threshold) - return; - - this->d->m_threshold = threshold; - emit this->thresholdChanged(threshold); -} - -void LifeElement::setLumaThreshold(int lumaThreshold) -{ - if (this->d->m_lumaThreshold == lumaThreshold) - return; - - this->d->m_lumaThreshold = lumaThreshold; - emit this->lumaThresholdChanged(lumaThreshold); -} - -void LifeElement::resetLifeColor() -{ - this->setLifeColor(qRgb(255, 255, 255)); -} - -void LifeElement::resetThreshold() -{ - this->setThreshold(15); -} - -void LifeElement::resetLumaThreshold() -{ - this->setLumaThreshold(15); -} - -AkPacket LifeElement::iStream(const AkPacket &packet) +AkPacket LifeElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -176,10 +134,52 @@ this->d->m_prevFrame = src.copy(); - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void LifeElement::setLifeColor(QRgb lifeColor) +{ + if (this->d->m_lifeColor == lifeColor) + return; + + this->d->m_lifeColor = lifeColor; + emit this->lifeColorChanged(lifeColor); +} + +void LifeElement::setThreshold(int threshold) +{ + if (this->d->m_threshold == threshold) + return; + + this->d->m_threshold = threshold; + emit this->thresholdChanged(threshold); +} + +void LifeElement::setLumaThreshold(int lumaThreshold) +{ + if (this->d->m_lumaThreshold == lumaThreshold) + return; + + this->d->m_lumaThreshold = lumaThreshold; + emit this->lumaThresholdChanged(lumaThreshold); +} + +void LifeElement::resetLifeColor() +{ + this->setLifeColor(qRgb(255, 255, 255)); +} + +void LifeElement::resetThreshold() +{ + this->setThreshold(15); +} + +void LifeElement::resetLumaThreshold() +{ + this->setLumaThreshold(15); +} + QImage LifeElementPrivate::imageDiff(const QImage &img1, const QImage &img2, int threshold, diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Life/src/lifeelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Life/src/lifeelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Life/src/lifeelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Life/src/lifeelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -59,6 +59,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void lifeColorChanged(QRgb lifeColor); @@ -72,8 +73,6 @@ void resetLifeColor(); void resetThreshold(); void resetLumaThreshold(); - - AkPacket iStream(const AkPacket &packet); }; #endif // LIFEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Matrix/src/matrixelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Matrix/src/matrixelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Matrix/src/matrixelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Matrix/src/matrixelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "matrixelement.h" @@ -339,13 +340,65 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket MatrixElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_RGB32); + + this->d->m_mutex.lock(); + int textWidth = src.width() / this->d->m_fontSize.width(); + int textHeight = src.height() / this->d->m_fontSize.height(); + + int outWidth = textWidth * this->d->m_fontSize.width(); + int outHeight = textHeight * this->d->m_fontSize.height(); + + QImage oFrame(outWidth, outHeight, src.format()); + + QList characters(this->d->m_characters); + this->d->m_mutex.unlock(); + + if (characters.size() < 256) { + oFrame.fill(this->d->m_backgroundColor); + auto oPacket = + AkVideoPacket::fromImage(oFrame.scaled(src.size()), packet); + akSend(oPacket) + } + + QImage textImage = src.scaled(textWidth, textHeight); + QRgb *textImageBits = reinterpret_cast(textImage.bits()); + int textArea = textImage.width() * textImage.height(); + QPainter painter; + + painter.begin(&oFrame); + + for (int i = 0; i < textArea; i++) { + int x = this->d->m_fontSize.width() * (i % textWidth); + int y = this->d->m_fontSize.height() * (i / textWidth); + + Character chr = characters[qGray(textImageBits[i])]; + painter.drawImage(x, y, chr.image); + textImageBits[i] = chr.foreground; + } + + painter.drawImage(0, 0, this->d->renderRain(oFrame.size(), textImage)); + painter.end(); + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void MatrixElement::setNDrops(int nDrops) { if (this->d->m_nDrops == nDrops) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_nDrops = nDrops; + this->d->m_mutex.unlock(); emit this->nDropsChanged(nDrops); } @@ -354,8 +407,9 @@ if (this->d->m_charTable == charTable) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_charTable = charTable; + this->d->m_mutex.unlock(); emit this->charTableChanged(charTable); } @@ -364,19 +418,18 @@ if (this->d->m_font == font) return; - QMutexLocker locker(&this->d->m_mutex); - + this->d->m_mutex.lock(); QFont::HintingPreference hp = hintingPreferenceToStr->key(this->hintingPreference(), QFont::PreferFullHinting); QFont::StyleStrategy ss = styleStrategyToStr->key(this->styleStrategy(), QFont::NoAntialias); - this->d->m_font = font; this->d->m_font.setHintingPreference(hp); this->d->m_font.setStyleStrategy(ss); this->d->m_rain.clear(); + this->d->m_mutex.unlock(); emit this->fontChanged(font); } @@ -389,9 +442,10 @@ if (this->d->m_font.hintingPreference() == hp) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_font.setHintingPreference(hp); this->d->m_rain.clear(); + this->d->m_mutex.unlock(); emit hintingPreferenceChanged(hintingPreference); } @@ -404,9 +458,10 @@ if (this->d->m_font.styleStrategy() == ss) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_font.setStyleStrategy(ss); this->d->m_rain.clear(); + this->d->m_mutex.unlock(); emit styleStrategyChanged(styleStrategy); } @@ -415,8 +470,9 @@ if (this->d->m_cursorColor == cursorColor) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_cursorColor = cursorColor; + this->d->m_mutex.unlock(); emit this->cursorColorChanged(cursorColor); } @@ -425,8 +481,9 @@ if (this->d->m_foregroundColor == foregroundColor) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_foregroundColor = foregroundColor; + this->d->m_mutex.unlock(); emit this->foregroundColorChanged(foregroundColor); } @@ -435,8 +492,9 @@ if (this->d->m_backgroundColor == backgroundColor) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_backgroundColor = backgroundColor; + this->d->m_mutex.unlock(); emit this->backgroundColorChanged(backgroundColor); } @@ -445,8 +503,9 @@ if (this->d->m_minDropLength == minDropLength) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_minDropLength = minDropLength; + this->d->m_mutex.unlock(); emit this->minDropLengthChanged(minDropLength); } @@ -455,8 +514,9 @@ if (this->d->m_maxDropLength == maxDropLength) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_maxDropLength = maxDropLength; + this->d->m_mutex.unlock(); emit this->maxDropLengthChanged(maxDropLength); } @@ -465,8 +525,9 @@ if (qFuzzyCompare(this->d->m_minSpeed, minSpeed)) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_minSpeed = minSpeed; + this->d->m_mutex.unlock(); emit this->minSpeedChanged(minSpeed); } @@ -475,8 +536,9 @@ if (qFuzzyCompare(this->d->m_maxSpeed, maxSpeed)) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_maxSpeed = maxSpeed; + this->d->m_mutex.unlock(); emit this->maxSpeedChanged(maxSpeed); } @@ -485,8 +547,9 @@ if (this->d->m_showCursor == showCursor) return; - QMutexLocker locker(&this->d->m_mutex); + this->d->m_mutex.lock(); this->d->m_showCursor = showCursor; + this->d->m_mutex.unlock(); emit this->showCursorChanged(showCursor); } @@ -560,58 +623,6 @@ this->setShowCursor(false); } -AkPacket MatrixElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_RGB32); - - this->d->m_mutex.lock(); - int textWidth = src.width() / this->d->m_fontSize.width(); - int textHeight = src.height() / this->d->m_fontSize.height(); - - int outWidth = textWidth * this->d->m_fontSize.width(); - int outHeight = textHeight * this->d->m_fontSize.height(); - - QImage oFrame(outWidth, outHeight, src.format()); - - QList characters(this->d->m_characters); - this->d->m_mutex.unlock(); - - if (characters.size() < 256) { - oFrame.fill(this->d->m_backgroundColor); - auto oPacket = AkVideoPacket::fromImage(oFrame.scaled(src.size()), - videoPacket).toPacket(); - akSend(oPacket) - } - - QImage textImage = src.scaled(textWidth, textHeight); - QRgb *textImageBits = reinterpret_cast(textImage.bits()); - int textArea = textImage.width() * textImage.height(); - QPainter painter; - - painter.begin(&oFrame); - - for (int i = 0; i < textArea; i++) { - int x = this->d->m_fontSize.width() * (i % textWidth); - int y = this->d->m_fontSize.height() * (i / textWidth); - - Character chr = characters[qGray(textImageBits[i])]; - painter.drawImage(x, y, chr.image); - textImageBits[i] = chr.foreground; - } - - painter.drawImage(0, 0, this->d->renderRain(oFrame.size(), textImage)); - painter.end(); - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - void MatrixElement::updateCharTable() { if (!this->d->m_mutex.tryLock()) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Matrix/src/matrixelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Matrix/src/matrixelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Matrix/src/matrixelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Matrix/src/matrixelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -119,6 +119,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void nDropsChanged(int nDrops); @@ -163,8 +164,6 @@ void resetMaxSpeed(); void resetShowCursor(); - AkPacket iStream(const AkPacket &packet); - private slots: void updateCharTable(); }; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Matrix/src/raindrop.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Matrix/src/raindrop.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Matrix/src/raindrop.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Matrix/src/raindrop.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,9 +17,10 @@ * Web-Site: http://webcamoid.github.io/ */ -#include -#include +#include #include +#include +#include #include "raindrop.h" @@ -40,14 +41,13 @@ qreal m_speed {0.0}; QImage m_sprite; - int randInt(int a, int b); - qreal randReal(qreal a, qreal b); int gradientColor(int i, int from, int to, int length); QRgb gradientRgb(int i, QRgb from, QRgb to, int length); QRgb gradient(int i, QRgb from, QRgb mid, QRgb to, int length); QImage drawChar(const QChar &chr, const QFont &font, const QSize &fontSize, QRgb foreground, QRgb background) const; + inline qreal boundedReal(qreal min, qreal max); }; RainDrop::RainDrop(const QSize &textArea, @@ -66,22 +66,25 @@ this->d = new RainDropPrivate; for (int i = 0; i < textArea.height(); i++) - this->d->m_line.append(charTable[qrand() % charTable.size()]); + this->d->m_line.append(QRandomGenerator::global()->bounded(charTable.size())); this->d->m_textArea = textArea; - int y = randomStart? qrand() % textArea.height(): 0; - this->d->m_pos = QPointF(qrand() % textArea.width(), y); + int y = randomStart? + QRandomGenerator::global()->bounded(textArea.height()): 0; + this->d->m_pos = + QPointF(QRandomGenerator::global()->bounded(textArea.width()), y); this->d->m_font = font; this->d->m_fontSize = fontSize; this->d->m_cursorColor = cursorColor; this->d->m_startColor = startColor; this->d->m_endColor = endColor; - this->d->m_length = this->d->randInt(minLength, maxLength); + this->d->m_length = + QRandomGenerator::global()->bounded(minLength, maxLength); if (this->d->m_length < 1) this->d->m_length = 1; - this->d->m_speed = this->d->randReal(minSpeed, maxSpeed); + this->d->m_speed = this->d->boundedReal(minSpeed, maxSpeed); if (this->d->m_speed < 0.1) this->d->m_speed = 0.1; @@ -155,17 +158,14 @@ return this->d->m_sprite; QPainter painter; - painter.begin(&this->d->m_sprite); - QChar c = this->d->m_line[qrand() % this->d->m_line.size()]; - - QImage sprite = + QChar c = this->d->m_line[QRandomGenerator::global()->bounded(this->d->m_line.size())]; + auto sprite = this->d->drawChar(c, this->d->m_font, this->d->m_fontSize, this->d->m_endColor, this->d->m_cursorColor); - painter.drawImage(0, (this->d->m_length - 1) * this->d->m_fontSize.height(), sprite); @@ -193,7 +193,7 @@ if (c >= 0 && c < this->d->m_line.size()) { if (i == this->d->m_length - 1) { - chr = this->d->m_line[qrand() % this->d->m_line.size()]; + chr = this->d->m_line[QRandomGenerator::global()->bounded(this->d->m_line.size())]; if (showCursor) { foreground = this->d->m_endColor; @@ -213,13 +213,12 @@ background = this->d->m_endColor; } - QImage sprite = + auto sprite = this->d->drawChar(chr, this->d->m_font, this->d->m_fontSize, foreground, background); - painter.drawImage(0, i * this->d->m_fontSize.height(), sprite); } } @@ -265,26 +264,11 @@ return fontImg; } -int RainDropPrivate::randInt(int a, int b) +qreal RainDropPrivate::boundedReal(qreal min, qreal max) { - if (a > b) { - int c = a; - a = b; - b = c; - } - - return qrand() % (b + 1 - a) + a; -} - -qreal RainDropPrivate::randReal(qreal a, qreal b) -{ - if (a > b) { - qreal c = a; - a = b; - b = c; - } + std::uniform_real_distribution distribution(min, max); - return qrand() * (b - a) / RAND_MAX + a; + return distribution(*QRandomGenerator::global()); } int RainDropPrivate::gradientColor(int i, int from, int to, int length) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MatrixTransform/src/matrixtransformelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MatrixTransform/src/matrixtransformelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MatrixTransform/src/matrixtransformelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MatrixTransform/src/matrixtransformelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "matrixtransformelement.h" @@ -73,35 +74,9 @@ context->setContextProperty("controlId", this->objectName()); } -void MatrixTransformElement::setKernel(const QVariantList &kernel) -{ - QVector k; - - for (const QVariant &e: kernel) - k << e.toReal(); - - if (this->d->m_kernel == k) - return; - - QMutexLocker locker(&this->d->m_mutex); - this->d->m_kernel = k; - emit this->kernelChanged(kernel); -} - -void MatrixTransformElement::resetKernel() -{ - static const QVariantList kernel = { - 1, 0, 0, - 0, 1, 0 - }; - - this->setKernel(kernel); -} - -AkPacket MatrixTransformElement::iStream(const AkPacket &packet) +AkPacket MatrixTransformElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -137,8 +112,33 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void MatrixTransformElement::setKernel(const QVariantList &kernel) +{ + QVector k; + + for (const QVariant &e: kernel) + k << e.toReal(); + + if (this->d->m_kernel == k) + return; + + QMutexLocker locker(&this->d->m_mutex); + this->d->m_kernel = k; + emit this->kernelChanged(kernel); +} + +void MatrixTransformElement::resetKernel() +{ + static const QVariantList kernel = { + 1, 0, 0, + 0, 1, 0 + }; + + this->setKernel(kernel); +} + #include "moc_matrixtransformelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MatrixTransform/src/matrixtransformelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MatrixTransform/src/matrixtransformelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MatrixTransform/src/matrixtransformelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MatrixTransform/src/matrixtransformelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void kernelChanged(const QVariantList &kernel); @@ -53,7 +54,6 @@ public slots: void setKernel(const QVariantList &kernel); void resetKernel(); - AkPacket iStream(const AkPacket &packet); }; #endif // MATRIXTRANSFORMELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Multiplex/src/multiplexelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Multiplex/src/multiplexelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Multiplex/src/multiplexelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Multiplex/src/multiplexelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,17 +17,17 @@ * Web-Site: http://webcamoid.github.io/ */ -#include #include +#include #include "multiplexelement.h" class MultiplexElementPrivate { public: + AkCaps m_caps; int m_inputIndex {-1}; int m_outputIndex {-1}; - QString m_caps; }; MultiplexElement::MultiplexElement(): AkElement() @@ -40,6 +40,11 @@ delete this->d; } +AkCaps MultiplexElement::caps() const +{ + return this->d->m_caps; +} + int MultiplexElement::inputIndex() const { return this->d->m_inputIndex; @@ -50,24 +55,36 @@ return this->d->m_outputIndex; } -QString MultiplexElement::caps() const +void MultiplexElement::setCaps(const AkCaps &caps) { - return this->d->m_caps; + if (this->d->m_caps == caps) + return; + + this->d->m_caps = caps; + emit this->capsChanged(caps); } -void MultiplexElement::setInputIndex(int method) +void MultiplexElement::setInputIndex(int inputIndex) { - this->d->m_inputIndex = method; + if (this->d->m_inputIndex == inputIndex) + return; + + this->d->m_inputIndex = inputIndex; + emit this->inputIndexChanged(inputIndex); } -void MultiplexElement::setOutputIndex(int params) +void MultiplexElement::setOutputIndex(int outputIndex) { - this->d->m_outputIndex = params; + if (this->d->m_outputIndex == outputIndex) + return; + + this->d->m_outputIndex = outputIndex; + emit this->outputIndexChanged(outputIndex); } -void MultiplexElement::setCaps(const QString &caps) +void MultiplexElement::resetCaps() { - this->d->m_caps = caps; + this->setCaps({}); } void MultiplexElement::resetInputIndex() @@ -80,20 +97,15 @@ this->setOutputIndex(-1); } -void MultiplexElement::resetCaps() -{ - this->setCaps(""); -} - AkPacket MultiplexElement::iStream(const AkPacket &packet) { if (this->d->m_inputIndex >= 0 && packet.index() != this->d->m_inputIndex) - return AkPacket(); + return {}; - if (!this->d->m_caps.isEmpty() + if (this->d->m_caps && !packet.caps().isCompatible(this->d->m_caps)) - return AkPacket(); + return {}; AkPacket oPacket(packet); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Multiplex/src/multiplexelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Multiplex/src/multiplexelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Multiplex/src/multiplexelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Multiplex/src/multiplexelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -23,32 +23,50 @@ #include class MultiplexElementPrivate; +class AkCaps; class MultiplexElement: public AkElement { Q_OBJECT - Q_PROPERTY(int inputIndex READ inputIndex WRITE setInputIndex RESET resetInputIndex) - Q_PROPERTY(int outputIndex READ outputIndex WRITE setOutputIndex RESET resetOutputIndex) - Q_PROPERTY(QString caps READ caps WRITE setCaps RESET resetCaps) + Q_PROPERTY(AkCaps caps + READ caps + WRITE setCaps + RESET resetCaps + NOTIFY capsChanged) + Q_PROPERTY(int inputIndex + READ inputIndex + WRITE setInputIndex + RESET resetInputIndex + NOTIFY inputIndexChanged) + Q_PROPERTY(int outputIndex + READ outputIndex + WRITE setOutputIndex + RESET resetOutputIndex + NOTIFY outputIndexChanged) public: MultiplexElement(); ~MultiplexElement(); + Q_INVOKABLE AkCaps caps() const; Q_INVOKABLE int inputIndex() const; Q_INVOKABLE int outputIndex() const; - Q_INVOKABLE QString caps() const; private: MultiplexElementPrivate *d; + signals: + void capsChanged(const AkCaps &caps); + void inputIndexChanged(int inputIndex); + void outputIndexChanged(int outputIndex); + public slots: + void setCaps(const AkCaps &caps); void setInputIndex(int inputIndex); void setOutputIndex(int outputIndex); - void setCaps(const QString &caps); + void resetCaps(); void resetInputIndex(); void resetOutputIndex(); - void resetCaps(); AkPacket iStream(const AkPacket &packet); }; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/MultiSink.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/MultiSink.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/MultiSink.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/MultiSink.pro 2021-02-15 15:25:23.000000000 +0000 @@ -23,3 +23,4 @@ SUBDIRS = src CONFIG(config_ffmpeg): SUBDIRS += src/ffmpeg CONFIG(config_gstreamer): SUBDIRS += src/gstreamer +CONFIG(config_ndk_media): SUBDIRS += src/ndkmedia diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/share/qml/main.qml webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/share/qml/main.qml --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/share/qml/main.qml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/share/qml/main.qml 2021-02-15 15:25:23.000000000 +0000 @@ -61,7 +61,6 @@ var streamConfig = streams[stream] var streamOptions = classStreamOptions.createObject(clyStreamOptions) streamOptions.Layout.fillWidth = true - var streamCaps = Ak.newCaps(streamConfig.caps) if (streamCaps.mimeType === "audio/x-raw") @@ -144,7 +143,7 @@ Connections { target: MultiSink - onSupportedFormatsChanged : updateSupportedFormats(supportedFormats) + onSupportedFormatsChanged: updateSupportedFormats(supportedFormats) onOutputFormatChanged: { btnFormatOptions.enabled = MultiSink.formatOptions().length > 0; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/ffmpeg.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/ffmpeg.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/ffmpeg.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/ffmpeg.pro 2021-02-15 15:25:23.000000000 +0000 @@ -65,6 +65,8 @@ DEFINES += HAVE_CODECPAR CONFIG(config_ffmpeg_avutil_extraoptions): \ DEFINES += HAVE_EXTRAOPTIONS +CONFIG(config_ffmpeg_avutil_sampleformat64): \ + DEFINES += HAVE_SAMPLEFORMAT64 QT += qml concurrent diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/abstractstream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/abstractstream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/abstractstream.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/abstractstream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -114,7 +114,7 @@ auto optKey = QString("%1/%2/%3").arg(formatContext->oformat->name) .arg(streamIndex) .arg(codecName); - QVariantMap options = codecOptions.value(optKey); + auto options = codecOptions.value(optKey); if (codecName == "libvpx") { if (!options.contains("deadline")) @@ -127,9 +127,7 @@ options["preset"] = "ultrafast"; } - for (auto it = options.begin(); - it != options.end(); - it++) { + for (auto it = options.begin(); it != options.end(); it++) { QString value = it.value().toString(); av_dict_set(&this->d->m_codecOptions, @@ -204,12 +202,12 @@ void AbstractStream::convertPacket(const AkPacket &packet) { - Q_UNUSED(packet); + Q_UNUSED(packet) } int AbstractStream::encodeData(AVFrame *frame) { - Q_UNUSED(frame); + Q_UNUSED(frame) return AVERROR_EOF; } @@ -308,7 +306,6 @@ void AbstractStream::uninit() { - this->d->m_runConvertLoop = false; waitLoop(this->d->m_convertLoopResult); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/abstractstream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/abstractstream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/abstractstream.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/abstractstream.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,7 +46,7 @@ class AbstractStream; class AkPacket; -typedef QSharedPointer AbstractStreamPtr; +using AbstractStreamPtr = QSharedPointer; class AbstractStream: public QObject { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/audiostream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/audiostream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/audiostream.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/audiostream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -35,47 +35,8 @@ #include "audiostream.h" #include "mediawriterffmpeg.h" -using AkFFChannelLayoutsMap = QMap; - -inline AkFFChannelLayoutsMap initAkFFChannelFormatsMap() -{ - AkFFChannelLayoutsMap channelLayouts = { - {AkAudioCaps::Layout_mono , AV_CH_LAYOUT_MONO }, - {AkAudioCaps::Layout_stereo , AV_CH_LAYOUT_STEREO }, - {AkAudioCaps::Layout_2p1 , AV_CH_LAYOUT_2POINT1 }, - {AkAudioCaps::Layout_3p0 , AV_CH_LAYOUT_SURROUND }, - {AkAudioCaps::Layout_3p0_back , AV_CH_LAYOUT_2_1 }, - {AkAudioCaps::Layout_3p1 , AV_CH_LAYOUT_3POINT1 }, - {AkAudioCaps::Layout_4p0 , AV_CH_LAYOUT_4POINT0 }, - {AkAudioCaps::Layout_quad , AV_CH_LAYOUT_QUAD }, - {AkAudioCaps::Layout_quad_side , AV_CH_LAYOUT_2_2 }, - {AkAudioCaps::Layout_4p1 , AV_CH_LAYOUT_4POINT1 }, - {AkAudioCaps::Layout_5p0 , AV_CH_LAYOUT_5POINT0_BACK }, - {AkAudioCaps::Layout_5p0_side , AV_CH_LAYOUT_5POINT0 }, - {AkAudioCaps::Layout_5p1 , AV_CH_LAYOUT_5POINT1_BACK }, - {AkAudioCaps::Layout_5p1_side , AV_CH_LAYOUT_5POINT1 }, - {AkAudioCaps::Layout_6p0 , AV_CH_LAYOUT_6POINT0 }, - {AkAudioCaps::Layout_6p0_front , AV_CH_LAYOUT_6POINT0_FRONT }, - {AkAudioCaps::Layout_hexagonal , AV_CH_LAYOUT_HEXAGONAL }, - {AkAudioCaps::Layout_6p1 , AV_CH_LAYOUT_6POINT1 }, - {AkAudioCaps::Layout_6p1_back , AV_CH_LAYOUT_6POINT1_BACK }, - {AkAudioCaps::Layout_6p1_front , AV_CH_LAYOUT_6POINT1_FRONT }, - {AkAudioCaps::Layout_7p0 , AV_CH_LAYOUT_7POINT0 }, - {AkAudioCaps::Layout_7p0_front , AV_CH_LAYOUT_7POINT0_FRONT }, - {AkAudioCaps::Layout_7p1 , AV_CH_LAYOUT_7POINT1 }, - {AkAudioCaps::Layout_7p1_wide , AV_CH_LAYOUT_7POINT1_WIDE }, - {AkAudioCaps::Layout_7p1_wide_side, AV_CH_LAYOUT_7POINT1_WIDE_BACK}, - {AkAudioCaps::Layout_octagonal , AV_CH_LAYOUT_OCTAGONAL }, -#ifdef AV_CH_LAYOUT_HEXADECAGONAL - {AkAudioCaps::Layout_hexadecagonal, AV_CH_LAYOUT_HEXADECAGONAL }, -#endif - {AkAudioCaps::Layout_downmix , AV_CH_LAYOUT_STEREO_DOWNMIX }, - }; - - return channelLayouts; -} - -Q_GLOBAL_STATIC_WITH_ARGS(AkFFChannelLayoutsMap, akFFChannelLayouts, (initAkFFChannelFormatsMap())) +using SampleFormatsMap = QMap; +using ChannelLayoutsMap = QMap; class AudioStreamPrivate { @@ -85,6 +46,85 @@ QMutex m_frameMutex; int64_t m_pts {0}; QWaitCondition m_frameReady; + + inline static const SampleFormatsMap &sampleFormats(bool planar) + { + static const SampleFormatsMap formats { + {AkAudioCaps::SampleFormat_u8 , AV_SAMPLE_FMT_U8 }, + {AkAudioCaps::SampleFormat_s16, AV_SAMPLE_FMT_S16}, + {AkAudioCaps::SampleFormat_s32, AV_SAMPLE_FMT_S32}, +#ifdef HAVE_SAMPLEFORMAT64 + {AkAudioCaps::SampleFormat_s64, AV_SAMPLE_FMT_S64 }, +#endif + {AkAudioCaps::SampleFormat_flt, AV_SAMPLE_FMT_FLT}, + {AkAudioCaps::SampleFormat_dbl, AV_SAMPLE_FMT_DBL}, + }; + static const SampleFormatsMap planarFormats { + {AkAudioCaps::SampleFormat_u8 , AV_SAMPLE_FMT_U8P }, + {AkAudioCaps::SampleFormat_s16, AV_SAMPLE_FMT_S16P}, + {AkAudioCaps::SampleFormat_s32, AV_SAMPLE_FMT_S32P}, +#ifdef HAVE_SAMPLEFORMAT64 + {AkAudioCaps::SampleFormat_s64, AV_SAMPLE_FMT_S64P}, +#endif + {AkAudioCaps::SampleFormat_flt, AV_SAMPLE_FMT_FLTP}, + {AkAudioCaps::SampleFormat_dbl, AV_SAMPLE_FMT_DBLP}, + }; + + return planar? planarFormats: formats; + } + + inline static const QVector &planarFormats() + { + static const QVector formats { + AV_SAMPLE_FMT_U8P , + AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBLP, + +#ifdef HAVE_SAMPLEFORMAT64 + AV_SAMPLE_FMT_S64P, +#endif + }; + + return formats; + } + + inline static const ChannelLayoutsMap &channelLayouts() + { + static const ChannelLayoutsMap channelLayouts = { + {AkAudioCaps::Layout_mono , AV_CH_LAYOUT_MONO }, + {AkAudioCaps::Layout_stereo , AV_CH_LAYOUT_STEREO }, + {AkAudioCaps::Layout_2p1 , AV_CH_LAYOUT_2POINT1 }, + {AkAudioCaps::Layout_3p0 , AV_CH_LAYOUT_SURROUND }, + {AkAudioCaps::Layout_3p0_back , AV_CH_LAYOUT_2_1 }, + {AkAudioCaps::Layout_3p1 , AV_CH_LAYOUT_3POINT1 }, + {AkAudioCaps::Layout_4p0 , AV_CH_LAYOUT_4POINT0 }, + {AkAudioCaps::Layout_quad , AV_CH_LAYOUT_QUAD }, + {AkAudioCaps::Layout_quad_side , AV_CH_LAYOUT_2_2 }, + {AkAudioCaps::Layout_4p1 , AV_CH_LAYOUT_4POINT1 }, + {AkAudioCaps::Layout_5p0 , AV_CH_LAYOUT_5POINT0_BACK }, + {AkAudioCaps::Layout_5p0_side , AV_CH_LAYOUT_5POINT0 }, + {AkAudioCaps::Layout_5p1 , AV_CH_LAYOUT_5POINT1_BACK }, + {AkAudioCaps::Layout_5p1_side , AV_CH_LAYOUT_5POINT1 }, + {AkAudioCaps::Layout_6p0 , AV_CH_LAYOUT_6POINT0 }, + {AkAudioCaps::Layout_6p0_front , AV_CH_LAYOUT_6POINT0_FRONT }, + {AkAudioCaps::Layout_hexagonal , AV_CH_LAYOUT_HEXAGONAL }, + {AkAudioCaps::Layout_6p1 , AV_CH_LAYOUT_6POINT1 }, + {AkAudioCaps::Layout_6p1_back , AV_CH_LAYOUT_6POINT1_BACK }, + {AkAudioCaps::Layout_6p1_front , AV_CH_LAYOUT_6POINT1_FRONT }, + {AkAudioCaps::Layout_7p0 , AV_CH_LAYOUT_7POINT0 }, + {AkAudioCaps::Layout_7p0_front , AV_CH_LAYOUT_7POINT0_FRONT }, + {AkAudioCaps::Layout_7p1 , AV_CH_LAYOUT_7POINT1 }, + {AkAudioCaps::Layout_7p1_wide , AV_CH_LAYOUT_7POINT1_WIDE }, + {AkAudioCaps::Layout_7p1_wide_back, AV_CH_LAYOUT_7POINT1_WIDE_BACK}, + {AkAudioCaps::Layout_octagonal , AV_CH_LAYOUT_OCTAGONAL }, + {AkAudioCaps::Layout_hexadecagonal, AV_CH_LAYOUT_HEXADECAGONAL }, + {AkAudioCaps::Layout_downmix , AV_CH_LAYOUT_STEREO_DOWNMIX }, + }; + + return channelLayouts; + } }; AudioStream::AudioStream(const AVFormatContext *formatContext, @@ -122,23 +162,33 @@ } AkAudioCaps audioCaps(configs["caps"].value()); - - QString sampleFormat = AkAudioCaps::sampleFormatToString(audioCaps.format()); - QStringList supportedSampleFormats = defaultCodecParams["supportedSampleFormats"].toStringList(); - - if (!supportedSampleFormats.isEmpty() && !supportedSampleFormats.contains(sampleFormat)) { - QString defaultSampleFormat = defaultCodecParams["defaultSampleFormat"].toString(); - audioCaps.format() = AkAudioCaps::sampleFormatFromString(defaultSampleFormat); - audioCaps.bps() = 8 * av_get_bytes_per_sample(av_get_sample_fmt(defaultSampleFormat.toStdString().c_str())); + auto ffFormat = + AudioStreamPrivate::sampleFormats(audioCaps.planar()) + .value(audioCaps.format(), AV_SAMPLE_FMT_NONE); + auto sampleFormat = QString(av_get_sample_fmt_name(ffFormat)); + auto supportedSampleFormats = + defaultCodecParams["supportedSampleFormats"].toStringList(); + + if (!supportedSampleFormats.isEmpty() + && !supportedSampleFormats.contains(sampleFormat)) { + auto defaultSampleFormat = defaultCodecParams["defaultSampleFormat"].toString(); + ffFormat = av_get_sample_fmt(defaultSampleFormat.toStdString().c_str()); + auto planar = AudioStreamPrivate::planarFormats().contains(ffFormat); + auto format = + AudioStreamPrivate::sampleFormats(planar) + .key(ffFormat, AkAudioCaps::SampleFormat_none); + audioCaps.setFormat(format); + audioCaps.updatePlaneSize(planar); } - QVariantList supportedSampleRates = defaultCodecParams["supportedSampleRates"].toList(); + auto supportedSampleRates = + defaultCodecParams["supportedSampleRates"].toList(); if (!supportedSampleRates.isEmpty()) { int sampleRate = 0; int maxDiff = std::numeric_limits::max(); - for (const QVariant &rate: supportedSampleRates) { + for (auto &rate: supportedSampleRates) { int diff = qAbs(audioCaps.rate() - rate.toInt()); if (diff < maxDiff) { @@ -154,29 +204,30 @@ audioCaps.rate() = sampleRate; } - QString channelLayout = AkAudioCaps::channelLayoutToString(audioCaps.layout()); - QStringList supportedChannelLayouts = defaultCodecParams["supportedChannelLayouts"].toStringList(); + auto channelLayout = AkAudioCaps::channelLayoutToString(audioCaps.layout()); + auto supportedChannelLayouts = + defaultCodecParams["supportedChannelLayouts"].toStringList(); if (!supportedChannelLayouts.isEmpty() && !supportedChannelLayouts.contains(channelLayout)) { - QString defaultChannelLayout = defaultCodecParams["defaultChannelLayout"].toString(); - audioCaps.layout() = AkAudioCaps::channelLayoutFromString(defaultChannelLayout); - audioCaps.channels() = av_get_channel_layout_nb_channels(av_get_channel_layout(defaultChannelLayout.toStdString().c_str())); + auto defaultChannelLayout = defaultCodecParams["defaultChannelLayout"].toString(); + auto layout = AkAudioCaps::channelLayoutFromString(defaultChannelLayout); + audioCaps.setLayout(layout); } if (!strcmp(formatContext->oformat->name, "gxf")) { audioCaps.rate() = 48000; - audioCaps.layout() = AkAudioCaps::Layout_mono; - audioCaps.channels() = 1; + audioCaps.setLayout(AkAudioCaps::Layout_mono); } else if (!strcmp(formatContext->oformat->name, "mxf")) { audioCaps.rate() = 48000; } else if (!strcmp(formatContext->oformat->name, "swf")) { audioCaps = mediaWriter->nearestSWFCaps(audioCaps); } - QString sampleFormatStr = AkAudioCaps::sampleFormatToString(audioCaps.format()); - codecContext->sample_fmt = av_get_sample_fmt(sampleFormatStr.toStdString().c_str()); + codecContext->sample_fmt = + AudioStreamPrivate::sampleFormats(audioCaps.planar()) + .value(audioCaps.format(), AV_SAMPLE_FMT_NONE); codecContext->sample_rate = audioCaps.rate(); - QString layout = AkAudioCaps::channelLayoutToString(audioCaps.layout()); + auto layout = AkAudioCaps::channelLayoutToString(audioCaps.layout()); codecContext->channel_layout = av_get_channel_layout(layout.toStdString().c_str()); codecContext->channels = audioCaps.channels(); @@ -186,13 +237,7 @@ codecContext->time_base = stream->time_base; this->d->m_convert = AkElement::create("ACapsConvert"); - - auto fmtName = av_get_sample_fmt_name(codecContext->sample_fmt); - AkAudioCaps caps(AkAudioCaps::sampleFormatFromString(fmtName), - codecContext->channels, - codecContext->sample_rate); - caps.layout() = akFFChannelLayouts->key(codecContext->channel_layout); - this->d->m_convert->setProperty("caps", caps.toString()); + this->d->m_convert->setProperty("caps", QVariant::fromValue(audioCaps)); } AudioStream::~AudioStream() diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/mediawriterffmpeg.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/mediawriterffmpeg.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/mediawriterffmpeg.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/mediawriterffmpeg.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -70,15 +70,15 @@ QMap m_codecDefaults; MediaWriterFFmpegGlobal(); - inline AvMediaTypeStrMap initAvMediaTypeStrMap(); - inline VectorVideoCaps initDVSupportedCaps(); - inline VectorVideoCaps initDNxHDSupportedCaps(); - inline QVector initH261SupportedSize(); - inline QVector initH263SupportedSize(); - inline QVector initGXFSupportedSize(); - inline QVector initSWFSupportedSampleRates(); + inline const AvMediaTypeStrMap &initAvMediaTypeStrMap(); + inline const VectorVideoCaps &initDVSupportedCaps(); + inline const VectorVideoCaps &initDNxHDSupportedCaps(); + inline const QVector &initH261SupportedSize(); + inline const QVector &initH263SupportedSize(); + inline const QVector &initGXFSupportedSize(); + inline const QVector &initSWFSupportedSampleRates(); inline bool initHasCudaSupport(); - inline OptionTypeStrMap initFFOptionTypeStrMap(); + inline const OptionTypeStrMap &initFFOptionTypeStrMap(); inline SupportedCodecsType initSupportedCodecs(); inline QMap initCodecDefaults(); }; @@ -120,7 +120,7 @@ // This codec fail. "vc2", - // The codecs are too slow for real time recording. + // These codecs are too slow for real time recording. "ayuv", "cinepak", "dpx", @@ -149,6 +149,17 @@ delete this->d; } +QString MediaWriterFFmpeg::defaultFormat() +{ + if (mediaWriterFFmpegGlobal->m_supportedCodecs.isEmpty()) + return {}; + + if (mediaWriterFFmpegGlobal->m_supportedCodecs.contains("webm")) + return QStringLiteral("webm"); + + return mediaWriterFFmpegGlobal->m_supportedCodecs.firstKey(); +} + QString MediaWriterFFmpeg::outputFormat() const { return this->d->m_outputFormat; @@ -186,29 +197,31 @@ QStringList MediaWriterFFmpeg::fileExtensions(const QString &format) { - AVOutputFormat *outputFormat = av_guess_format(format.toStdString().c_str(), - nullptr, - nullptr); + auto outputFormat = + av_guess_format(format.toStdString().c_str(), + nullptr, + nullptr); if (!outputFormat) - return QStringList(); + return {}; QString extensions(outputFormat->extensions); if (extensions.isEmpty()) - return QStringList(); + return {}; return extensions.split(","); } QString MediaWriterFFmpeg::formatDescription(const QString &format) { - AVOutputFormat *outputFormat = av_guess_format(format.toStdString().c_str(), - nullptr, - nullptr); + auto outputFormat = + av_guess_format(format.toStdString().c_str(), + nullptr, + nullptr); if (!outputFormat) - return QString(); + return {}; return QString(outputFormat->long_name); } @@ -218,14 +231,15 @@ auto outFormat = this->d->guessFormat(); if (outFormat.isEmpty()) - return QVariantList(); + return {}; - AVOutputFormat *outputFormat = av_guess_format(outFormat.toStdString().c_str(), - nullptr, - nullptr); + auto outputFormat = + av_guess_format(outFormat.toStdString().c_str(), + nullptr, + nullptr); if (!outputFormat) - return QVariantList(); + return {}; auto options = this->d->parseOptions(outputFormat->priv_class); auto globalFormatOptions = this->d->m_formatOptions.value(outFormat); @@ -261,8 +275,11 @@ supportedCodecs << codec; } } else { - auto codecType = mediaWriterFFmpegGlobal->m_mediaTypeToStr.key(type, AVMEDIA_TYPE_UNKNOWN); - auto codecs = mediaWriterFFmpegGlobal->m_supportedCodecs.value(format).value(codecType); + auto codecType = + mediaWriterFFmpegGlobal->m_mediaTypeToStr.key(type, + AVMEDIA_TYPE_UNKNOWN); + auto codecs = + mediaWriterFFmpegGlobal->m_supportedCodecs.value(format).value(codecType); for (auto &codec: codecs) if (!this->m_codecsBlackList.contains(codec)) @@ -277,9 +294,10 @@ QString MediaWriterFFmpeg::defaultCodec(const QString &format, const QString &type) { - auto outputFormat = av_guess_format(format.toStdString().c_str(), - nullptr, - nullptr); + auto outputFormat = + av_guess_format(format.toStdString().c_str(), + nullptr, + nullptr); if (!outputFormat) return QString(); @@ -293,18 +311,18 @@ AV_CODEC_ID_NONE; if (codecId == AV_CODEC_ID_NONE) - return QString(); + return {}; if (codecId == AV_CODEC_ID_VP9) codecId = AV_CODEC_ID_VP8; - AVCodec *codec = avcodec_find_encoder(codecId); + auto codec = avcodec_find_encoder(codecId); QString codecName(codec->name); - QStringList supportedCodecs = this->supportedCodecs(format, type); + auto supportedCodecs = this->supportedCodecs(format, type); if (supportedCodecs.isEmpty()) - return QString(); + return {}; if (!supportedCodecs.contains(codecName)) codecName = supportedCodecs.first(); @@ -314,20 +332,22 @@ QString MediaWriterFFmpeg::codecDescription(const QString &codec) { - auto avCodec = avcodec_find_encoder_by_name(codec.toStdString().c_str()); + auto avCodec = + avcodec_find_encoder_by_name(codec.toStdString().c_str()); if (!avCodec) - return QString(); + return {}; return QString(avCodec->long_name); } QString MediaWriterFFmpeg::codecType(const QString &codec) { - auto avCodec = avcodec_find_encoder_by_name(codec.toStdString().c_str()); + auto avCodec = + avcodec_find_encoder_by_name(codec.toStdString().c_str()); if (!avCodec) - return QString(); + return {}; return mediaWriterFFmpegGlobal->m_mediaTypeToStr.value(avCodec->type); } @@ -347,10 +367,10 @@ const AkCaps &streamCaps, const QVariantMap &codecParams) { - QString outputFormat = this->d->guessFormat(); + auto outputFormat = this->d->guessFormat(); if (outputFormat.isEmpty()) - return QVariantMap(); + return {}; QVariantMap outputParams; @@ -361,7 +381,7 @@ auto codec = codecParams.value("codec").toString(); if (codec.isEmpty()) - return QVariantMap(); + return {}; auto supportedCodecs = this->supportedCodecs(outputFormat, streamCaps.mimeType()); @@ -406,10 +426,10 @@ QVariantMap MediaWriterFFmpeg::updateStream(int index, const QVariantMap &codecParams) { - QString outputFormat = this->d->guessFormat(); + auto outputFormat = this->d->guessFormat(); if (outputFormat.isEmpty()) - return QVariantMap(); + return {}; bool streamChanged = false; @@ -419,7 +439,7 @@ streamChanged = true; } - AkCaps streamCaps = this->d->m_streamConfigs[index]["caps"].value(); + auto streamCaps = this->d->m_streamConfigs[index]["caps"].value(); if (codecParams.contains("caps") && this->d->m_streamConfigs[index]["caps"] != codecParams.value("caps")) { @@ -441,7 +461,7 @@ } else codec = this->d->m_streamConfigs[index]["codec"].toString(); - QVariantMap codecDefaults = this->defaultCodecParams(codec); + auto codecDefaults = this->defaultCodecParams(codec); if ((streamCaps.mimeType() == "audio/x-raw" || streamCaps.mimeType() == "video/x-raw") @@ -471,17 +491,18 @@ auto outputFormat = this->d->guessFormat(); if (outputFormat.isEmpty()) - return QVariantList(); + return {}; - auto codec = this->d->m_streamConfigs.value(index).value("codec").toString(); + auto codec = + this->d->m_streamConfigs.value(index).value("codec").toString(); if (codec.isEmpty()) - return QVariantList(); + return {}; auto avCodec = avcodec_find_encoder_by_name(codec.toStdString().c_str()); if (!avCodec) - return QVariantList(); + return {}; auto optKey = QString("%1/%2/%3").arg(outputFormat).arg(index).arg(codec); auto options = this->d->parseOptions(avCodec->priv_class); @@ -644,18 +665,18 @@ menu[option->unit] = QVariantList {QVariant(menuOption)}; } else { avOptions << QVariantList { - option->name, - option->help, - mediaWriterFFmpegGlobal->m_codecFFOptionTypeToStr.value(option->type), - option->min, - option->max, - step, - value, - value, - option->unit? - QVariantList {option->unit}: - QVariantList() - }; + option->name, + option->help, + mediaWriterFFmpegGlobal->m_codecFFOptionTypeToStr.value(option->type), + option->min, + option->max, + step, + value, + value, + option->unit? + QVariantList {option->unit}: + QVariantList() + }; } /* @@ -795,7 +816,7 @@ AkVideoCaps MediaWriterFFmpeg::nearestDVCaps(const AkVideoCaps &caps) const { AkVideoCaps nearestCaps; - qreal q = std::numeric_limits::max(); + auto q = std::numeric_limits::max(); for (auto &sCaps: mediaWriterFFmpegGlobal->m_dvSupportedCaps) { qreal dw = sCaps.width() - caps.width(); @@ -816,7 +837,7 @@ AkVideoCaps MediaWriterFFmpeg::nearestDNxHDCaps(const AkVideoCaps &caps) const { AkVideoCaps nearestCaps; - qreal q = std::numeric_limits::max(); + auto q = std::numeric_limits::max(); for (auto &sCaps: mediaWriterFFmpegGlobal->m_dnXhdSupportedCaps) { qreal dw = sCaps.width() - caps.width(); @@ -840,7 +861,7 @@ AkVideoCaps MediaWriterFFmpeg::nearestH261Caps(const AkVideoCaps &caps) const { QSize nearestSize; - qreal q = std::numeric_limits::max(); + auto q = std::numeric_limits::max(); for (auto &size: mediaWriterFFmpegGlobal->m_h261SupportedSize) { qreal dw = size.width() - caps.width(); @@ -857,8 +878,8 @@ } AkVideoCaps nearestCaps(caps); - nearestCaps.width() = nearestSize.width(); - nearestCaps.height() = nearestSize.height(); + nearestCaps.setWidth(nearestSize.width()); + nearestCaps.setHeight(nearestSize.height()); return nearestCaps; } @@ -866,7 +887,7 @@ AkVideoCaps MediaWriterFFmpeg::nearestH263Caps(const AkVideoCaps &caps) const { QSize nearestSize; - qreal q = std::numeric_limits::max(); + auto q = std::numeric_limits::max(); for (auto &size: mediaWriterFFmpegGlobal->m_h263SupportedSize) { qreal dw = size.width() - caps.width(); @@ -883,8 +904,8 @@ } AkVideoCaps nearestCaps(caps); - nearestCaps.width() = nearestSize.width(); - nearestCaps.height() = nearestSize.height(); + nearestCaps.setWidth(nearestSize.width()); + nearestCaps.setHeight(nearestSize.height()); return nearestCaps; } @@ -892,7 +913,7 @@ AkVideoCaps MediaWriterFFmpeg::nearestGXFCaps(const AkVideoCaps &caps) const { QSize nearestSize; - qreal q = std::numeric_limits::max(); + auto q = std::numeric_limits::max(); for (auto &size: mediaWriterFFmpegGlobal->m_gxfSupportedSize) { qreal dw = size.width() - caps.width(); @@ -909,8 +930,8 @@ } AkVideoCaps nearestCaps(caps); - nearestCaps.width() = nearestSize.width(); - nearestCaps.height() = nearestSize.height(); + nearestCaps.setWidth(nearestSize.width()); + nearestCaps.setHeight(nearestSize.height()); return nearestCaps; } @@ -989,7 +1010,7 @@ } if (modified) - emit this->codecOptionsChanged(optKey, this->d->m_formatOptions.value(optKey)); + emit this->codecOptionsChanged(optKey, this->d->m_codecOptions.value(optKey)); } void MediaWriterFFmpeg::setMaxPacketQueueSize(qint64 maxPacketQueueSize) @@ -1071,8 +1092,8 @@ if (!strcmp(this->d->m_formatContext->oformat->name, "mxf_opatom")) { QList mxfConfigs; - for (const QVariantMap &configs: streamConfigs) { - AkCaps streamCaps = configs["caps"].value(); + for (auto &configs: streamConfigs) { + auto streamCaps = configs["caps"].value(); if (streamCaps.mimeType() == "video/x-raw") { mxfConfigs << configs; @@ -1082,8 +1103,8 @@ } if (mxfConfigs.isEmpty()) - for (const QVariantMap &configs: streamConfigs) { - AkCaps streamCaps = configs["caps"].value(); + for (auto &configs: streamConfigs) { + auto streamCaps = configs["caps"].value(); if (streamCaps.mimeType() == "audio/x-raw") { mxfConfigs << configs; @@ -1096,7 +1117,7 @@ } for (int i = 0; i < streamConfigs.count(); i++) { - QVariantMap configs = streamConfigs[i]; + auto configs = streamConfigs[i]; auto stream = avformat_new_stream(this->d->m_formatContext, nullptr); stream->id = i; @@ -1242,9 +1263,9 @@ this->m_codecDefaults = this->initCodecDefaults(); } -AvMediaTypeStrMap MediaWriterFFmpegGlobal::initAvMediaTypeStrMap() +const AvMediaTypeStrMap &MediaWriterFFmpegGlobal::initAvMediaTypeStrMap() { - const AvMediaTypeStrMap mediaTypeToStr = { + static const AvMediaTypeStrMap mediaTypeToStr = { {AVMEDIA_TYPE_UNKNOWN , "unknown/x-raw" }, {AVMEDIA_TYPE_VIDEO , "video/x-raw" }, {AVMEDIA_TYPE_AUDIO , "audio/x-raw" }, @@ -1257,80 +1278,87 @@ return mediaTypeToStr; } -VectorVideoCaps MediaWriterFFmpegGlobal::initDVSupportedCaps() +const VectorVideoCaps &MediaWriterFFmpegGlobal::initDVSupportedCaps() { - const QStringList supportedCaps = { + static const VectorVideoCaps dvSupportedCaps { // Digital Video doesn't support height > 576 yet. - /*"video/x-raw,format=yuv422p,width=1440,height=1080,fps=25/1", - "video/x-raw,format=yuv422p,width=1280,height=1080,fps=30000/1001", - "video/x-raw,format=yuv422p,width=960,height=720,fps=60000/1001", - "video/x-raw,format=yuv422p,width=960,height=720,fps=50/1",*/ - "video/x-raw,format=yuv422p,width=720,height=576,fps=25/1", - "video/x-raw,format=yuv420p,width=720,height=576,fps=25/1", - "video/x-raw,format=yuv411p,width=720,height=576,fps=25/1", - "video/x-raw,format=yuv422p,width=720,height=480,fps=30000/1001", - "video/x-raw,format=yuv411p,width=720,height=480,fps=30000/1001" + /* + {AkVideoCaps::Format_yuv422p, 1440, 1080, {25, 1} }, + {AkVideoCaps::Format_yuv422p, 1280, 1080, {30000, 1001}}, + {AkVideoCaps::Format_yuv422p, 960 , 720 , {60000, 1001}}, + {AkVideoCaps::Format_yuv422p, 960 , 720 , {50, 1} },*/ + {AkVideoCaps::Format_yuv422p, 720, 576, {25, 1} }, + {AkVideoCaps::Format_yuv420p, 720, 576, {25, 1} }, + {AkVideoCaps::Format_yuv411p, 720, 576, {25, 1} }, + {AkVideoCaps::Format_yuv422p, 720, 480, {30000, 1001}}, + {AkVideoCaps::Format_yuv411p, 720, 480, {30000, 1001}}, }; - VectorVideoCaps dvSupportedCaps(supportedCaps.size()); - - for (int i = 0; i < dvSupportedCaps.size(); i++) - dvSupportedCaps[i] = supportedCaps[i]; - return dvSupportedCaps; } -VectorVideoCaps MediaWriterFFmpegGlobal::initDNxHDSupportedCaps() +const VectorVideoCaps &MediaWriterFFmpegGlobal::initDNxHDSupportedCaps() { - const QStringList supportedCaps = { - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=60000/1001,bitrate=440000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=50/1,bitrate=365000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=60000/1001,bitrate=290000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=50/1,bitrate=240000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=30000/1001,bitrate=220000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=25/1,bitrate=185000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=24000/1001,bitrate=175000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=30000/1001,bitrate=145000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=25/1,bitrate=120000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=24000/1001,bitrate=115000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=60000/1001,bitrate=90000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=24000/1001,bitrate=36000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=25/1,bitrate=36000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=30000/1001,bitrate=45000000", - "video/x-raw,format=yuv422p,width=1920,height=1080,fps=50/1,bitrate=75000000", - "video/x-raw,format=yuv422p,width=1440,height=1080,fps=0/0,bitrate=110000000", - "video/x-raw,format=yuv422p,width=1440,height=1080,fps=0/0,bitrate=100000000", - "video/x-raw,format=yuv422p,width=1440,height=1080,fps=0/0,bitrate=90000000", - "video/x-raw,format=yuv422p,width=1440,height=1080,fps=0/0,bitrate=84000000", - "video/x-raw,format=yuv422p,width=1440,height=1080,fps=0/0,bitrate=80000000", - "video/x-raw,format=yuv422p,width=1440,height=1080,fps=0/0,bitrate=63000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=60000/1001,bitrate=220000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=50/1,bitrate=180000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=60000/1001,bitrate=145000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=50/1,bitrate=120000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=30000/1001,bitrate=110000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=25/1,bitrate=90000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=24000/1001,bitrate=90000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=30000/1001,bitrate=75000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=25/1,bitrate=60000000", - "video/x-raw,format=yuv422p,width=1280,height=720,fps=24000/1001,bitrate=60000000", - "video/x-raw,format=yuv422p,width=960,height=720,fps=0/0,bitrate=115000000", - "video/x-raw,format=yuv422p,width=960,height=720,fps=0/0,bitrate=75000000", - "video/x-raw,format=yuv422p,width=960,height=720,fps=0/0,bitrate=60000000", - "video/x-raw,format=yuv422p,width=960,height=720,fps=0/0,bitrate=42000000" + static VectorVideoCaps dnXhdSupportedCaps; + + if (!dnXhdSupportedCaps.isEmpty()) + return dnXhdSupportedCaps; + + struct CapsEx + { + AkVideoCaps caps; + quint64 bitrate; }; - VectorVideoCaps dnXhdSupportedCaps(supportedCaps.size()); + const QVector supportedCaps { + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {60000, 1001}}, 440000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {50, 1} }, 365000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {60000, 1001}}, 290000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {50, 1} }, 240000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {30000, 1001}}, 220000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {25, 1} }, 185000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {24000, 1001}}, 175000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {30000, 1001}}, 145000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {25, 1} }, 120000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {24000, 1001}}, 115000000}, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {60000, 1001}}, 90000000 }, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {24000, 1001}}, 36000000 }, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {25, 1} }, 36000000 }, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {30000, 1001}}, 45000000 }, + {{AkVideoCaps::Format_yuv422p, 1920, 1080, {50, 1} }, 75000000 }, + {{AkVideoCaps::Format_yuv422p, 1440, 1080, {0, 0} }, 110000000}, + {{AkVideoCaps::Format_yuv422p, 1440, 1080, {0, 0} }, 100000000}, + {{AkVideoCaps::Format_yuv422p, 1440, 1080, {0, 0} }, 90000000 }, + {{AkVideoCaps::Format_yuv422p, 1440, 1080, {0, 0} }, 84000000 }, + {{AkVideoCaps::Format_yuv422p, 1440, 1080, {0, 0} }, 80000000 }, + {{AkVideoCaps::Format_yuv422p, 1440, 1080, {0, 0} }, 63000000 }, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {60000, 1001}}, 220000000}, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {50, 1} }, 180000000}, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {60000, 1001}}, 145000000}, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {50, 1} }, 120000000}, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {30000, 1001}}, 110000000}, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {25, 1} }, 90000000 }, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {24000, 1001}}, 90000000 }, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {30000, 1001}}, 75000000 }, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {25, 1} }, 60000000 }, + {{AkVideoCaps::Format_yuv422p, 1280, 720 , {24000, 1001}}, 60000000 }, + {{AkVideoCaps::Format_yuv422p, 960 , 720 , {0, 0} }, 115000000}, + {{AkVideoCaps::Format_yuv422p, 960 , 720 , {0, 0} }, 75000000 }, + {{AkVideoCaps::Format_yuv422p, 960 , 720 , {0, 0} }, 60000000 }, + {{AkVideoCaps::Format_yuv422p, 960 , 720 , {0, 0} }, 42000000 }, + }; - for (int i = 0; i < dnXhdSupportedCaps.size(); i++) - dnXhdSupportedCaps[i] = supportedCaps[i]; + for (auto &capsEx: supportedCaps) { + dnXhdSupportedCaps << capsEx.caps; + dnXhdSupportedCaps.last().setProperty("bitrate", capsEx.bitrate); + } return dnXhdSupportedCaps; } -QVector MediaWriterFFmpegGlobal::initH261SupportedSize() +const QVector &MediaWriterFFmpegGlobal::initH261SupportedSize() { - const QVector supportedSize = { + static const QVector supportedSize = { QSize(352, 288), QSize(176, 144) }; @@ -1338,9 +1366,9 @@ return supportedSize; } -QVector MediaWriterFFmpegGlobal::initH263SupportedSize() +const QVector &MediaWriterFFmpegGlobal::initH263SupportedSize() { - const QVector supportedSize = { + static const QVector supportedSize = { QSize(1408, 1152), QSize(704, 576), QSize(352, 288), @@ -1351,9 +1379,9 @@ return supportedSize; } -QVector MediaWriterFFmpegGlobal::initGXFSupportedSize() +const QVector &MediaWriterFFmpegGlobal::initGXFSupportedSize() { - const QVector supportedSize = { + static const QVector supportedSize = { QSize(768, 576), // PAL QSize(640, 480) // NTSC }; @@ -1361,9 +1389,9 @@ return supportedSize; } -QVector MediaWriterFFmpegGlobal::initSWFSupportedSampleRates() +const QVector &MediaWriterFFmpegGlobal::initSWFSupportedSampleRates() { - const QVector supportedSampleRates = { + static const QVector supportedSampleRates = { 44100, 22050, 11025 @@ -1387,9 +1415,9 @@ return false; } -OptionTypeStrMap MediaWriterFFmpegGlobal::initFFOptionTypeStrMap() +const OptionTypeStrMap &MediaWriterFFmpegGlobal::initFFOptionTypeStrMap() { - const OptionTypeStrMap optionTypeStrMap = { + static const OptionTypeStrMap optionTypeStrMap = { {AV_OPT_TYPE_FLAGS , "flags" }, {AV_OPT_TYPE_INT , "number" }, {AV_OPT_TYPE_INT64 , "number" }, @@ -1569,7 +1597,7 @@ if (codec->sample_fmts) for (int i = 0; ; i++) { - AVSampleFormat sampleFormat = codec->sample_fmts[i]; + auto sampleFormat = codec->sample_fmts[i]; if (sampleFormat == AV_SAMPLE_FMT_NONE) break; @@ -1581,7 +1609,7 @@ char layout[1024]; if (codec->channel_layouts) - for (int i = 0; uint64_t channelLayout = codec->channel_layouts[i]; i++) { + for (int i = 0; auto channelLayout = codec->channel_layouts[i]; i++) { int channels = av_get_channel_layout_nb_channels(channelLayout); av_get_channel_layout_string(layout, 1024, channels, channelLayout); supportedChannelLayouts << QString(layout); @@ -1614,7 +1642,7 @@ break; default: break; - }; + } codecParams["supportedSampleRates"] = supportedSampleRates; codecParams["supportedSampleFormats"] = supportedSampleFormats; @@ -1655,7 +1683,7 @@ if (codec->supported_framerates) for (int i = 0; ; i++) { - AVRational frameRate = codec->supported_framerates[i]; + auto frameRate = codec->supported_framerates[i]; if (frameRate.num == 0 && frameRate.den == 0) break; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/mediawriterffmpeg.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/mediawriterffmpeg.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/mediawriterffmpeg.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/mediawriterffmpeg.h 2021-02-15 15:25:23.000000000 +0000 @@ -35,6 +35,7 @@ MediaWriterFFmpeg(QObject *parent=nullptr); ~MediaWriterFFmpeg(); + Q_INVOKABLE QString defaultFormat(); Q_INVOKABLE QString outputFormat() const; Q_INVOKABLE QVariantList streams() const; Q_INVOKABLE qint64 maxPacketQueueSize() const; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/videostream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/videostream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/videostream.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ffmpeg/src/videostream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -91,16 +91,18 @@ AkVideoCaps videoCaps(configs["caps"].value()); - QString pixelFormat = AkVideoCaps::pixelFormatToString(videoCaps.format()); - QStringList supportedPixelFormats = defaultCodecParams["supportedPixelFormats"].toStringList(); - - if (!supportedPixelFormats.isEmpty() && !supportedPixelFormats.contains(pixelFormat)) { - QString defaultPixelFormat = defaultCodecParams["defaultPixelFormat"].toString(); - videoCaps.format() = AkVideoCaps::pixelFormatFromString(defaultPixelFormat); - videoCaps.bpp() = AkVideoCaps::bitsPerPixel(videoCaps.format()); + auto pixelFormat = AkVideoCaps::pixelFormatToString(videoCaps.format()); + auto supportedPixelFormats = + defaultCodecParams["supportedPixelFormats"].toStringList(); + + if (!supportedPixelFormats.isEmpty() + && !supportedPixelFormats.contains(pixelFormat)) { + auto defaultPixelFormat = defaultCodecParams["defaultPixelFormat"].toString(); + videoCaps.setFormat(AkVideoCaps::pixelFormatFromString(defaultPixelFormat)); } - QVariantList supportedFrameRates = defaultCodecParams["supportedFrameRates"].toList(); + auto supportedFrameRates = + defaultCodecParams["supportedFrameRates"].toList(); if (!supportedFrameRates.isEmpty()) { AkFrac frameRate; @@ -139,20 +141,20 @@ videoCaps.setProperty("bitrate", QVariant()); break; case AV_CODEC_ID_ROQ: - videoCaps.width() = int(qPow(2, qRound(qLn(videoCaps.width()) / qLn(2)))); - videoCaps.height() = int(qPow(2, qRound(qLn(videoCaps.height()) / qLn(2)))); + videoCaps.setWidth(int(qPow(2, qRound(qLn(videoCaps.width()) / qLn(2))))); + videoCaps.setHeight(int(qPow(2, qRound(qLn(videoCaps.height()) / qLn(2))))); videoCaps.fps() = AkFrac(qRound(videoCaps.fps().value()), 1); break; case AV_CODEC_ID_RV10: - videoCaps.width() = 16 * qRound(videoCaps.width() / 16.); - videoCaps.height() = 16 * qRound(videoCaps.height() / 16.); + videoCaps.setWidth(16 * qRound(videoCaps.width() / 16.)); + videoCaps.setHeight(16 * qRound(videoCaps.height() / 16.)); break; case AV_CODEC_ID_AMV: - videoCaps.height() = 16 * qRound(videoCaps.height() / 16.); + videoCaps.setHeight(16 * qRound(videoCaps.height() / 16.)); break; case AV_CODEC_ID_XFACE: - videoCaps.width() = 48; - videoCaps.height() = 48; + videoCaps.setWidth(48); + videoCaps.setHeight(48); break; default: break; @@ -161,7 +163,7 @@ if (!strcmp(formatContext->oformat->name, "gxf")) videoCaps = mediaWriter->nearestGXFCaps(videoCaps); - QString pixelFormatStr = AkVideoCaps::pixelFormatToString(videoCaps.format()); + auto pixelFormatStr = AkVideoCaps::pixelFormatToString(videoCaps.format()); codecContext->pix_fmt = av_get_pix_fmt(pixelFormatStr.toStdString().c_str()); codecContext->width = videoCaps.width(); codecContext->height = videoCaps.height(); @@ -217,7 +219,7 @@ oFrame->height = codecContext->height; oFrame->pts = packet.pts(); - AkVideoPacket videoPacket = packet; + AkVideoPacket videoPacket(packet); auto image = videoPacket.toImage(); image = image.convertToFormat(QImage::Format_ARGB32); image = this->d->swapChannels(image); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/mediawritergstreamer.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/mediawritergstreamer.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/mediawritergstreamer.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/mediawritergstreamer.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -40,202 +40,14 @@ #define MINIMUM_PLUGIN_RANK GST_RANK_SECONDARY -using StringStringMap = QMap; - -inline StringStringMap initGstToFF() -{ - StringStringMap gstToFF { - // Audio - {"S8" , "s8" }, - {"U8" , "u8" }, - {"S16LE" , "s16le" }, - {"S16BE" , "s16be" }, - {"U16LE" , "u16le" }, - {"U16BE" , "u16be" }, - {"S24_32LE", "s2432le"}, - {"S24_32BE", "s2432be"}, - {"U24_32LE", "u2432le"}, - {"U24_32BE", "u2432be"}, - {"S32LE" , "s32le" }, - {"S32BE" , "s32be" }, - {"U32LE" , "u32le" }, - {"U32BE" , "u32be" }, - {"S24LE" , "s24le" }, - {"S24BE" , "s24be" }, - {"U24LE" , "u24le" }, - {"U24BE" , "u24be" }, - {"S20LE" , "s20le" }, - {"S20BE" , "s20be" }, - {"U20LE" , "u20le" }, - {"U20BE" , "u20be" }, - {"S18LE" , "s18le" }, - {"S18BE" , "s18be" }, - {"U18LE" , "u18le" }, - {"U18BE" , "u18le" }, - {"F32LE" , "fltle" }, - {"F32BE" , "fltbe" }, - {"F64LE" , "dblle" }, - {"F64BE" , "dblbe" }, - {"S16" , "s16" }, - {"U16" , "u16" }, - {"S24_32" , "s2432" }, - {"U24_32" , "u2432" }, - {"S32" , "s32" }, - {"U32" , "u32" }, - {"S24" , "s24" }, - {"U24" , "u24" }, - {"S20" , "s20" }, - {"U20" , "u20" }, - {"S18" , "s18" }, - {"U18" , "u18" }, - {"F32" , "flt" }, - {"F64" , "dbl" }, - - // Video - {"I420", "yuv420p"}, - //{"YV12", ""}, - {"YUY2", "yuyv422"}, - {"UYVY", "uyvy422"}, - //{"AYUV", ""}, - {"RGBx", "rgb0" }, - {"BGRx", "bgr0" }, - {"xRGB", "0rgb" }, - {"xBGR", "0bgr" }, - {"RGBA", "rgba" }, - {"BGRA", "bgra" }, - {"ARGB", "argb" }, - {"ABGR", "abgr" }, - {"RGB" , "rgb24" }, - {"BGR" , "bgr24" }, - {"Y41B", "yuv411p"}, - {"Y42B", "yuv422p"}, - //{"YVYU", ""}, - {"Y444" , "yuv444p" }, - {"v210" , "v210" }, - {"v216" , "v216" }, - {"NV12" , "nv12" }, - {"NV21" , "nv21" }, - {"GRAY8" , "gray8" }, - {"GRAY16_BE", "gray16be"}, - {"GRAY16_LE", "gray16le"}, - {"V308" , "v308" }, - {"RGB16" , "rgb565" }, - {"BGR16" , "bgr565le"}, - {"RGB15" , "rgb555" }, - {"BGR15" , "rgb555le"}, - //{"UYVP", ""}, - {"A420" , "yuva420p"}, - {"RGB8P", "pal8" }, - {"YUV9" , "yuv410p" }, - //{"YVU9" , ""}, - //{"IYU1" , ""}, - //{"ARGB64", ""}, - {"AYUV64", "ayuv64le"}, - //{"r210", ""}, - {"I420_10BE", "yuv420p10be"}, - {"I420_10LE", "yuv420p10le"}, - {"I422_10BE", "yuv422p10be"}, - {"I422_10LE", "yuv422p10le"}, - {"Y444_10BE", "yuv444p10be"}, - {"Y444_10LE", "yuv444p10le"}, - {"GBR" , "gbrp" }, - {"GBR_10BE" , "gbrp10be" }, - {"GBR_10LE" , "gbrp10le" }, - {"NV16" , "nv16" }, - //{"NV24" , ""}, - //{"NV12_64Z32", ""}, - {"A420_10BE", "yuva420p10be"}, - {"A420_10LE", "yuva420p10le"}, - {"A422_10BE", "yuva422p10be"}, - {"A422_10LE", "yuva422p10le"}, - {"A444_10BE", "yuva444p10be"}, - {"A444_10LE", "yuva444p10le"}, - //{"NV61", ""}, - }; - - return gstToFF; -} - -Q_GLOBAL_STATIC_WITH_ARGS(StringStringMap, gstToFF, (initGstToFF())) - -using VectorVideoCaps = QVector; - -inline VectorVideoCaps initDVSupportedCaps() -{ - QStringList supportedCaps = { - // Digital Video doesn't support height > 576 yet. - /*"video/x-raw,format=yuv422p,width=1440,height=1080,fps=25/1", - "video/x-raw,format=yuv422p,width=1280,height=1080,fps=30000/1001", - "video/x-raw,format=yuv422p,width=960,height=720,fps=60000/1001", - "video/x-raw,format=yuv422p,width=960,height=720,fps=50/1",*/ - "video/x-raw,format=yuv422p,width=720,height=576,fps=25/1", - "video/x-raw,format=yuv420p,width=720,height=576,fps=25/1", - "video/x-raw,format=yuv411p,width=720,height=576,fps=25/1", - "video/x-raw,format=yuv422p,width=720,height=480,fps=30000/1001", - "video/x-raw,format=yuv411p,width=720,height=480,fps=30000/1001" - }; - - VectorVideoCaps dvSupportedCaps(supportedCaps.size()); - - for (int i = 0; i < dvSupportedCaps.size(); i++) - dvSupportedCaps[i] = supportedCaps[i]; - - return dvSupportedCaps; -} - -Q_GLOBAL_STATIC_WITH_ARGS(VectorVideoCaps, dvSupportedCaps, (initDVSupportedCaps())) - using VectorInt = QVector; +using SizeList = QList; +using GstToSampleFormatMap = QMap; +using GstToPixelFormatMap = QMap; +using VectorVideoCaps = QVector; using StringVectorIntMap = QMap; - -inline StringVectorIntMap initFLVSupportedSampleRates() -{ - StringVectorIntMap flvSupportedSampleRates = { - {"avenc_adpcm_swf" , {5512, 11025, 22050, 44100 }}, - {"lamemp3enc" , {5512, 8000 , 11025, 22050, 44100 }}, - {"faac" , { }}, - {"avenc_nellymoser", {5512, 8000 , 11025, 16000, 22050, 44100}}, - {"identity" , {5512, 11025, 22050, 44100 }}, - {"alawenc" , {5512, 11025, 22050, 44100 }}, - {"mulawenc" , {5512, 11025, 22050, 44100 }}, - {"speexenc" , {16000 }} - }; - - return flvSupportedSampleRates; -} - -Q_GLOBAL_STATIC_WITH_ARGS(StringVectorIntMap, flvSupportedSampleRates, (initFLVSupportedSampleRates())) - using OptionTypeStrMap = QMap; -inline OptionTypeStrMap initGstOptionTypeStrMap() -{ - static const OptionTypeStrMap optionTypeStrMap = { - {G_TYPE_STRING , "string" }, - {G_TYPE_BOOLEAN , "boolean"}, - {G_TYPE_ULONG , "number" }, - {G_TYPE_LONG , "number" }, - {G_TYPE_UINT , "number" }, - {G_TYPE_INT , "number" }, - {G_TYPE_UINT64 , "number" }, - {G_TYPE_INT64 , "number" }, - {G_TYPE_FLOAT , "number" }, - {G_TYPE_DOUBLE , "number" }, - {G_TYPE_CHAR , "number" }, - {G_TYPE_UCHAR , "number" }, - {G_TYPE_PARAM_ENUM , "menu" }, - {G_TYPE_PARAM_FLAGS , "flags" }, - {GST_TYPE_CAPS , "caps" }, - {GST_TYPE_PARAM_FRACTION, "frac" }, - }; - - return optionTypeStrMap; -} - -Q_GLOBAL_STATIC_WITH_ARGS(OptionTypeStrMap, codecGstOptionTypeToStr, (initGstOptionTypeStrMap())) - -using SizeList = QList; - class MediaWriterGStreamerPrivate { public: @@ -274,6 +86,140 @@ AkVideoCaps nearestFrameSize(const AkVideoCaps &caps, const QList &frameSizes) const; + inline static const GstToSampleFormatMap &gstToSampleFormat() + { + static const GstToSampleFormatMap gstToFormat { + {AkAudioCaps::SampleFormat_s8 , "S8" }, + {AkAudioCaps::SampleFormat_u8 , "U8" }, + {AkAudioCaps::SampleFormat_s16le, "S16LE"}, + {AkAudioCaps::SampleFormat_s16be, "S16BE"}, + {AkAudioCaps::SampleFormat_u16le, "U16LE"}, + {AkAudioCaps::SampleFormat_u16be, "U16BE"}, + {AkAudioCaps::SampleFormat_s32le, "S32LE"}, + {AkAudioCaps::SampleFormat_s32be, "S32BE"}, + {AkAudioCaps::SampleFormat_u32le, "U32LE"}, + {AkAudioCaps::SampleFormat_u32be, "U32BE"}, + {AkAudioCaps::SampleFormat_fltle, "F32LE"}, + {AkAudioCaps::SampleFormat_fltbe, "F32BE"}, + {AkAudioCaps::SampleFormat_dblle, "F64LE"}, + {AkAudioCaps::SampleFormat_dblbe, "F64BE"}, + }; + + return gstToFormat; + } + + inline static const GstToPixelFormatMap &gstToPixelFormat() + { + static const GstToPixelFormatMap gstToFormat { + {AkVideoCaps::Format_yuv420p , "I420" }, + {AkVideoCaps::Format_yuyv422 , "YUY2" }, + {AkVideoCaps::Format_uyvy422 , "UYVY" }, + {AkVideoCaps::Format_rgb0 , "RGBx" }, + {AkVideoCaps::Format_bgr0 , "BGRx" }, + {AkVideoCaps::Format_0rgb , "xRGB" }, + {AkVideoCaps::Format_0bgr , "xBGR" }, + {AkVideoCaps::Format_rgba , "RGBA" }, + {AkVideoCaps::Format_bgra , "BGRA" }, + {AkVideoCaps::Format_argb , "ARGB" }, + {AkVideoCaps::Format_abgr , "ABGR" }, + {AkVideoCaps::Format_rgb24 , "RGB" }, + {AkVideoCaps::Format_bgr24 , "BGR" }, + {AkVideoCaps::Format_yuv411p , "Y41B" }, + {AkVideoCaps::Format_yuv422p , "Y42B" }, + {AkVideoCaps::Format_yuv444p , "Y444" }, + {AkVideoCaps::Format_nv12 , "NV12" }, + {AkVideoCaps::Format_nv21 , "NV21" }, + {AkVideoCaps::Format_gray , "GRAY8" }, + {AkVideoCaps::Format_gray16be , "GRAY16_BE"}, + {AkVideoCaps::Format_gray16le , "GRAY16_LE"}, + {AkVideoCaps::Format_rgb565le , "RGB16" }, + {AkVideoCaps::Format_bgr565le , "BGR16" }, + {AkVideoCaps::Format_rgb555le , "RGB15" }, + {AkVideoCaps::Format_rgb555le , "BGR15" }, + {AkVideoCaps::Format_yuva420p , "A420" }, + {AkVideoCaps::Format_pal8 , "RGB8P" }, + {AkVideoCaps::Format_yuv410p , "YUV9" }, + {AkVideoCaps::Format_ayuv64le , "AYUV64" }, + {AkVideoCaps::Format_yuv420p10be , "I420_10BE"}, + {AkVideoCaps::Format_yuv420p10le , "I420_10LE"}, + {AkVideoCaps::Format_yuv422p10be , "I422_10BE"}, + {AkVideoCaps::Format_yuv422p10le , "I422_10LE"}, + {AkVideoCaps::Format_yuv444p10be , "Y444_10BE"}, + {AkVideoCaps::Format_yuv444p10le , "Y444_10LE"}, + {AkVideoCaps::Format_gbrp , "GBR" }, + {AkVideoCaps::Format_gbrp10be , "GBR_10BE" }, + {AkVideoCaps::Format_gbrp10le , "GBR_10LE" }, + {AkVideoCaps::Format_nv16 , "NV16" }, + {AkVideoCaps::Format_yuva420p10be, "A420_10BE"}, + {AkVideoCaps::Format_yuva420p10le, "A420_10LE"}, + {AkVideoCaps::Format_yuva422p10be, "A422_10BE"}, + {AkVideoCaps::Format_yuva422p10le, "A422_10LE"}, + {AkVideoCaps::Format_yuva444p10be, "A444_10BE"}, + {AkVideoCaps::Format_yuva444p10le, "A444_10LE"}, + }; + + return gstToFormat; + } + + inline static const VectorVideoCaps &dvSupportedCaps() + { + static const VectorVideoCaps dvSupportedCaps { + // Digital Video doesn't support height > 576 yet. + /* + {AkVideoCaps::Format_yuv422p, 1440, 1080, {25, 1} }, + {AkVideoCaps::Format_yuv422p, 1280, 1080, {30000, 1001}}, + {AkVideoCaps::Format_yuv422p, 960 , 720 , {60000, 1001}}, + {AkVideoCaps::Format_yuv422p, 960 , 720 , {50, 1} },*/ + {AkVideoCaps::Format_yuv422p, 720 , 576 , {25, 1} }, + {AkVideoCaps::Format_yuv420p, 720 , 576 , {25, 1} }, + {AkVideoCaps::Format_yuv411p, 720 , 576 , {25, 1} }, + {AkVideoCaps::Format_yuv422p, 720 , 480 , {30000, 1001}}, + {AkVideoCaps::Format_yuv411p, 720 , 480 , {30000, 1001}}, + }; + + return dvSupportedCaps; + } + + inline static const StringVectorIntMap &flvSupportedSampleRates() + { + static const StringVectorIntMap flvSupportedSampleRates { + {"avenc_adpcm_swf" , {5512, 11025, 22050, 44100} }, + {"lamemp3enc" , {5512, 8000 , 11025, 22050, 44100} }, + {"faac" , {} }, + {"avenc_nellymoser", {5512, 8000 , 11025, 16000, 22050, 44100}}, + {"identity" , {5512, 11025, 22050, 44100} }, + {"alawenc" , {5512, 11025, 22050, 44100} }, + {"mulawenc" , {5512, 11025, 22050, 44100} }, + {"speexenc" , {16000} }, + }; + + return flvSupportedSampleRates; + } + + inline static const OptionTypeStrMap &codecGstOptionTypeToStr() + { + static const OptionTypeStrMap optionTypeStrMap { + {G_TYPE_STRING , "string" }, + {G_TYPE_BOOLEAN , "boolean"}, + {G_TYPE_ULONG , "number" }, + {G_TYPE_LONG , "number" }, + {G_TYPE_UINT , "number" }, + {G_TYPE_INT , "number" }, + {G_TYPE_UINT64 , "number" }, + {G_TYPE_INT64 , "number" }, + {G_TYPE_FLOAT , "number" }, + {G_TYPE_DOUBLE , "number" }, + {G_TYPE_CHAR , "number" }, + {G_TYPE_UCHAR , "number" }, + {G_TYPE_PARAM_ENUM , "menu" }, + {G_TYPE_PARAM_FLAGS , "flags" }, + {GST_TYPE_CAPS , "caps" }, + {GST_TYPE_PARAM_FRACTION, "frac" }, + }; + + return optionTypeStrMap; + } + template inline static R align(R value, S align) { @@ -285,7 +231,6 @@ MediaWriter(parent) { this->d = new MediaWriterGStreamerPrivate(this); - // setenv("GST_DEBUG", "2", 1); gst_init(nullptr, nullptr); @@ -302,6 +247,19 @@ delete this->d; } +QString MediaWriterGStreamer::defaultFormat() +{ + auto formats = this->supportedFormats(); + + if (formats.isEmpty()) + return {}; + + if (formats.contains("webmmux")) + return QStringLiteral("webmmux"); + + return formats.first(); +} + QString MediaWriterGStreamer::outputFormat() const { return this->d->m_outputFormat; @@ -702,12 +660,16 @@ if (codecType == "audio/x-raw") { if (codec.startsWith("identity/audio")) { - auto sampleFormat = gstToFF->value(codec.split("/").at(2), "s16"); + auto gstFormat = codec.split("/").at(2); + auto sampleFormat = + MediaWriterGStreamerPrivate::gstToSampleFormat().key(gstFormat, + AkAudioCaps::SampleFormat_none); + auto sampleFormatStr = AkAudioCaps::sampleFormatToString(sampleFormat); codecParams["defaultBitRate"] = 128000; - codecParams["supportedSampleFormats"] = QStringList {sampleFormat}; + codecParams["supportedSampleFormats"] = QStringList {sampleFormatStr}; codecParams["supportedChannelLayouts"] = QStringList {"mono", "stereo"}; codecParams["supportedSampleRates"] = QVariantList(); - codecParams["defaultSampleFormat"] = sampleFormat; + codecParams["defaultSampleFormat"] = sampleFormatStr; codecParams["defaultChannelLayout"] = "stereo"; codecParams["defaultChannels"] = 2; codecParams["defaultSampleRate"] = 44100; @@ -758,21 +720,31 @@ GType fieldType = gst_structure_get_field_type(capsStructure, "format"); if (fieldType == G_TYPE_STRING) { - const gchar *format = gst_structure_get_string(capsStructure, "format"); - auto formatFF = gstToFF->value(format, ""); - - if (!formatFF.isEmpty() && !supportedSampleFormats.contains(formatFF)) - supportedSampleFormats << formatFF; + auto format = gst_structure_get_string(capsStructure, "format"); + auto formatFF = + MediaWriterGStreamerPrivate::gstToSampleFormat().key(format, + AkAudioCaps::SampleFormat_none); + auto formatFFStr = AkAudioCaps::sampleFormatToString(formatFF); + + if (!formatFFStr.isEmpty() + && formatFFStr != "none" + && !supportedSampleFormats.contains(formatFFStr)) + supportedSampleFormats << formatFFStr; } else if (fieldType == GST_TYPE_LIST) { const GValue *formats = gst_structure_get_value(capsStructure, "format"); for (guint i = 0; i < gst_value_list_get_size(formats); i++) { auto format = gst_value_list_get_value(formats, i); auto formatId = g_value_get_string(format); - auto formatFF = gstToFF->value(formatId, ""); - - if (!formatFF.isEmpty() && !supportedSampleFormats.contains(formatFF)) - supportedSampleFormats << formatFF; + auto formatFF = + MediaWriterGStreamerPrivate::gstToSampleFormat().key(formatId, + AkAudioCaps::SampleFormat_none); + auto formatFFStr = AkAudioCaps::sampleFormatToString(formatFF); + + if (!formatFFStr.isEmpty() + && formatFFStr != "none" + && !supportedSampleFormats.contains(formatFFStr)) + supportedSampleFormats << formatFFStr; } } } @@ -877,12 +849,12 @@ codecParams["supportedSampleFormats"] = supportedSampleFormats; codecParams["supportedChannelLayouts"] = supportedChannelLayouts; codecParams["supportedSampleRates"] = supportedSamplerates; - - codecParams["defaultSampleFormat"] = supportedSampleFormats.isEmpty()? - QString("s16"): supportedSampleFormats.at(0); - - QString channelLayout = supportedChannelLayouts.isEmpty()? - QString("stereo"): supportedChannelLayouts.at(0); + codecParams["defaultSampleFormat"] = + supportedSampleFormats.isEmpty()? + QString("s16"): supportedSampleFormats.at(0); + QString channelLayout = + supportedChannelLayouts.isEmpty()? + QString("stereo"): supportedChannelLayouts.at(0); codecParams["defaultChannelLayout"] = channelLayout; codecParams["defaultChannels"] = AkAudioCaps::channelCount(channelLayout); codecParams["defaultSampleRate"] = supportedSamplerates.isEmpty()? @@ -894,13 +866,17 @@ } } else if (codecType == "video/x-raw") { if (codec.startsWith("identity/video")) { - QString pixelFormat = gstToFF->value(codec.split("/").at(2), "yuv420p"); + auto gstFormat = codec.split("/").at(2); + auto pixelFormat = + MediaWriterGStreamerPrivate::gstToPixelFormat().key(gstFormat, + AkVideoCaps::Format_none); + auto pixelFormatStr = AkVideoCaps::pixelFormatToString(pixelFormat); codecParams["defaultBitRate"] = 1500000; codecParams["defaultGOP"] = 12; codecParams["supportedFrameRates"] = QVariantList(); - codecParams["supportedPixelFormats"] = QStringList {pixelFormat}; + codecParams["supportedPixelFormats"] = QStringList {pixelFormatStr}; codecParams["supportedFrameSizes"] = QVariantList(); - codecParams["defaultPixelFormat"] = pixelFormat; + codecParams["defaultPixelFormat"] = pixelFormatStr; } else { auto factory = gst_element_factory_find(codec.toStdString().c_str()); @@ -945,20 +921,32 @@ if (fieldType == G_TYPE_STRING) { auto format = gst_structure_get_string(capsStructure, "format"); - auto formatFF = gstToFF->value(format, ""); - - if (!formatFF.isEmpty() && !supportedPixelFormats.contains(formatFF)) - supportedPixelFormats << formatFF; + auto formatFF = + MediaWriterGStreamerPrivate::gstToPixelFormat() + .key(format, AkVideoCaps::Format_none); + auto formatFFStr = + AkVideoCaps::pixelFormatToString(formatFF); + + if (!formatFFStr.isEmpty() + && formatFFStr != "none" + && !supportedPixelFormats.contains(formatFFStr)) + supportedPixelFormats << formatFFStr; } else if (fieldType == GST_TYPE_LIST) { auto formats = gst_structure_get_value(capsStructure, "format"); for (guint i = 0; i < gst_value_list_get_size(formats); i++) { auto format = gst_value_list_get_value(formats, i); auto formatId = g_value_get_string(format); - auto formatFF = gstToFF->value(formatId, ""); - - if (!formatFF.isEmpty() && !supportedPixelFormats.contains(formatFF)) - supportedPixelFormats << formatFF; + auto formatFF = + MediaWriterGStreamerPrivate::gstToPixelFormat() + .key(formatId, AkVideoCaps::Format_none); + auto formatFFStr = + AkVideoCaps::pixelFormatToString(formatFF); + + if (!formatFFStr.isEmpty() + && formatFFStr != "none" + && !supportedPixelFormats.contains(formatFFStr)) + supportedPixelFormats << formatFFStr; } } } @@ -1335,7 +1323,7 @@ } if (modified) - emit this->codecOptionsChanged(optKey, this->d->m_formatOptions.value(optKey)); + emit this->codecOptionsChanged(optKey, this->d->m_codecOptions.value(optKey)); } void MediaWriterGStreamer::resetOutputFormat() @@ -1450,8 +1438,8 @@ if (!supportedSampleFormats.isEmpty() && !supportedSampleFormats.contains(sampleFormat)) { auto defaultSampleFormat = codecDefaults["defaultSampleFormat"].toString(); - audioCaps.format() = AkAudioCaps::sampleFormatFromString(defaultSampleFormat); - audioCaps.bps() = AkAudioCaps::bitsPerSample(defaultSampleFormat); + auto format = AkAudioCaps::sampleFormatFromString(defaultSampleFormat); + audioCaps.setFormat(format); } auto supportedSampleRates = codecDefaults["supportedSampleRates"].toList(); @@ -1462,18 +1450,16 @@ if (!supportedChannelLayouts.isEmpty() && !supportedChannelLayouts.contains(channelLayout)) { auto defaultChannelLayout = codecDefaults["defaultChannelLayout"].toString(); - audioCaps.layout() = AkAudioCaps::channelLayoutFromString(defaultChannelLayout); - audioCaps.channels() = AkAudioCaps::channelCount(defaultChannelLayout); - }; + auto layout = AkAudioCaps::channelLayoutFromString(defaultChannelLayout); + audioCaps.setLayout(layout); + } if (outputFormat == "flvmux") { audioCaps = this->d->nearestFLVAudioCaps(audioCaps, codec); QStringList codecs {"speexenc", "avenc_nellymoser"}; - if (codecs.contains(codec)) { - audioCaps.channels() = 1; - audioCaps.layout() = AkAudioCaps::Layout_mono; - } + if (codecs.contains(codec)) + audioCaps.setLayout(AkAudioCaps::Layout_mono); } else if (outputFormat == "avmux_dv") { audioCaps.rate() = 48000; } else if (outputFormat == "avmux_gxf" @@ -1484,9 +1470,9 @@ audioCaps.rate() = qBound(8000, audioCaps.rate(), 96000); } - auto format = AkAudioCaps::sampleFormatToString(audioCaps.format()); - auto gstFormat = gstToFF->key(format, "S16"); - + auto gstFormat = + MediaWriterGStreamerPrivate::gstToSampleFormat() + .value(audioCaps.format(), "S16"); auto gstAudioCaps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, gstFormat.toStdString().c_str(), @@ -1554,8 +1540,7 @@ if (!supportedPixelFormats.isEmpty() && !supportedPixelFormats.contains(pixelFormat)) { auto defaultPixelFormat = codecDefaults["defaultPixelFormat"].toString(); - videoCaps.format() = AkVideoCaps::pixelFormatFromString(defaultPixelFormat); - videoCaps.bpp() = AkVideoCaps::bitsPerPixel(videoCaps.format()); + videoCaps.setFormat(AkVideoCaps::pixelFormatFromString(defaultPixelFormat)); } auto supportedFrameSizes = codecDefaults["supportedFrameSizes"].value(); @@ -1568,10 +1553,10 @@ if (codec == "avenc_dvvideo") videoCaps = this->d->nearestDVCaps(videoCaps); - auto format = AkVideoCaps::pixelFormatToString(videoCaps.format()); - auto gstFormat = gstToFF->key(format, "I420"); - videoCaps.width() = - MediaWriterGStreamerPrivate::align(videoCaps.width(), 4); + auto gstFormat = + MediaWriterGStreamerPrivate::gstToPixelFormat() + .value(videoCaps.format(), "I420"); + videoCaps.setWidth(MediaWriterGStreamerPrivate::align(videoCaps.width(), 4)); auto gstVideoCaps = gst_caps_new_simple("video/x-raw", @@ -1769,18 +1754,9 @@ return; auto sourceCaps = gst_app_src_get_caps(GST_APP_SRC(source)); - - auto iFormat = AkAudioCaps::sampleFormatToString(packet.caps().format()); - iFormat = gstToFF->key(iFormat, "S16"); - -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - QString fEnd = "LE"; -#elif Q_BYTE_ORDER == Q_BIG_ENDIAN - QString fEnd = "BE"; -#endif - - if (!iFormat.endsWith(fEnd)) - iFormat += fEnd; + auto iFormat = + MediaWriterGStreamerPrivate::gstToSampleFormat() + .value(packet.caps().format(), "S16LE"); auto inputCaps = gst_caps_new_simple("audio/x-raw", @@ -1841,7 +1817,7 @@ if (streamIndex < 0) return; - auto videoPacket = packet.roundSizeTo(4).convert(AkVideoCaps::Format_rgb24); + auto videoPacket = packet.convert(AkVideoCaps::Format_rgb24, 32); auto souceName = QString("video_%1").arg(streamIndex); auto source = gst_bin_get_by_name(GST_BIN(this->d->m_pipeline), @@ -1851,9 +1827,8 @@ return; auto sourceCaps = gst_app_src_get_caps(GST_APP_SRC(source)); - - auto iFormat = AkVideoCaps::pixelFormatToString(videoPacket.caps().format()); - iFormat = gstToFF->key(iFormat, "BGR"); + auto iFormat = MediaWriterGStreamerPrivate::gstToPixelFormat() + .value(videoPacket.caps().format(), "BGR"); auto inputCaps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, iFormat.toStdString().c_str(), @@ -2000,7 +1975,7 @@ qreal max = 0; qreal step = 0; QVariantList menu; - auto paramType = codecGstOptionTypeToStr->value(param->value_type); + auto paramType = MediaWriterGStreamerPrivate::codecGstOptionTypeToStr().value(param->value_type); GValue gValue; memset(&gValue, 0, sizeof(GValue)); @@ -2174,7 +2149,7 @@ paramType = "frac"; } else if (param->value_type == GST_TYPE_CAPS) { auto caps = gst_caps_to_string(gst_value_get_caps(&gValue)); - value = QVariant::fromValue(AkCaps(caps)); + value = QString(caps); g_free(caps); defaultValue = value; paramType = "caps"; @@ -2430,7 +2405,7 @@ AkVideoCaps nearestCaps; qreal q = std::numeric_limits::max(); - for (auto &sCaps: *dvSupportedCaps) { + for (auto &sCaps: MediaWriterGStreamerPrivate::dvSupportedCaps()) { qreal dw = sCaps.width() - caps.width(); qreal dh = sCaps.height() - caps.height(); qreal df = sCaps.fps().value() - caps.fps().value(); @@ -2451,8 +2426,9 @@ { int nearestSampleRate = caps.rate(); int q = std::numeric_limits::max(); + auto &sampleRates = MediaWriterGStreamerPrivate::flvSupportedSampleRates(); - for (auto &sampleRate: flvSupportedSampleRates->value(codec)) { + for (auto &sampleRate: sampleRates.value(codec)) { int k = qAbs(sampleRate - caps.rate()); if (k < q) { @@ -2572,8 +2548,8 @@ } AkVideoCaps nearestCaps(caps); - nearestCaps.width() = nearestSize.width(); - nearestCaps.height() = nearestSize.height(); + nearestCaps.setWidth(nearestSize.width()); + nearestCaps.setHeight(nearestSize.height()); return nearestCaps; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/mediawritergstreamer.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/mediawritergstreamer.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/mediawritergstreamer.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/mediawritergstreamer.h 2021-02-15 15:25:23.000000000 +0000 @@ -34,9 +34,9 @@ MediaWriterGStreamer(QObject *parent=nullptr); ~MediaWriterGStreamer(); + Q_INVOKABLE QString defaultFormat(); Q_INVOKABLE QString outputFormat() const; Q_INVOKABLE QVariantList streams() const; - Q_INVOKABLE QStringList supportedFormats(); Q_INVOKABLE QStringList fileExtensions(const QString &format); Q_INVOKABLE QString formatDescription(const QString &format); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/outputparams.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/outputparams.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/outputparams.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/outputparams.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,41 +19,50 @@ #include "outputparams.h" +class OutputParamsPrivate +{ + public: + int m_inputIndex {-1}; + quint64 m_nFrame {0}; + qint64 m_id {-1}; + qint64 m_pts {0}; + qint64 m_ptsDiff {0}; + qint64 m_ptsDrift {0}; +}; + OutputParams::OutputParams(int inputIndex, QObject *parent): - QObject(parent), - m_inputIndex(inputIndex), - m_nFrame(0), - m_id(-1), - m_pts(0), - m_ptsDiff(0), - m_ptsDrift(0) + QObject(parent) { + this->d = new OutputParamsPrivate; + this->d->m_inputIndex = inputIndex; } OutputParams::OutputParams(const OutputParams &other): - QObject(other.parent()), - m_inputIndex(other.m_inputIndex), - m_nFrame(other.m_nFrame), - m_id(other.m_id), - m_pts(other.m_pts), - m_ptsDiff(other.m_ptsDiff), - m_ptsDrift(other.m_ptsDrift) + QObject(other.parent()) { + this->d = new OutputParamsPrivate; + this->d->m_inputIndex = other.d->m_inputIndex; + this->d->m_nFrame = other.d->m_nFrame; + this->d->m_id = other.d->m_id; + this->d->m_pts = other.d->m_pts; + this->d->m_ptsDiff = other.d->m_ptsDiff; + this->d->m_ptsDrift = other.d->m_ptsDrift; } OutputParams::~OutputParams() { + delete this->d; } OutputParams &OutputParams::operator =(const OutputParams &other) { if (this != &other) { - this->m_inputIndex = other.m_inputIndex; - this->m_nFrame = other.m_nFrame; - this->m_id = other.m_id; - this->m_pts = other.m_pts; - this->m_ptsDiff = other.m_ptsDiff; - this->m_ptsDrift = other.m_ptsDrift; + this->d->m_inputIndex = other.d->m_inputIndex; + this->d->m_nFrame = other.d->m_nFrame; + this->d->m_id = other.d->m_id; + this->d->m_pts = other.d->m_pts; + this->d->m_ptsDiff = other.d->m_ptsDiff; + this->d->m_ptsDrift = other.d->m_ptsDrift; } return *this; @@ -61,63 +70,63 @@ int OutputParams::inputIndex() const { - return this->m_inputIndex; + return this->d->m_inputIndex; } int &OutputParams::inputIndex() { - return this->m_inputIndex; + return this->d->m_inputIndex; } quint64 OutputParams::nFrame() const { - return this->m_nFrame; + return this->d->m_nFrame; } quint64 &OutputParams::nFrame() { - return this->m_nFrame; + return this->d->m_nFrame; } qint64 OutputParams::nextPts(qint64 pts, qint64 id) { - if (this->m_pts < 0 || this->m_id < 0) { - this->m_ptsDrift = -pts; - this->m_pts = pts; - this->m_id = id; + if (this->d->m_pts < 0 || this->d->m_id < 0) { + this->d->m_ptsDrift = -pts; + this->d->m_pts = pts; + this->d->m_id = id; return 0; } - if (pts <= this->m_pts || id != this->m_id) { - this->m_ptsDrift += this->m_pts - pts + this->m_ptsDiff; - this->m_pts = pts; - this->m_id = id; + if (pts <= this->d->m_pts || id != this->d->m_id) { + this->d->m_ptsDrift += this->d->m_pts - pts + this->d->m_ptsDiff; + this->d->m_pts = pts; + this->d->m_id = id; - return pts + this->m_ptsDrift; + return pts + this->d->m_ptsDrift; } - this->m_ptsDiff = pts - this->m_pts; - this->m_pts = pts; + this->d->m_ptsDiff = pts - this->d->m_pts; + this->d->m_pts = pts; - return pts + this->m_ptsDrift; + return pts + this->d->m_ptsDrift; } void OutputParams::setInputIndex(int inputIndex) { - if (this->m_inputIndex == inputIndex) + if (this->d->m_inputIndex == inputIndex) return; - this->m_inputIndex = inputIndex; + this->d->m_inputIndex = inputIndex; emit this->inputIndexChanged(inputIndex); } void OutputParams::setNFrame(quint64 nFrame) { - if (this->m_nFrame == nFrame) + if (this->d->m_nFrame == nFrame) return; - this->m_nFrame = nFrame; + this->d->m_nFrame = nFrame; emit this->nFrameChanged(nFrame); } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/outputparams.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/outputparams.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/outputparams.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/gstreamer/src/outputparams.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,8 @@ #include +class OutputParamsPrivate; + class OutputParams: public QObject { Q_OBJECT @@ -50,12 +52,7 @@ Q_INVOKABLE qint64 nextPts(qint64 pts, qint64 id); private: - int m_inputIndex; - quint64 m_nFrame; - qint64 m_id; - qint64 m_pts; - qint64 m_ptsDiff; - qint64 m_ptsDrift; + OutputParamsPrivate *d; signals: void inputIndexChanged(int inputIndex); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/mediawriter.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/mediawriter.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/mediawriter.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/mediawriter.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -33,14 +33,19 @@ return this->m_location; } +QString MediaWriter::defaultFormat() +{ + return {}; +} + QString MediaWriter::outputFormat() const { - return QString(); + return {}; } QVariantList MediaWriter::streams() const { - return QVariantList(); + return {}; } qint64 MediaWriter::maxPacketQueueSize() const @@ -60,33 +65,33 @@ QStringList MediaWriter::supportedFormats() { - return QStringList(); + return {}; } QStringList MediaWriter::fileExtensions(const QString &format) { Q_UNUSED(format) - return QStringList(); + return {}; } QString MediaWriter::formatDescription(const QString &format) { Q_UNUSED(format) - return QString(); + return {}; } QVariantList MediaWriter::formatOptions() { - return QVariantList(); + return {}; } QStringList MediaWriter::supportedCodecs(const QString &format) { Q_UNUSED(format) - return QStringList(); + return {}; } QStringList MediaWriter::supportedCodecs(const QString &format, @@ -95,7 +100,7 @@ Q_UNUSED(format) Q_UNUSED(type) - return QStringList(); + return {}; } QString MediaWriter::defaultCodec(const QString &format, const QString &type) @@ -110,21 +115,21 @@ { Q_UNUSED(codec) - return QString(); + return {}; } QString MediaWriter::codecType(const QString &codec) { Q_UNUSED(codec) - return QString(); + return {}; } QVariantMap MediaWriter::defaultCodecParams(const QString &codec) { Q_UNUSED(codec) - return QVariantMap(); + return {}; } QVariantMap MediaWriter::addStream(int streamIndex, const AkCaps &streamCaps) @@ -132,7 +137,7 @@ Q_UNUSED(streamIndex) Q_UNUSED(streamCaps) - return QVariantMap(); + return {}; } QVariantMap MediaWriter::addStream(int streamIndex, @@ -143,14 +148,14 @@ Q_UNUSED(streamCaps) Q_UNUSED(codecParams) - return QVariantMap(); + return {}; } QVariantMap MediaWriter::updateStream(int index) { Q_UNUSED(index) - return QVariantMap(); + return {}; } QVariantMap MediaWriter::updateStream(int index, const QVariantMap &codecParams) @@ -158,14 +163,14 @@ Q_UNUSED(index) Q_UNUSED(codecParams) - return QVariantMap(); + return {}; } QVariantList MediaWriter::codecOptions(int index) { Q_UNUSED(index) - return QVariantList(); + return {}; } void MediaWriter::setLocation(const QString &location) @@ -179,12 +184,12 @@ void MediaWriter::setOutputFormat(const QString &outputFormat) { - Q_UNUSED(outputFormat); + Q_UNUSED(outputFormat) } void MediaWriter::setFormatOptions(const QVariantMap &formatOptions) { - Q_UNUSED(formatOptions); + Q_UNUSED(formatOptions) } void MediaWriter::setCodecOptions(int index, const QVariantMap &codecOptions) @@ -195,7 +200,7 @@ void MediaWriter::setMaxPacketQueueSize(qint64 maxPacketQueueSize) { - Q_UNUSED(maxPacketQueueSize); + Q_UNUSED(maxPacketQueueSize) } void MediaWriter::setFormatsBlackList(const QStringList &formatsBlackList) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/mediawriter.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/mediawriter.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/mediawriter.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/mediawriter.h 2021-02-15 15:25:23.000000000 +0000 @@ -33,6 +33,9 @@ WRITE setLocation RESET resetLocation NOTIFY locationChanged) + Q_PROPERTY(QString defaultFormat + READ defaultFormat + NOTIFY defaultFormatChanged) Q_PROPERTY(QString outputFormat READ outputFormat WRITE setOutputFormat @@ -62,6 +65,7 @@ virtual ~MediaWriter() = default; Q_INVOKABLE virtual QString location() const; + Q_INVOKABLE virtual QString defaultFormat(); Q_INVOKABLE virtual QString outputFormat() const; Q_INVOKABLE virtual QVariantList streams() const; Q_INVOKABLE virtual qint64 maxPacketQueueSize() const; @@ -97,6 +101,7 @@ signals: void locationChanged(const QString &location); + void defaultFormatChanged(const QString &defaultFormat); void outputFormatChanged(const QString &outputFormat); void formatOptionsChanged(const QVariantMap &formatOptions); void codecOptionsChanged(const QString &key, diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisink.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisink.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisink.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisink.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include "multisink.h" #include "multisinkelement.h" +#include "multisinkelementsettings.h" QObject *MultiSink::create(const QString &key, const QString &specification) { @@ -26,13 +27,16 @@ if (key == AK_PLUGIN_TYPE_ELEMENT) return new MultiSinkElement(); + else if (key == AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + return new MultiSinkElementSettings(); return nullptr; } QStringList MultiSink::keys() const { - return QStringList(); + return {AK_PLUGIN_TYPE_ELEMENT, + AK_PLUGIN_TYPE_ELEMENT_SETTINGS}; } #include "moc_multisink.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -22,12 +22,10 @@ #include #include "multisinkelement.h" -#include "multisinkglobals.h" +#include "multisinkelementsettings.h" #include "mediawriter.h" #include "multisinkutils.h" -Q_GLOBAL_STATIC(MultiSinkGlobals, globalMultiSink) - template inline QSharedPointer ptr_cast(QObject *obj=nullptr) { @@ -39,6 +37,8 @@ class MultiSinkElementPrivate { public: + MultiSinkElement *self; + MultiSinkElementSettings m_settings; QString m_location; QVariantList m_userControls; QVariantMap m_userControlsValues; @@ -55,23 +55,22 @@ QMap m_codecDescription; QMap m_codecType; QMap m_defaultCodecParams; + + explicit MultiSinkElementPrivate(MultiSinkElement *self); + void codecLibUpdated(const QString &codecLib); }; MultiSinkElement::MultiSinkElement(): AkElement() { - this->d = new MultiSinkElementPrivate; + this->d = new MultiSinkElementPrivate(this); + QObject::connect(&this->d->m_settings, + &MultiSinkElementSettings::codecLibChanged, + [this] (const QString &codecLib) { + this->d->codecLibUpdated(codecLib); + }); - QObject::connect(globalMultiSink, - SIGNAL(codecLibChanged(const QString &)), - this, - SIGNAL(codecLibChanged(const QString &))); - QObject::connect(globalMultiSink, - SIGNAL(codecLibChanged(const QString &)), - this, - SLOT(codecLibUpdated(const QString &))); - - this->codecLibUpdated(globalMultiSink->codecLib()); + this->d->codecLibUpdated(this->d->m_settings.codecLib()); } MultiSinkElement::~MultiSinkElement() @@ -85,6 +84,14 @@ return this->d->m_location; } +QString MultiSinkElement::defaultFormat() const +{ + if (!this->d->m_mediaWriter) + return {}; + + return this->d->m_mediaWriter->defaultFormat(); +} + QStringList MultiSinkElement::supportedFormats() const { return this->d->m_supportedFormats; @@ -106,11 +113,6 @@ return this->d->m_mediaWriter->streams(); } -QString MultiSinkElement::codecLib() const -{ - return globalMultiSink->codecLib(); -} - bool MultiSinkElement::showFormatOptions() const { return this->d->m_showFormatOptions; @@ -273,11 +275,6 @@ this->d->m_mediaWriter->setCodecOptions(index, codecOptions); } -void MultiSinkElement::setCodecLib(const QString &codecLib) -{ - globalMultiSink->setCodecLib(codecLib); -} - void MultiSinkElement::setShowFormatOptions(bool showFormatOptions) { if (this->d->m_showFormatOptions == showFormatOptions) @@ -340,11 +337,6 @@ this->d->m_mediaWriter->resetCodecOptions(index); } -void MultiSinkElement::resetCodecLib() -{ - globalMultiSink->resetCodecLib(); -} - void MultiSinkElement::resetShowFormatOptions() { this->setShowFormatOptions(false); @@ -411,91 +403,101 @@ return AkElement::setState(state); } -void MultiSinkElement::codecLibUpdated(const QString &codecLib) +MultiSinkElementPrivate::MultiSinkElementPrivate(MultiSinkElement *self): + self(self) { - auto state = this->state(); - this->setState(AkElement::ElementStateNull); + +} + +void MultiSinkElementPrivate::codecLibUpdated(const QString &codecLib) +{ + auto state = self->state(); + self->setState(AkElement::ElementStateNull); QString location; - if (this->d->m_mediaWriter) - location = this->d->m_mediaWriter->location(); + if (this->m_mediaWriter) + location = this->m_mediaWriter->location(); - this->d->m_mediaWriter = + this->m_mediaWriter = ptr_cast(MultiSinkElement::loadSubModule("MultiSink", codecLib)); - if (!this->d->m_mediaWriter) + if (!this->m_mediaWriter) return; - this->d->m_supportedFormats.clear(); - this->d->m_fileExtensions.clear(); - this->d->m_formatDescription.clear(); - this->d->m_supportedCodecs.clear(); - this->d->m_codecDescription.clear(); - this->d->m_codecType.clear(); - this->d->m_defaultCodecParams.clear(); - - for (auto &format: this->d->m_mediaWriter->supportedFormats()) { - this->d->m_supportedFormats << format; - this->d->m_fileExtensions[format] = - this->d->m_mediaWriter->fileExtensions(format); - this->d->m_formatDescription[format] = - this->d->m_mediaWriter->formatDescription(format); - - for (auto &codec: this->d->m_mediaWriter->supportedCodecs(format)) - if (!this->d->m_supportedCodecs.contains(codec)) { - this->d->m_supportedCodecs << codec; - this->d->m_codecDescription[codec] = - this->d->m_mediaWriter->codecDescription(codec); - this->d->m_codecType[codec] = - this->d->m_mediaWriter->codecType(codec); - this->d->m_defaultCodecParams[codec] = - this->d->m_mediaWriter->defaultCodecParams(codec); + this->m_supportedFormats.clear(); + this->m_fileExtensions.clear(); + this->m_formatDescription.clear(); + this->m_supportedCodecs.clear(); + this->m_codecDescription.clear(); + this->m_codecType.clear(); + this->m_defaultCodecParams.clear(); + + for (auto &format: this->m_mediaWriter->supportedFormats()) { + this->m_supportedFormats << format; + this->m_fileExtensions[format] = + this->m_mediaWriter->fileExtensions(format); + this->m_formatDescription[format] = + this->m_mediaWriter->formatDescription(format); + + for (auto &codec: this->m_mediaWriter->supportedCodecs(format)) + if (!this->m_supportedCodecs.contains(codec)) { + this->m_supportedCodecs << codec; + this->m_codecDescription[codec] = + this->m_mediaWriter->codecDescription(codec); + this->m_codecType[codec] = + this->m_mediaWriter->codecType(codec); + this->m_defaultCodecParams[codec] = + this->m_mediaWriter->defaultCodecParams(codec); } } - QObject::connect(this->d->m_mediaWriter.data(), + QObject::connect(this->m_mediaWriter.data(), &MediaWriter::locationChanged, - this, + self, &MultiSinkElement::locationChanged); - QObject::connect(this->d->m_mediaWriter.data(), + QObject::connect(this->m_mediaWriter.data(), + &MediaWriter::defaultFormatChanged, + self, + &MultiSinkElement::defaultFormatChanged); + QObject::connect(this->m_mediaWriter.data(), &MediaWriter::outputFormatChanged, - this, + self, &MultiSinkElement::outputFormatChanged); - QObject::connect(this->d->m_mediaWriter.data(), + QObject::connect(this->m_mediaWriter.data(), &MediaWriter::formatOptionsChanged, - this, + self, &MultiSinkElement::formatOptionsChanged); - QObject::connect(this->d->m_mediaWriter.data(), + QObject::connect(this->m_mediaWriter.data(), &MediaWriter::codecOptionsChanged, - this, + self, &MultiSinkElement::codecOptionsChanged); - QObject::connect(this->d->m_mediaWriter.data(), + QObject::connect(this->m_mediaWriter.data(), &MediaWriter::streamsChanged, - this, + self, &MultiSinkElement::streamsChanged); - QObject::connect(this->d->m_mediaWriter.data(), + QObject::connect(this->m_mediaWriter.data(), &MediaWriter::formatsBlackListChanged, - this, + self, &MultiSinkElement::formatsBlackListChanged); - QObject::connect(this->d->m_mediaWriter.data(), + QObject::connect(this->m_mediaWriter.data(), &MediaWriter::codecsBlackListChanged, - this, + self, &MultiSinkElement::formatsBlackListChanged); - QObject::connect(this, + QObject::connect(self, &MultiSinkElement::locationChanged, - this->d->m_mediaWriter.data(), + this->m_mediaWriter.data(), &MediaWriter::setLocation); - QObject::connect(this, + QObject::connect(self, &MultiSinkElement::formatOptionsChanged, - this->d->m_mediaWriter.data(), + this->m_mediaWriter.data(), &MediaWriter::setFormatOptions); - this->d->m_mediaWriter->setLocation(location); - emit this->supportedFormatsChanged(this->supportedFormats()); + this->m_mediaWriter->setLocation(location); + emit self->supportedFormatsChanged(self->supportedFormats()); - this->setState(state); + self->setState(state); } #include "moc_multisinkelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -34,6 +34,9 @@ WRITE setLocation RESET resetLocation NOTIFY locationChanged) + Q_PROPERTY(QString defaultFormat + READ defaultFormat + NOTIFY defaultFormatChanged) Q_PROPERTY(QStringList supportedFormats READ supportedFormats NOTIFY supportedFormatsChanged) @@ -45,11 +48,6 @@ Q_PROPERTY(QVariantList streams READ streams NOTIFY streamsChanged) - Q_PROPERTY(QString codecLib - READ codecLib - WRITE setCodecLib - RESET resetCodecLib - NOTIFY codecLibChanged) Q_PROPERTY(bool showFormatOptions READ showFormatOptions WRITE setShowFormatOptions @@ -81,10 +79,10 @@ ~MultiSinkElement(); Q_INVOKABLE QString location() const; + Q_INVOKABLE QString defaultFormat() const; Q_INVOKABLE QStringList supportedFormats() const; Q_INVOKABLE QString outputFormat() const; Q_INVOKABLE QVariantList streams(); - Q_INVOKABLE QString codecLib() const; Q_INVOKABLE bool showFormatOptions() const; Q_INVOKABLE QVariantList userControls() const; Q_INVOKABLE QVariantMap userControlsValues() const; @@ -117,13 +115,13 @@ signals: void locationChanged(const QString &location); + void defaultFormatChanged(const QString &defaultFormat); void supportedFormatsChanged(const QStringList &supportedFormats); void outputFormatChanged(const QString &outputFormat); void formatOptionsChanged(const QVariantMap &formatOptions); void codecOptionsChanged(const QString &key, const QVariantMap &codecOptions); void streamsChanged(const QVariantList &streams); - void codecLibChanged(const QString &codecLib); void showFormatOptionsChanged(bool showFormatOptions); void userControlsChanged(const QVariantList &userControls); void userControlsValuesChanged(const QVariantMap &userControlsValues); @@ -135,7 +133,6 @@ void setOutputFormat(const QString &outputFormat); void setFormatOptions(const QVariantMap &formatOptions); void setCodecOptions(int index, const QVariantMap &codecOptions); - void setCodecLib(const QString &codecLib); void setShowFormatOptions(bool showFormatOptions); void setUserControls(const QVariantList &userControls); void setUserControlsValues(const QVariantMap &userControlsValues); @@ -145,7 +142,6 @@ void resetOutputFormat(); void resetFormatOptions(); void resetCodecOptions(int index); - void resetCodecLib(); void resetShowFormatOptions(); void resetUserControls(); void resetUserControlsValues(); @@ -155,9 +151,6 @@ AkPacket iStream(const AkPacket &packet); bool setState(AkElement::ElementState state); - - private slots: - void codecLibUpdated(const QString &codecLib); }; #endif // MULTISINKELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelementsettings.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelementsettings.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelementsettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelementsettings.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,54 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "multisinkelementsettings.h" +#include "multisinkglobals.h" + +Q_GLOBAL_STATIC(MultiSinkGlobals, globalMultiSink) + +MultiSinkElementSettings::MultiSinkElementSettings(QObject *parent): + QObject(parent) +{ + QObject::connect(globalMultiSink, + &MultiSinkGlobals::codecLibChanged, + this, + &MultiSinkElementSettings::codecLibChanged); +} + +QString MultiSinkElementSettings::codecLib() const +{ + return globalMultiSink->codecLib(); +} + +QStringList MultiSinkElementSettings::subModules() const +{ + return globalMultiSink->subModules(); +} + +void MultiSinkElementSettings::setCodecLib(const QString &codecLib) +{ + globalMultiSink->setCodecLib(codecLib); +} + +void MultiSinkElementSettings::resetCodecLib() +{ + globalMultiSink->resetCodecLib(); +} + +#include "moc_multisinkelementsettings.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelementsettings.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelementsettings.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelementsettings.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkelementsettings.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,52 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef MULTISINKELEMENTSETTINGS_H +#define MULTISINKELEMENTSETTINGS_H + +#include + +class MultiSinkElementSettings: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString codecLib + READ codecLib + WRITE setCodecLib + RESET resetCodecLib + NOTIFY codecLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules + NOTIFY subModulesChanged) + + public: + MultiSinkElementSettings(QObject *parent=nullptr); + + Q_INVOKABLE QString codecLib() const; + Q_INVOKABLE QStringList subModules() const; + + signals: + void codecLibChanged(const QString &codecLib); + void subModulesChanged(const QStringList &subModules); + + public slots: + void setCodecLib(const QString &codecLib); + void resetCodecLib(); +}; + +#endif // MULTISINKELEMENTSETTINGS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkglobals.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkglobals.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkglobals.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkglobals.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,28 +21,43 @@ #include "multisinkglobals.h" +class MultiSinkGlobalsPrivate +{ + public: + QString m_codecLib; + QStringList m_preferredFramework; + + MultiSinkGlobalsPrivate(); +}; + MultiSinkGlobals::MultiSinkGlobals(QObject *parent): QObject(parent) { - this->m_preferredFramework = QStringList { - "ffmpeg", - "gstreamer" - }; - + this->d = new MultiSinkGlobalsPrivate; this->resetCodecLib(); } +MultiSinkGlobals::~MultiSinkGlobals() +{ + delete this->d; +} + QString MultiSinkGlobals::codecLib() const { - return this->m_codecLib; + return this->d->m_codecLib; +} + +QStringList MultiSinkGlobals::subModules() const +{ + return AkElement::listSubModules("MultiSink"); } void MultiSinkGlobals::setCodecLib(const QString &codecLib) { - if (this->m_codecLib == codecLib) + if (this->d->m_codecLib == codecLib) return; - this->m_codecLib = codecLib; + this->d->m_codecLib = codecLib; emit this->codecLibChanged(codecLib); } @@ -50,15 +65,25 @@ { auto subModules = AkElement::listSubModules("MultiSink"); - for (auto &framework: this->m_preferredFramework) + for (auto &framework: this->d->m_preferredFramework) if (subModules.contains(framework)) { this->setCodecLib(framework); return; } - if (this->m_codecLib.isEmpty() && !subModules.isEmpty()) + if (this->d->m_codecLib.isEmpty() && !subModules.isEmpty()) this->setCodecLib(subModules.first()); else this->setCodecLib(""); } + +MultiSinkGlobalsPrivate::MultiSinkGlobalsPrivate() +{ + this->m_preferredFramework = QStringList { + "ffmpeg", + "gstreamer" + }; +} + +#include "moc_multisinkglobals.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkglobals.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkglobals.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/multisinkglobals.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/multisinkglobals.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,8 @@ #include +class MultiSinkGlobalsPrivate; + class MultiSinkGlobals: public QObject { Q_OBJECT @@ -30,15 +32,18 @@ WRITE setCodecLib RESET resetCodecLib NOTIFY codecLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules) public: MultiSinkGlobals(QObject *parent=nullptr); + ~MultiSinkGlobals(); Q_INVOKABLE QString codecLib() const; + Q_INVOKABLE QStringList subModules() const; private: - QString m_codecLib; - QStringList m_preferredFramework; + MultiSinkGlobalsPrivate *d; signals: void codecLibChanged(const QString &codecLib); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/ndkmedia.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/ndkmedia.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/ndkmedia.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/ndkmedia.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,71 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../akcommons.pri) { + include(../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +CONFIG += plugin + +HEADERS = \ + src/plugin.h \ + src/mediawriterndkmedia.h \ + src/abstractstream.h \ + src/videostream.h \ + src/audiostream.h \ + ../mediawriter.h + +INCLUDEPATH += \ + ../../../../Lib/src \ + ../ + +LIBS += -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} +LIBS += \ + -lmediandk + +OTHER_FILES += pspec.json + +QT += qml concurrent + +SOURCES = \ + src/plugin.cpp \ + src/mediawriterndkmedia.cpp \ + src/abstractstream.cpp \ + src/videostream.cpp \ + src/audiostream.cpp \ + ../mediawriter.cpp + +akModule = MultiSink +DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,3 @@ +{ + "pluginType": "Ak.SubModule" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/abstractstream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/abstractstream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/abstractstream.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/abstractstream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,434 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "abstractstream.h" +#include "audiostream.h" +#include "videostream.h" +#include "mediawriterndkmedia.h" + +template +inline void waitLoop(const QFuture &loop) +{ + while (!loop.isFinished()) { + auto eventDispatcher = QThread::currentThread()->eventDispatcher(); + + if (eventDispatcher) + eventDispatcher->processEvents(QEventLoop::AllEvents); + } +} + +class AbstractStreamPrivate +{ + public: + AbstractStream *self; + QString m_mimeType; + AMediaMuxer *m_mediaMuxer {nullptr}; + MediaWriterNDKMedia *m_mediaWriter {nullptr}; + AMediaCodec *m_codec {nullptr}; + AMediaFormat *m_mediaFormat {nullptr}; + QThreadPool m_threadPool; + qint64 m_id {-1}; + qint64 m_pts {0}; + qint64 m_ptsDiff {0}; + qint64 m_ptsDrift {0}; + QQueue m_packetQueue; + QMutex m_convertMutex; + QWaitCondition m_packetQueueNotFull; + QWaitCondition m_packetQueueNotEmpty; + QFuture m_convertLoopResult; + QFuture m_equeueLoopResult; + QFuture m_dequeueLoopResult; + uint m_index {0}; + int m_streamIndex {-1}; + bool m_runConvertLoop {false}; + bool m_runEqueueLoop {false}; + bool m_runDequeueLoop {false}; + bool m_setMediaFormat {false}; + bool m_ready {false}; + + explicit AbstractStreamPrivate(AbstractStream *self); + void convertLoop(); + void equeueLoop(); + void dequeueLoop(); + qint64 nextPts(qint64 pts, qint64 id); +}; + +AbstractStream::AbstractStream(AMediaMuxer *mediaMuxer, + uint index, int streamIndex, + const QVariantMap &configs, + const QMap &codecOptions, + MediaWriterNDKMedia *mediaWriter, + QObject *parent): + QObject(parent) +{ + this->d = new AbstractStreamPrivate(this); + this->m_maxPacketQueueSize = 9; + this->d->m_index = index; + this->d->m_streamIndex = streamIndex; + this->d->m_mediaMuxer = mediaMuxer; + this->d->m_mediaWriter = mediaWriter; + + QString codecName = configs["codec"].toString(); + this->d->m_codec = + AMediaCodec_createEncoderByType(codecName.toStdString().c_str()); + this->d->m_mediaFormat = AMediaFormat_new(); + AMediaFormat_setString(this->d->m_mediaFormat, + AMEDIAFORMAT_KEY_MIME, + codecName.toStdString().c_str()); + + auto bitrate = configs["bitrate"].toInt(); + + if (bitrate < 1) + bitrate = configs["defaultBitRate"].toInt(); + + AMediaFormat_setInt32(this->d->m_mediaFormat, + AMEDIAFORMAT_KEY_BIT_RATE, + bitrate); +/* AMediaFormat_setInt64(this->d->m_mediaFormat, + AMEDIAFORMAT_KEY_DURATION, + 0);*/ + AMediaFormat_setString(this->d->m_mediaFormat, + AMEDIAFORMAT_KEY_LANGUAGE, + "und"); + + // Set codec options. + auto optKey = + QString("%1/%2/%3").arg(this->d->m_mediaWriter->outputFormat()) + .arg(streamIndex) + .arg(codecName); + auto options = codecOptions.value(optKey); + + for (auto it = options.begin(); it != options.end(); it++) + AMediaFormat_setInt32(this->d->m_mediaFormat, + it.key().toStdString().c_str(), + it.value().toInt()); + + if (this->d->m_threadPool.maxThreadCount() < 4) + this->d->m_threadPool.setMaxThreadCount(4); +} + +AbstractStream::~AbstractStream() +{ + this->uninit(); + + if (this->d->m_mediaFormat) + AMediaFormat_delete(this->d->m_mediaFormat); + + if (this->d->m_codec) + AMediaCodec_delete(this->d->m_codec); + + delete this->d; +} + +uint AbstractStream::index() const +{ + return this->d->m_index; +} + +int AbstractStream::streamIndex() const +{ + return this->d->m_streamIndex; +} + +QString AbstractStream::mimeType() const +{ + return this->d->m_mimeType; +} + +AMediaCodec *AbstractStream::codec() const +{ + return this->d->m_codec; +} + +AMediaFormat *AbstractStream::mediaFormat() const +{ + return this->d->m_mediaFormat; +} + +void AbstractStream::packetEnqueue(const AkPacket &packet) +{ + if (!this->d->m_runConvertLoop) + return; + + this->d->m_convertMutex.lock(); + bool enqueue = true; + + if (this->d->m_packetQueue.size() >= this->m_maxPacketQueueSize) + enqueue = this->d->m_packetQueueNotFull.wait(&this->d->m_convertMutex, + THREAD_WAIT_LIMIT); + + if (enqueue) { + this->d->m_packetQueue << packet; + this->d->m_packetQueueNotEmpty.wakeAll(); + } + + this->d->m_convertMutex.unlock(); +} + +bool AbstractStream::ready() const +{ + return this->d->m_ready; +} + +void AbstractStream::convertPacket(const AkPacket &packet) +{ + Q_UNUSED(packet) +} + +AkPacket AbstractStream::avPacketDequeue(size_t bufferSize) +{ + Q_UNUSED(bufferSize) + + return {}; +} + +AbstractStreamPrivate::AbstractStreamPrivate(AbstractStream *self): + self(self) +{ +} + +void AbstractStreamPrivate::convertLoop() +{ + while (this->m_runConvertLoop) { + this->m_convertMutex.lock(); + bool gotPacket = true; + + if (this->m_packetQueue.isEmpty()) + gotPacket = this->m_packetQueueNotEmpty.wait(&this->m_convertMutex, + THREAD_WAIT_LIMIT); + + AkPacket packet; + + if (gotPacket) { + packet = this->m_packetQueue.dequeue(); + this->m_packetQueueNotFull.wakeAll(); + } + + this->m_convertMutex.unlock(); + + if (packet) + self->convertPacket(packet); + } +} + +void AbstractStreamPrivate::equeueLoop() +{ + const ssize_t timeOut = 5000; + bool eosSent = false; + qint64 pts = 0; + qint64 ptsDiff = 0; + + while (this->m_runEqueueLoop) { + auto bufferIndex = + AMediaCodec_dequeueInputBuffer(this->m_codec, timeOut); + + if (bufferIndex < 0) + continue; + + size_t bufferSize = 0; + auto buffer = AMediaCodec_getInputBuffer(this->m_codec, + size_t(bufferIndex), + &bufferSize); + AkPacket packet; + + do { + packet = self->avPacketDequeue(bufferSize); + } while (!packet && this->m_runEqueueLoop); + + if (this->m_runEqueueLoop) { + bufferSize = qMin(size_t(packet.buffer().size()), bufferSize); + memcpy(buffer, packet.buffer().constData(), bufferSize); + auto presentationTimeUs = + qRound64(1e6 * packet.pts() * packet.timeBase().value()); + presentationTimeUs = this->nextPts(presentationTimeUs, packet.id()); + AMediaCodec_queueInputBuffer(this->m_codec, + size_t(bufferIndex), + 0, + bufferSize, + size_t(presentationTimeUs), + 0); + ptsDiff = presentationTimeUs - pts; + pts = presentationTimeUs; + } else { + auto presentationTimeUs = pts + ptsDiff; + AMediaCodec_queueInputBuffer(this->m_codec, + size_t(bufferIndex), + 0, + 0, + size_t(presentationTimeUs), + AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); + eosSent = true; + } + } + + // End Stream + if (!eosSent) { + auto bufferIndex = + AMediaCodec_dequeueInputBuffer(this->m_codec, timeOut); + + if (bufferIndex >= 0) { + AMediaCodec_queueInputBuffer(this->m_codec, + size_t(bufferIndex), + 0, + 0, + 0, + AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); + } + } +} + +void AbstractStreamPrivate::dequeueLoop() +{ + const ssize_t timeOut = 5000; + bool eos = false; + + while (!eos) { + AMediaCodecBufferInfo info; + memset(&info, 0, sizeof(AMediaCodecBufferInfo)); + auto bufferIndex = AMediaCodec_dequeueOutputBuffer(this->m_codec, + &info, + timeOut); + + if (bufferIndex < 0) + continue; + + if (info.flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) + continue; + + if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) + eos = true; + + size_t bufferSize = 0; + auto data = AMediaCodec_getOutputBuffer(this->m_codec, + size_t(bufferIndex), + &bufferSize); + + if (!this->m_ready) { + if (this->m_mediaFormat) + AMediaFormat_delete(this->m_mediaFormat); + + this->m_mediaFormat = AMediaCodec_getOutputFormat(this->m_codec); + this->m_ready = true; + + while (!this->m_mediaWriter->startMuxing() + && this->m_runDequeueLoop) + QThread::msleep(500); + } + + emit self->packetReady(this->m_index, data, &info); + AMediaCodec_releaseOutputBuffer(this->m_codec, + size_t(bufferIndex), + info.size != 0); + } +} + +qint64 AbstractStreamPrivate::nextPts(qint64 pts, qint64 id) +{ + if (this->m_pts < 0 || this->m_id < 0) { + this->m_ptsDrift = -pts; + this->m_pts = pts; + this->m_id = id; + + return 0; + } + + if (pts <= this->m_pts || id != this->m_id) { + this->m_ptsDrift += this->m_pts - pts + this->m_ptsDiff; + this->m_pts = pts; + this->m_id = id; + + return pts + this->m_ptsDrift; + } + + this->m_ptsDiff = pts - this->m_pts; + this->m_pts = pts; + + return pts + this->m_ptsDrift; +} + +bool AbstractStream::init() +{ + if (!this->d->m_codec) + return false; + + this->d->m_setMediaFormat = false; + + if (AMediaCodec_configure(this->d->m_codec, + this->d->m_mediaFormat, + nullptr, + nullptr, + AMEDIACODEC_CONFIGURE_FLAG_ENCODE) != AMEDIA_OK) + return false; + + if (AMediaCodec_start(this->d->m_codec) != AMEDIA_OK) + return false; + + this->d->m_runDequeueLoop = true; + this->d->m_dequeueLoopResult = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &AbstractStreamPrivate::dequeueLoop); + + this->d->m_runEqueueLoop = true; + this->d->m_equeueLoopResult = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &AbstractStreamPrivate::equeueLoop); + + this->d->m_runConvertLoop = true; + this->d->m_convertLoopResult = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &AbstractStreamPrivate::convertLoop); + + return true; +} + +void AbstractStream::uninit() +{ + this->d->m_runConvertLoop = false; + waitLoop(this->d->m_convertLoopResult); + + this->d->m_runEqueueLoop = false; + waitLoop(this->d->m_equeueLoopResult); + + this->d->m_runDequeueLoop = false; + waitLoop(this->d->m_dequeueLoopResult); + + AMediaCodec_stop(this->d->m_codec); + this->d->m_packetQueue.clear(); + + this->d->m_ready = false; +} + +#include "moc_abstractstream.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/abstractstream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/abstractstream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/abstractstream.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/abstractstream.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,80 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef ABSTRACTSTREAM_H +#define ABSTRACTSTREAM_H + +#include + +#define THREAD_WAIT_LIMIT 500 + +class AbstractStream; +class AbstractStreamPrivate; +class MediaWriterNDKMedia; +class AkCaps; +class AkPacket; +struct AMediaMuxer; +struct AMediaFormat; +struct AMediaCodec; +struct AMediaCodecBufferInfo; +using AbstractStreamPtr = QSharedPointer; + +class AbstractStream: public QObject +{ + Q_OBJECT + + public: + AbstractStream(AMediaMuxer *mediaMuxer=nullptr, + uint index=0, int streamIndex=-1, + const QVariantMap &configs={}, + const QMap &codecOptions={}, + MediaWriterNDKMedia *mediaWriter=nullptr, + QObject *parent=nullptr); + virtual ~AbstractStream(); + + Q_INVOKABLE uint index() const; + Q_INVOKABLE int streamIndex() const; + Q_INVOKABLE QString mimeType() const; + Q_INVOKABLE AMediaCodec *codec() const; + Q_INVOKABLE AMediaFormat *mediaFormat() const; + Q_INVOKABLE void packetEnqueue(const AkPacket &packet); + Q_INVOKABLE bool ready() const; + + protected: + int m_maxPacketQueueSize; + + virtual void convertPacket(const AkPacket &packet); + virtual AkPacket avPacketDequeue(size_t bufferSize); + + private: + AbstractStreamPrivate *d; + + signals: + void packetReady(size_t trackIdx, + const uint8_t *data, + const AMediaCodecBufferInfo *info); + + public slots: + virtual bool init(); + virtual void uninit(); + + friend class AbstractStreamPrivate; +}; + +#endif // ABSTRACTSTREAM_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/audiostream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/audiostream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/audiostream.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/audiostream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,224 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audiostream.h" +#include "mediawriterndkmedia.h" + +#define ENCODING_PCM_16BIT 0x2 +#define ENCODING_PCM_8BIT 0x3 +#define ENCODING_PCM_FLOAT 0x4 + +#define CHANNEL_MASK_MONO 0x2 +#define CHANNEL_MASK_FRONT_LEFT 0x4 +#define CHANNEL_MASK_FRONT_RIGHT 0x8 +#define CHANNEL_MASK_FRONT_CENTER 0x10 +#define CHANNEL_MASK_LOW_FREQUENCY 0x20 +#define CHANNEL_MASK_BACK_LEFT 0x40 +#define CHANNEL_MASK_BACK_RIGHT 0x80 +#define CHANNEL_MASK_FRONT_LEFT_OF_CENTER 0x100 +#define CHANNEL_MASK_FRONT_RIGHT_OF_CENTER 0x200 +#define CHANNEL_MASK_BACK_CENTER 0x400 +#define CHANNEL_MASK_SIDE_LEFT 0x800 +#define CHANNEL_MASK_SIDE_RIGHT 0x1000 + +using ChannelMaskToPositionMap = QMap; + +inline const ChannelMaskToPositionMap &channelMaskToPosition() +{ + static const ChannelMaskToPositionMap channelMaskToPosition { + {CHANNEL_MASK_MONO , AkAudioCaps::Position_FrontCenter }, + {CHANNEL_MASK_FRONT_LEFT , AkAudioCaps::Position_FrontLeft }, + {CHANNEL_MASK_FRONT_RIGHT , AkAudioCaps::Position_FrontRight }, + {CHANNEL_MASK_FRONT_CENTER , AkAudioCaps::Position_FrontCenter }, + {CHANNEL_MASK_LOW_FREQUENCY , AkAudioCaps::Position_LowFrequency1 }, + {CHANNEL_MASK_BACK_LEFT , AkAudioCaps::Position_BackLeft }, + {CHANNEL_MASK_BACK_RIGHT , AkAudioCaps::Position_BackRight }, + {CHANNEL_MASK_FRONT_LEFT_OF_CENTER , AkAudioCaps::Position_FrontLeftOfCenter }, + {CHANNEL_MASK_FRONT_RIGHT_OF_CENTER, AkAudioCaps::Position_FrontRightOfCenter}, + {CHANNEL_MASK_BACK_CENTER , AkAudioCaps::Position_BackCenter }, + {CHANNEL_MASK_SIDE_LEFT , AkAudioCaps::Position_SideLeft }, + {CHANNEL_MASK_SIDE_RIGHT , AkAudioCaps::Position_SideRight }, + }; + + return channelMaskToPosition; +} + +class AudioStreamPrivate +{ + public: + AudioStream *self; + AkElementPtr m_convert; + AkAudioPacket m_frame; + QMutex m_frameMutex; + int64_t m_pts {0}; + QWaitCondition m_frameReady; + AkAudioCaps m_caps; + + explicit AudioStreamPrivate(AudioStream *self); +}; + +AudioStream::AudioStream(AMediaMuxer *mediaMuxer, + uint index, + int streamIndex, + const QVariantMap &configs, + const QMap &codecOptions, + MediaWriterNDKMedia *mediaWriter, + QObject *parent): + AbstractStream(mediaMuxer, + index, streamIndex, + configs, + codecOptions, + mediaWriter, + parent) +{ + this->d = new AudioStreamPrivate(this); + this->d->m_caps = configs["caps"].value(); + +#if __ANDROID_API__ >= 28 + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_PCM_ENCODING, + AudioStream::encodingFromSampleFormat(this->d->m_caps.format())); +#endif + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_CHANNEL_MASK, + AudioStream::channelMaskFromLayout(this->d->m_caps.layout())); + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_CHANNEL_COUNT, + this->d->m_caps.channels()); + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_SAMPLE_RATE, + this->d->m_caps.rate()); + + this->d->m_convert = AkElement::create("ACapsConvert"); + this->d->m_convert->setProperty("caps", QVariant::fromValue(this->d->m_caps)); +} + +AudioStream::~AudioStream() +{ + this->uninit(); + delete this->d; +} + +int32_t AudioStream::encodingFromSampleFormat(AkAudioCaps::SampleFormat format) +{ + static const QMap encodingFromSampleFormat { + {AkAudioCaps::SampleFormat_u8 , ENCODING_PCM_8BIT }, + {AkAudioCaps::SampleFormat_s16, ENCODING_PCM_16BIT}, + {AkAudioCaps::SampleFormat_flt, ENCODING_PCM_FLOAT}, + }; + + return encodingFromSampleFormat.value(format); +} + +int32_t AudioStream::channelMaskFromLayout(AkAudioCaps::ChannelLayout layout) +{ + int32_t mask = 0; + + for (auto position: AkAudioCaps::positions(layout)) + mask |= channelMaskToPosition().key(position); + + return mask; +} + +void AudioStream::convertPacket(const AkPacket &packet) +{ + if (!packet) + return; + + auto iPacket = AkAudioPacket(this->d->m_convert->iStream(packet)); + + if (!iPacket) + return; + + this->d->m_frameMutex.lock(); + + if (this->d->m_frame) + this->d->m_frame += iPacket; + else + this->d->m_frame = iPacket; + + this->d->m_frameReady.wakeAll(); + this->d->m_frameMutex.unlock(); +} + +AkPacket AudioStream::avPacketDequeue(size_t bufferSize) +{ + if (bufferSize < 1) + return {}; + + this->d->m_frameMutex.lock(); + int samples = 8 * int(bufferSize) + / (this->d->m_caps.bps() + * this->d->m_caps.channels()); + + if (this->d->m_frame.caps().samples() < samples) { + if (!this->d->m_frameReady.wait(&this->d->m_frameMutex, + THREAD_WAIT_LIMIT)) { + this->d->m_frameMutex.unlock(); + + return {}; + } else if (this->d->m_frame.caps().samples() < samples) { + this->d->m_frameMutex.unlock(); + + return {}; + } + } + + auto frame = this->d->m_frame.pop(samples); + this->d->m_frameMutex.unlock(); + + return frame; +} + +bool AudioStream::init() +{ + this->d->m_convert->setState(AkElement::ElementStatePlaying); + auto result = AbstractStream::init(); + + if (!result) + this->d->m_convert->setState(AkElement::ElementStateNull); + + return result; +} + +void AudioStream::uninit() +{ + AbstractStream::uninit(); + this->d->m_convert->setState(AkElement::ElementStateNull); +} + +AudioStreamPrivate::AudioStreamPrivate(AudioStream *self): + self(self) +{ + +} + +#include "moc_audiostream.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/audiostream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/audiostream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/audiostream.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/audiostream.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,56 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef AUDIOSTREAM_H +#define AUDIOSTREAM_H + +#include + +#include "abstractstream.h" + +class AudioStreamPrivate; + +class AudioStream: public AbstractStream +{ + Q_OBJECT + + public: + AudioStream(AMediaMuxer *mediaMuxer=nullptr, + uint index=0, int streamIndex=-1, + const QVariantMap &configs={}, + const QMap &codecOptions={}, + MediaWriterNDKMedia *mediaWriter=nullptr, + QObject *parent=nullptr); + ~AudioStream(); + Q_INVOKABLE static int32_t encodingFromSampleFormat(AkAudioCaps::SampleFormat format); + Q_INVOKABLE static int32_t channelMaskFromLayout(AkAudioCaps::ChannelLayout layout); + + private: + AudioStreamPrivate *d; + + protected: + void convertPacket(const AkPacket &packet); + AkPacket avPacketDequeue(size_t bufferSize); + + public slots: + bool init(); + void uninit(); +}; + +#endif // AUDIOSTREAM_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/mediawriterndkmedia.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/mediawriterndkmedia.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/mediawriterndkmedia.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/mediawriterndkmedia.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,1425 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mediawriterndkmedia.h" +#include "audiostream.h" +#include "videostream.h" + +#define AVCProfileBaseline 0x01 +#define AVCProfileMain 0x02 +#define AVCProfileExtended 0x04 +#define AVCProfileHigh 0x08 +#define AVCProfileHigh10 0x10 +#define AVCProfileHigh422 0x20 +#define AVCProfileHigh444 0x40 +#define AVCProfileConstrainedBaseline 0x10000 +#define AVCProfileConstrainedHigh 0x80000 + +#define AVCLevel1 0x01 +#define AVCLevel1b 0x02 +#define AVCLevel11 0x04 +#define AVCLevel12 0x08 +#define AVCLevel13 0x10 +#define AVCLevel2 0x20 +#define AVCLevel21 0x40 +#define AVCLevel22 0x80 +#define AVCLevel3 0x100 +#define AVCLevel31 0x200 +#define AVCLevel32 0x400 +#define AVCLevel4 0x800 +#define AVCLevel41 0x1000 +#define AVCLevel42 0x2000 +#define AVCLevel5 0x4000 +#define AVCLevel51 0x8000 +#define AVCLevel52 0x10000 + +#define H263ProfileBaseline 0x01 +#define H263ProfileH320Coding 0x02 +#define H263ProfileBackwardCompatible 0x04 +#define H263ProfileISWV2 0x08 +#define H263ProfileISWV3 0x10 +#define H263ProfileHighCompression 0x20 +#define H263ProfileInternet 0x40 +#define H263ProfileInterlace 0x80 +#define H263ProfileHighLatency 0x100 + +#define H263Level10 0x01 +#define H263Level20 0x02 +#define H263Level30 0x04 +#define H263Level40 0x08 +#define H263Level45 0x10 +#define H263Level50 0x20 +#define H263Level60 0x40 +#define H263Level70 0x80 + +#define MPEG4ProfileSimple 0x01 +#define MPEG4ProfileSimpleScalable 0x02 +#define MPEG4ProfileCore 0x04 +#define MPEG4ProfileMain 0x08 +#define MPEG4ProfileNbit 0x10 +#define MPEG4ProfileScalableTexture 0x20 +#define MPEG4ProfileSimpleFace 0x40 +#define MPEG4ProfileSimpleFBA 0x80 +#define MPEG4ProfileBasicAnimated 0x100 +#define MPEG4ProfileHybrid 0x200 +#define MPEG4ProfileAdvancedRealTime 0x400 +#define MPEG4ProfileCoreScalable 0x800 +#define MPEG4ProfileAdvancedCoding 0x1000 +#define MPEG4ProfileAdvancedCore 0x2000 +#define MPEG4ProfileAdvancedScalable 0x4000 +#define MPEG4ProfileAdvancedSimple 0x8000 + +#define MPEG4Level0 0x01 +#define MPEG4Level0b 0x02 +#define MPEG4Level1 0x04 +#define MPEG4Level2 0x08 +#define MPEG4Level3 0x10 +#define MPEG4Level3b 0x18 +#define MPEG4Level4 0x20 +#define MPEG4Level4a 0x40 +#define MPEG4Level5 0x80 +#define MPEG4Level6 0x100 + +#define MPEG2ProfileSimple 0x00 +#define MPEG2ProfileMain 0x01 +#define MPEG2Profile422 0x02 +#define MPEG2ProfileSNR 0x03 +#define MPEG2ProfileSpatial 0x04 +#define MPEG2ProfileHigh 0x05 + +#define MPEG2LevelLL 0x00 +#define MPEG2LevelML 0x01 +#define MPEG2LevelH14 0x02 +#define MPEG2LevelHL 0x03 +#define MPEG2LevelHP 0x04 + +#define VP8Level_Version0 0x01 +#define VP8Level_Version1 0x02 +#define VP8Level_Version2 0x04 +#define VP8Level_Version3 0x08 + +#define VP8ProfileMain 0x01 + +#define VP9Profile0 0x01 +#define VP9Profile1 0x02 +#define VP9Profile2 0x04 +#define VP9Profile3 0x08 +#define VP9Profile2HDR 0x1000 +#define VP9Profile3HDR 0x2000 + +#define VP9Level1 0x1 +#define VP9Level11 0x2 +#define VP9Level2 0x4 +#define VP9Level21 0x8 +#define VP9Level3 0x10 +#define VP9Level31 0x20 +#define VP9Level4 0x40 +#define VP9Level41 0x80 +#define VP9Level5 0x100 +#define VP9Level51 0x200 +#define VP9Level52 0x400 +#define VP9Level6 0x800 +#define VP9Level61 0x1000 +#define VP9Level62 0x2000 + +#define HEVCProfileMain 0x01 +#define HEVCProfileMain10 0x02 +#define HEVCProfileMainStill 0x04 +#define HEVCProfileMain10HDR10 0x1000 + +#define HEVCMainTierLevel1 0x1 +#define HEVCHighTierLevel1 0x2 +#define HEVCMainTierLevel2 0x4 +#define HEVCHighTierLevel2 0x8 +#define HEVCMainTierLevel21 0x10 +#define HEVCHighTierLevel21 0x20 +#define HEVCMainTierLevel3 0x40 +#define HEVCHighTierLevel3 0x80 +#define HEVCMainTierLevel31 0x100 +#define HEVCHighTierLevel31 0x200 +#define HEVCMainTierLevel4 0x400 +#define HEVCHighTierLevel4 0x800 +#define HEVCMainTierLevel41 0x1000 +#define HEVCHighTierLevel41 0x2000 +#define HEVCMainTierLevel5 0x4000 +#define HEVCHighTierLevel5 0x8000 +#define HEVCMainTierLevel51 0x10000 +#define HEVCHighTierLevel51 0x20000 +#define HEVCMainTierLevel52 0x40000 +#define HEVCHighTierLevel52 0x80000 +#define HEVCMainTierLevel6 0x100000 +#define HEVCHighTierLevel6 0x200000 +#define HEVCMainTierLevel61 0x400000 +#define HEVCHighTierLevel61 0x800000 +#define HEVCMainTierLevel62 0x1000000 +#define HEVCHighTierLevel62 0x2000000 + +#define DolbyVisionProfileDvavPer 0x1 +#define DolbyVisionProfileDvavPen 0x2 +#define DolbyVisionProfileDvheDer 0x4 +#define DolbyVisionProfileDvheDen 0x8 +#define DolbyVisionProfileDvheDtr 0x10 +#define DolbyVisionProfileDvheStn 0x20 +#define DolbyVisionProfileDvheDth 0x40 +#define DolbyVisionProfileDvheDtb 0x80 +#define DolbyVisionProfileDvheSt 0x100 +#define DolbyVisionProfileDvavSe 0x200 + +#define DolbyVisionLevelHd24 0x1 +#define DolbyVisionLevelHd30 0x2 +#define DolbyVisionLevelFhd24 0x4 +#define DolbyVisionLevelFhd30 0x8 +#define DolbyVisionLevelFhd60 0x10 +#define DolbyVisionLevelUhd24 0x20 +#define DolbyVisionLevelUhd30 0x40 +#define DolbyVisionLevelUhd48 0x80 +#define DolbyVisionLevelUhd60 0x100 + +#define BITRATE_MODE_CQ 0 +#define BITRATE_MODE_VBR 1 +#define BITRATE_MODE_CBR 2 + +class CodecOption +{ + public: + QString name; + int min; + int max; + int step; + int defaultValue; +}; + +static const QVector &codecOptionsVector() +{ + static const QVector options { +#if __ANDROID_API__ >= 28 + {AMEDIAFORMAT_KEY_BITRATE_MODE, 0, 2, 1, 2}, + {AMEDIAFORMAT_KEY_PROFILE , 0, 0, 1, 0}, + {AMEDIAFORMAT_KEY_LEVEL , 0, 0, 1, 0}, +#endif + }; + + return options; +} + +class OutputFormatsInfo; +using OutputFormatsInfoVector = QVector; +using SupportedCodecsType = QMap>; + +class OutputFormatsInfo +{ + public: + QString mimeType; + OutputFormat format; + QString description; + QStringList fileExtensions; + + inline static const OutputFormatsInfoVector &info(); + inline static const OutputFormatsInfo *byMimeType(const QString &mimeType); + inline static const OutputFormatsInfo *byFormat(OutputFormat format); +}; + +class CodecsInfo; +using CodecsInfoVector = QVector; + +class CodecsInfo +{ + public: + QString mimeType; + QString description; + + inline static const CodecsInfoVector &info(); + inline static const CodecsInfo *byMimeType(const QString &mimeType); +}; + +using CodecOptionValue = QMap; +using CodecOptions = QMap; + +class MediaWriterNDKMediaPrivate +{ + public: + MediaWriterNDKMedia *self; + QString m_outputFormat; + QFile m_outputFile; + QList m_streamConfigs; + AMediaMuxer *m_mediaMuxer {nullptr}; + QThreadPool m_threadPool; + qint64 m_maxPacketQueueSize {15 * 1024 * 1024}; + QMutex m_packetMutex; + QMutex m_audioMutex; + QMutex m_videoMutex; + QMutex m_subtitleMutex; + QMutex m_writeMutex; + QMutex m_startMuxingMutex; + QMap m_streamsMap; + SupportedCodecsType m_supportedCodecs; + QMap m_codecOptions; + bool m_isRecording {false}; + bool m_muxingStarted {false}; + + explicit MediaWriterNDKMediaPrivate(MediaWriterNDKMedia *self); + QString guessFormat(); + static const QStringList &availableCodecs(); + static const SupportedCodecsType &supportedCodecs(); + static QVariantList parseOptions(const QString &codec); + static const QVariantList menu(const QString &codec, + const QString &option); + static const QVector codecDefaults(const QString &codec); +}; + +MediaWriterNDKMedia::MediaWriterNDKMedia(QObject *parent): + MediaWriter(parent) +{ + this->d = new MediaWriterNDKMediaPrivate(this); + this->d->m_supportedCodecs = MediaWriterNDKMediaPrivate::supportedCodecs(); +} + +MediaWriterNDKMedia::~MediaWriterNDKMedia() +{ + this->uninit(); + delete this->d; +} + +QString MediaWriterNDKMedia::defaultFormat() +{ + if (this->d->m_supportedCodecs.isEmpty()) + return {}; + + if (this->d->m_supportedCodecs.contains("video/webm")) + return QStringLiteral("video/webm"); + + return this->d->m_supportedCodecs.firstKey(); +} + +QString MediaWriterNDKMedia::outputFormat() const +{ + return this->d->m_outputFormat; +} + +QVariantList MediaWriterNDKMedia::streams() const +{ + QVariantList streams; + + for (auto &stream: this->d->m_streamConfigs) + streams << stream; + + return streams; +} + +qint64 MediaWriterNDKMedia::maxPacketQueueSize() const +{ + return this->d->m_maxPacketQueueSize; +} + +QStringList MediaWriterNDKMedia::supportedFormats() +{ + QStringList formats; + + for (auto it = this->d->m_supportedCodecs.constBegin(); + it != this->d->m_supportedCodecs.constEnd(); + it++) + if (!this->m_formatsBlackList.contains(it.key())) + formats << it.key(); + + std::sort(formats.begin(), formats.end()); + + return formats; +} + +QStringList MediaWriterNDKMedia::fileExtensions(const QString &format) +{ + auto info = OutputFormatsInfo::byMimeType(format); + + if (!info) + return {}; + + return info->fileExtensions; +} + +QString MediaWriterNDKMedia::formatDescription(const QString &format) +{ + auto info = OutputFormatsInfo::byMimeType(format); + + if (!info) + return {}; + + return info->description; +} + +QVariantList MediaWriterNDKMedia::formatOptions() +{ + return {}; +} + +QStringList MediaWriterNDKMedia::supportedCodecs(const QString &format) +{ + return this->supportedCodecs(format, ""); +} + +QStringList MediaWriterNDKMedia::supportedCodecs(const QString &format, + const QString &type) +{ + QStringList supportedCodecs; + + if (type.isEmpty()) { + for (auto &codecs: this->d->m_supportedCodecs.value(format)) { + for (auto &codec: codecs) + if (!this->m_codecsBlackList.contains(codec)) + supportedCodecs << codec; + } + } else { + auto codecs = this->d->m_supportedCodecs.value(format).value(type); + + for (auto &codec: codecs) + if (!this->m_codecsBlackList.contains(codec)) + supportedCodecs << codec; + } + + std::sort(supportedCodecs.begin(), supportedCodecs.end()); + + return supportedCodecs; +} + +QString MediaWriterNDKMedia::defaultCodec(const QString &format, + const QString &type) +{ + auto codecs = this->d->m_supportedCodecs.value(format).value(type); + + for (auto &codec: codecs) + if (!this->m_codecsBlackList.contains(codec)) + return codec; + + return {}; +} + +QString MediaWriterNDKMedia::codecDescription(const QString &codec) +{ + auto info = CodecsInfo::byMimeType(codec); + + if (!info) + return {}; + + return info->description; +} + +QString MediaWriterNDKMedia::codecType(const QString &codec) +{ + auto info = CodecsInfo::byMimeType(codec); + + if (!info) + return {}; + + return info->mimeType.startsWith("audio/")? + QStringLiteral("audio/x-raw"): + QStringLiteral("video/x-raw"); +} + +QVariantMap MediaWriterNDKMedia::defaultCodecParams(const QString &codec) +{ + auto info = CodecsInfo::byMimeType(codec); + + if (!info) + return {}; + + QVariantMap codecParams; + + if (info->mimeType.startsWith("audio/")) { + static const QStringList supportedSampleFormats {"s16"}; + + codecParams["supportedSampleFormats"] = supportedSampleFormats; + codecParams["supportedSampleRates"] = QVariantList(); + codecParams["supportedChannelLayouts"] = QVariantList(); + codecParams["defaultSampleFormat"] = supportedSampleFormats.first(); + codecParams["defaultBitRate"] = 128000; + codecParams["defaultSampleRate"] = 44100; + codecParams["defaultChannelLayout"] = "stereo"; + codecParams["defaultChannels"] = 2; + } else { + static const QStringList supportedPixelFormats {"yuv420p", "nv12"}; + + codecParams["supportedPixelFormats"] = supportedPixelFormats; + codecParams["supportedFrameRates"] = QVariantList(); + codecParams["defaultGOP"] = 12; + codecParams["defaultBitRate"] = 1500000; + codecParams["defaultPixelFormat"] = supportedPixelFormats.first(); + } + + return codecParams; +} + +QVariantMap MediaWriterNDKMedia::addStream(int streamIndex, + const AkCaps &streamCaps) +{ + return this->addStream(streamIndex, streamCaps, {}); +} + +QVariantMap MediaWriterNDKMedia::addStream(int streamIndex, + const AkCaps &streamCaps, + const QVariantMap &codecParams) +{ + auto outputFormat = this->d->guessFormat(); + + if (outputFormat.isEmpty()) + return {}; + + QVariantMap outputParams; + + if (codecParams.contains("label")) + outputParams["label"] = codecParams["label"]; + + outputParams["index"] = streamIndex; + auto codec = codecParams.value("codec").toString(); + + if (codec.isEmpty()) + return {}; + + auto supportedCodecs = this->supportedCodecs(outputFormat, streamCaps.mimeType()); + + if (codec.isEmpty() || !supportedCodecs.contains(codec)) + codec = this->defaultCodec(outputFormat, streamCaps.mimeType()); + + outputParams["codec"] = codec; + outputParams["caps"] = QVariant::fromValue(streamCaps); + + auto defaultCodecParams = this->defaultCodecParams(codec); + + if (streamCaps.mimeType() == "audio/x-raw" + || streamCaps.mimeType() == "video/x-raw") { + int bitrate = codecParams.value("bitrate").toInt(); + + if (bitrate < 1) + bitrate = defaultCodecParams["defaultBitRate"].toInt(); + + outputParams["bitrate"] = bitrate; + } + + if (streamCaps.mimeType() == "video/x-raw") { + int gop = codecParams.value("gop").toInt(); + + if (gop < 1) + gop = defaultCodecParams["defaultGOP"].toInt(); + + outputParams["gop"] = gop; + } + + this->d->m_streamConfigs << outputParams; + emit this->streamsChanged(this->streams()); + + return outputParams; +} + +QVariantMap MediaWriterNDKMedia::updateStream(int index) +{ + return this->updateStream(index, {}); +} + +QVariantMap MediaWriterNDKMedia::updateStream(int index, + const QVariantMap &codecParams) +{ + auto outputFormat = this->d->guessFormat(); + + if (outputFormat.isEmpty()) + return {}; + + bool streamChanged = false; + + if (codecParams.contains("label") + && this->d->m_streamConfigs[index]["label"] != codecParams.value("label")) { + this->d->m_streamConfigs[index]["label"] = codecParams.value("label"); + streamChanged = true; + } + + auto streamCaps = this->d->m_streamConfigs[index]["caps"].value(); + + if (codecParams.contains("caps") + && this->d->m_streamConfigs[index]["caps"] != codecParams.value("caps")) { + this->d->m_streamConfigs[index]["caps"] = codecParams.value("caps"); + streamChanged = true; + } + + QString codec; + + if (codecParams.contains("codec")) { + if (this->supportedCodecs(outputFormat, streamCaps.mimeType()) + .contains(codecParams["codec"].toString())) { + codec = codecParams["codec"].toString(); + } else + codec = this->defaultCodec(outputFormat, streamCaps.mimeType()); + + this->d->m_streamConfigs[index]["codec"] = codec; + streamChanged = true; + } else + codec = this->d->m_streamConfigs[index]["codec"].toString(); + + auto codecDefaults = this->defaultCodecParams(codec); + + if ((streamCaps.mimeType() == "audio/x-raw" + || streamCaps.mimeType() == "video/x-raw") + && codecParams.contains("bitrate")) { + int bitRate = codecParams["bitrate"].toInt(); + this->d->m_streamConfigs[index]["bitrate"] = + bitRate > 0? bitRate: codecDefaults["defaultBitRate"].toInt(); + streamChanged = true; + } + + if (streamCaps.mimeType() == "video/x-raw" + && codecParams.contains("gop")) { + int gop = codecParams["gop"].toInt(); + this->d->m_streamConfigs[index]["gop"] = + gop > 0? gop: codecDefaults["defaultGOP"].toInt(); + streamChanged = true; + } + + if (streamChanged) + emit this->streamsChanged(this->streams()); + + return this->d->m_streamConfigs[index]; +} + +QVariantList MediaWriterNDKMedia::codecOptions(int index) +{ + auto outputFormat = this->d->guessFormat(); + + if (outputFormat.isEmpty()) + return {}; + + auto codec = + this->d->m_streamConfigs.value(index).value("codec").toString(); + + if (codec.isEmpty()) + return {}; + + auto optKey = QString("%1/%2/%3").arg(outputFormat).arg(index).arg(codec); + auto options = this->d->parseOptions(codec); + auto globalCodecOptions = this->d->m_codecOptions.value(optKey); + QVariantList codecOptions; + + for (auto &option: options) { + auto optionList = option.toList(); + auto key = optionList[0].toString(); + + if (globalCodecOptions.contains(key)) + optionList[7] = globalCodecOptions[key]; + + codecOptions << QVariant(optionList); + } + + return codecOptions; +} + +MediaWriterNDKMediaPrivate::MediaWriterNDKMediaPrivate(MediaWriterNDKMedia *self): + self(self) +{ +} + +QString MediaWriterNDKMediaPrivate::guessFormat() +{ + if (self->supportedFormats().contains(this->m_outputFormat)) + return this->m_outputFormat; + else { + auto extension = QFileInfo(self->location()).completeSuffix(); + + for (auto &info: OutputFormatsInfo::info()) + if (info.fileExtensions.contains(extension)) + return info.mimeType; + } + + return {}; +} + +const QStringList &MediaWriterNDKMediaPrivate::availableCodecs() +{ + auto &codecsInfo = CodecsInfo::info(); + static QStringList availableCodecs; + + if (!availableCodecs.isEmpty()) + return availableCodecs; + + for (auto it = codecsInfo.constBegin(); it != codecsInfo.constEnd(); it++) + if (auto codec = AMediaCodec_createEncoderByType(it->mimeType.toStdString().c_str())) { + availableCodecs << it->mimeType; + AMediaCodec_delete(codec); + } + + return availableCodecs; +} + +const SupportedCodecsType &MediaWriterNDKMediaPrivate::supportedCodecs() +{ + static SupportedCodecsType supportedCodecs; + + if (!supportedCodecs.isEmpty()) + return supportedCodecs; + + auto &codecs = MediaWriterNDKMediaPrivate::availableCodecs(); + + auto audioMediaFormat = AMediaFormat_new(); + AMediaFormat_setInt32(audioMediaFormat, + AMEDIAFORMAT_KEY_BIT_RATE, + 128000); +#if __ANDROID_API__ >= 28 + AMediaFormat_setInt32(audioMediaFormat, + AMEDIAFORMAT_KEY_PCM_ENCODING, + 0x2); // s16 +#endif + AMediaFormat_setInt32(audioMediaFormat, + AMEDIAFORMAT_KEY_CHANNEL_MASK, + 0x4 | 0x8); // stereo + AMediaFormat_setInt32(audioMediaFormat, + AMEDIAFORMAT_KEY_CHANNEL_COUNT, + 2); + AMediaFormat_setInt32(audioMediaFormat, + AMEDIAFORMAT_KEY_SAMPLE_RATE, + 44100); + + auto videoMediaFormat = AMediaFormat_new(); + AMediaFormat_setInt32(videoMediaFormat, + AMEDIAFORMAT_KEY_BIT_RATE, + 1500000); + AMediaFormat_setInt32(videoMediaFormat, + AMEDIAFORMAT_KEY_COLOR_FORMAT, + 19); // yuv420p + AMediaFormat_setInt32(videoMediaFormat, + AMEDIAFORMAT_KEY_WIDTH, + 640); + AMediaFormat_setInt32(videoMediaFormat, + AMEDIAFORMAT_KEY_HEIGHT, + 480); + AMediaFormat_setInt32(videoMediaFormat, + AMEDIAFORMAT_KEY_FRAME_RATE, + 30); + AMediaFormat_setInt32(videoMediaFormat, + AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, + 1); + + auto &formatsInfo = OutputFormatsInfo::info(); + + for (auto &format: formatsInfo) { + for (auto codec: codecs) { + QTemporaryFile tempFile; + tempFile.setAutoRemove(true); + + if (tempFile.open()) { + if (auto muxer = AMediaMuxer_new(tempFile.handle(), format.format)) { + AMediaFormat *mediaFormat = nullptr; + QString mimeType; + + if (codec.startsWith("audio/")) { + mediaFormat = audioMediaFormat; + mimeType = "audio/x-raw"; + } else { + mediaFormat = videoMediaFormat; + mimeType = "video/x-raw"; + } + + AMediaFormat_setString(mediaFormat, + AMEDIAFORMAT_KEY_MIME, + codec.toStdString().c_str()); + + if (AMediaMuxer_addTrack(muxer, mediaFormat) >= 0) + supportedCodecs[format.mimeType][mimeType] << codec; + + AMediaMuxer_start(muxer); + AMediaMuxer_delete(muxer); + } + } + } + } + + AMediaFormat_delete(audioMediaFormat); + AMediaFormat_delete(videoMediaFormat); + + return supportedCodecs; +} + +QVariantList MediaWriterNDKMediaPrivate::parseOptions(const QString &codec) +{ + QVariantList options; + + auto profileLevel = MediaWriterNDKMediaPrivate::codecDefaults(codec); + + for (auto &option: codecOptionsVector()) { + auto menu = MediaWriterNDKMediaPrivate::menu(codec, option.name); + + if (menu.size() > 1) { + auto defaultValue = option.defaultValue; + + if (!profileLevel.isEmpty()) { + if (option.name == "profile") + defaultValue = profileLevel[0]; + + if (option.name == "level") + defaultValue = profileLevel[1]; + } + + options << QVariant(QVariantList { + option.name, + option.name, + "menu", + option.min, + menu.size(), + option.step, + defaultValue, + defaultValue, + menu + }); + } + } + + return options; +} + +const QVariantList MediaWriterNDKMediaPrivate::menu(const QString &codec, + const QString &option) +{ + class MenuOption + { + public: + QString name; + int value; + }; + + using MenuOptions = QVector; + + static const MenuOptions AVCProfile { + {"Baseline" , AVCProfileBaseline }, + {"Main" , AVCProfileMain }, + {"Extended" , AVCProfileExtended }, + {"High" , AVCProfileHigh }, + {"High 10" , AVCProfileHigh10 }, + {"High 422" , AVCProfileHigh422 }, + {"High 444" , AVCProfileHigh444 }, + {"Constrained Baseline", AVCProfileConstrainedBaseline}, + {"Constrained High" , AVCProfileConstrainedHigh }, + }; + + static const MenuOptions AVCLevel { + {"1" , AVCLevel1 }, + {"1b", AVCLevel1b}, + {"11", AVCLevel11}, + {"12", AVCLevel12}, + {"13", AVCLevel13}, + {"2" , AVCLevel2 }, + {"21", AVCLevel21}, + {"22", AVCLevel22}, + {"3" , AVCLevel3 }, + {"31", AVCLevel31}, + {"32", AVCLevel32}, + {"4" , AVCLevel4 }, + {"41", AVCLevel41}, + {"42", AVCLevel42}, + {"5" , AVCLevel5 }, + {"51", AVCLevel51}, + {"52", AVCLevel52}, + }; + + static const MenuOptions H263Profile { + {"Baseline" , H263ProfileBaseline }, + {"H320 Coding" , H263ProfileH320Coding }, + {"Backward Compatible", H263ProfileBackwardCompatible}, + {"ISWV2" , H263ProfileISWV2 }, + {"ISWV3" , H263ProfileISWV3 }, + {"High Compression" , H263ProfileHighCompression }, + {"Internet" , H263ProfileInternet }, + {"Interlace" , H263ProfileInterlace }, + {"High Latency" , H263ProfileHighLatency }, + }; + + static const MenuOptions H263Level { + {"10", H263Level10}, + {"20", H263Level20}, + {"30", H263Level30}, + {"40", H263Level40}, + {"45", H263Level45}, + {"50", H263Level50}, + {"60", H263Level60}, + {"70", H263Level70}, + }; + + static const MenuOptions MPEG4Profile { + {"Simple" , MPEG4ProfileSimple }, + {"Simple Scalable" , MPEG4ProfileSimpleScalable }, + {"Core" , MPEG4ProfileCore }, + {"Main" , MPEG4ProfileMain }, + {"Nbit" , MPEG4ProfileNbit }, + {"Scalable Texture" , MPEG4ProfileScalableTexture }, + {"Simple Face" , MPEG4ProfileSimpleFace }, + {"Simple FBA" , MPEG4ProfileSimpleFBA }, + {"Basic Animated" , MPEG4ProfileBasicAnimated }, + {"Hybrid" , MPEG4ProfileHybrid }, + {"Advanced Real Time", MPEG4ProfileAdvancedRealTime}, + {"Core Scalable" , MPEG4ProfileCoreScalable }, + {"Advanced Coding" , MPEG4ProfileAdvancedCoding }, + {"Advanced Core" , MPEG4ProfileAdvancedCore }, + {"Advanced Scalable" , MPEG4ProfileAdvancedScalable}, + {"Advanced Simple" , MPEG4ProfileAdvancedSimple }, + }; + + static const MenuOptions MPEG4Level { + {"0" , MPEG4Level0 }, + {"0b", MPEG4Level0b}, + {"1" , MPEG4Level1 }, + {"2" , MPEG4Level2 }, + {"3" , MPEG4Level3 }, + {"3b", MPEG4Level3b}, + {"4" , MPEG4Level4 }, + {"4a", MPEG4Level4a}, + {"5" , MPEG4Level5 }, + {"6" , MPEG4Level6 }, + }; + + static const MenuOptions MPEG2Profile { + {"Simple" , MPEG2ProfileSimple }, + {"Main" , MPEG2ProfileMain }, + {"422" , MPEG2Profile422 }, + {"SNR" , MPEG2ProfileSNR }, + {"Spatial", MPEG2ProfileSpatial}, + {"High" , MPEG2ProfileHigh }, + }; + + static const MenuOptions MPEG2Level { + {"LL" , MPEG2LevelLL }, + {"ML" , MPEG2LevelML }, + {"H14", MPEG2LevelH14}, + {"HL" , MPEG2LevelHL }, + {"HP" , MPEG2LevelHP }, + }; + + static const MenuOptions VP8Level { + {"Version 0", VP8Level_Version0}, + {"Version 1", VP8Level_Version1}, + {"Version 2", VP8Level_Version2}, + {"Version 3", VP8Level_Version3}, + }; + + static const MenuOptions VP8Profile { + {"Main", VP8ProfileMain}, + }; + + static const MenuOptions VP9Profile { + {"0" , VP9Profile0 }, + {"1" , VP9Profile1 }, + {"2" , VP9Profile2 }, + {"3" , VP9Profile3 }, + {"2 HDR", VP9Profile2HDR}, + {"3 HDR", VP9Profile3HDR}, + }; + + static const MenuOptions VP9Level { + {"1" , VP9Level1 }, + {"11", VP9Level11}, + {"2" , VP9Level2 }, + {"21", VP9Level21}, + {"3" , VP9Level3 }, + {"31", VP9Level31}, + {"4" , VP9Level4 }, + {"41", VP9Level41}, + {"5" , VP9Level5 }, + {"51", VP9Level51}, + {"52", VP9Level52}, + {"6" , VP9Level6 }, + {"61", VP9Level61}, + {"62", VP9Level62}, + }; + + static const MenuOptions HEVCProfile { + {"Main" , HEVCProfileMain }, + {"Main 10" , HEVCProfileMain10 }, + {"Main Still" , HEVCProfileMainStill }, + {"Main 10 HDR 10", HEVCProfileMain10HDR10}, + }; + + static const MenuOptions HEVCLevel { + {"Main Tier 1" , HEVCMainTierLevel1 }, + {"High Tier 1" , HEVCHighTierLevel1 }, + {"Main Tier 2" , HEVCMainTierLevel2 }, + {"High Tier 2" , HEVCHighTierLevel2 }, + {"Main Tier 21", HEVCMainTierLevel21}, + {"High Tier 21", HEVCHighTierLevel21}, + {"Main Tier 3" , HEVCMainTierLevel3 }, + {"High Tier 3" , HEVCHighTierLevel3 }, + {"Main Tier 31", HEVCMainTierLevel31}, + {"High Tier 31", HEVCHighTierLevel31}, + {"Main Tier 4" , HEVCMainTierLevel4 }, + {"High Tier 4" , HEVCHighTierLevel4 }, + {"Main Tier 41", HEVCMainTierLevel41}, + {"High Tier 41", HEVCHighTierLevel41}, + {"Main Tier 5" , HEVCMainTierLevel5 }, + {"High Tier 5" , HEVCHighTierLevel5 }, + {"Main Tier 51", HEVCMainTierLevel51}, + {"High Tier 51", HEVCHighTierLevel51}, + {"Main Tier 52", HEVCMainTierLevel52}, + {"High Tier 52", HEVCHighTierLevel52}, + {"Main Tier 6" , HEVCMainTierLevel6 }, + {"High Tier 6" , HEVCHighTierLevel6 }, + {"Main Tier 61", HEVCMainTierLevel61}, + {"High Tier 61", HEVCHighTierLevel61}, + {"Main Tier 62", HEVCMainTierLevel62}, + {"High Tier 62", HEVCHighTierLevel62}, + }; + + static const MenuOptions DolbyVisionProfile { + {"DvavPer", DolbyVisionProfileDvavPer}, + {"DvavPen", DolbyVisionProfileDvavPen}, + {"DvheDer", DolbyVisionProfileDvheDer}, + {"DvheDen", DolbyVisionProfileDvheDen}, + {"DvheDtr", DolbyVisionProfileDvheDtr}, + {"DvheStn", DolbyVisionProfileDvheStn}, + {"DvheDth", DolbyVisionProfileDvheDth}, + {"DvheDtb", DolbyVisionProfileDvheDtb}, + {"DvheSt" , DolbyVisionProfileDvheSt }, + {"DvavSe" , DolbyVisionProfileDvavSe }, + }; + + static const MenuOptions DolbyVisionLevel { + {"Hd 24" , DolbyVisionLevelHd24 }, + {"Hd 30" , DolbyVisionLevelHd30 }, + {"Fhd 24", DolbyVisionLevelFhd24}, + {"Fhd 30", DolbyVisionLevelFhd30}, + {"Fhd 60", DolbyVisionLevelFhd60}, + {"Uhd 24", DolbyVisionLevelUhd24}, + {"Uhd 30", DolbyVisionLevelUhd30}, + {"Uhd 48", DolbyVisionLevelUhd48}, + {"Uhd 60", DolbyVisionLevelUhd60}, + }; + + static const MenuOptions BitrateMode { + {"Constant Quality" , BITRATE_MODE_CQ }, + {"Variable Bit Rate", BITRATE_MODE_VBR}, + {"Constant Bit Rate", BITRATE_MODE_CBR}, + }; + + using MenuOptionsMap = QMap; + + static const MenuOptionsMap ProfileOptions { + {"video/avc" , &AVCProfile }, + {"video/3gpp" , &H263Profile }, + {"video/mp4v-es" , &MPEG4Profile }, + {"video/mpeg2" , &MPEG2Profile }, + {"video/x-vnd.on2.vp8", &VP8Profile }, + {"video/x-vnd.on2.vp9", &VP9Profile }, + {"video/hevc" , &HEVCProfile }, + {"video/dolby-vision" , &DolbyVisionProfile}, + }; + + static const MenuOptionsMap LevelOptions { + {"video/avc" , &AVCLevel }, + {"video/3gpp" , &H263Level }, + {"video/mp4v-es" , &MPEG4Level }, + {"video/mpeg2" , &MPEG2Level }, + {"video/x-vnd.on2.vp8", &VP8Level }, + {"video/x-vnd.on2.vp9", &VP9Level }, + {"video/hevc" , &HEVCLevel }, + {"video/dolby-vision" , &DolbyVisionLevel}, + }; + + const MenuOptions *menuOptions {nullptr}; + +#if __ANDROID_API__ >= 28 + if (option == AMEDIAFORMAT_KEY_BITRATE_MODE) + menuOptions = &BitrateMode; + else if (option == AMEDIAFORMAT_KEY_PROFILE + && ProfileOptions.contains(codec)) + menuOptions = ProfileOptions[codec]; + else if (option == AMEDIAFORMAT_KEY_LEVEL + && LevelOptions.contains(codec)) + menuOptions = LevelOptions[codec]; +#endif + + if (!menuOptions) + return {}; + + QVariantList optionsList; + + for (auto &option: *menuOptions) + optionsList << QVariant(QVariantList { + option.name, + QString(), + option.value + }); + + return optionsList; +} + +const QVector MediaWriterNDKMediaPrivate::codecDefaults(const QString &codec) +{ + class CodecProfileLevel + { + public: + QString codec; + int profile; + int level; + }; + + static const QVector profileLevel { + {"video/avc" , AVCProfileBaseline , AVCLevel41 }, + {"video/3gpp" , H263ProfileBaseline , H263Level45 }, + {"video/mp4v-es" , MPEG4ProfileSimple , MPEG4Level3 }, + {"video/mpeg2" , MPEG2ProfileSimple , MPEG2LevelHL }, + {"video/x-vnd.on2.vp8", VP8ProfileMain , VP8Level_Version0 }, + {"video/x-vnd.on2.vp9", VP9Profile0 , VP9Level41 }, + {"video/hevc" , HEVCProfileMain , HEVCMainTierLevel51 }, + {"video/dolby-vision" , DolbyVisionProfileDvavPer, DolbyVisionLevelHd24}, + }; + + for (auto &pl: profileLevel) + if (pl.codec == codec) + return {pl.profile, pl.level}; + + return {}; +} + +void MediaWriterNDKMedia::setOutputFormat(const QString &outputFormat) +{ + if (this->d->m_outputFormat == outputFormat) + return; + + this->d->m_outputFormat = outputFormat; + emit this->outputFormatChanged(outputFormat); +} + +void MediaWriterNDKMedia::setFormatOptions(const QVariantMap &formatOptions) +{ + Q_UNUSED(formatOptions) +} + +void MediaWriterNDKMedia::setCodecOptions(int index, + const QVariantMap &codecOptions) +{ + auto outputFormat = this->d->guessFormat(); + + if (outputFormat.isEmpty()) + return; + + auto codec = this->d->m_streamConfigs.value(index).value("codec").toString(); + + if (codec.isEmpty()) + return; + + auto optKey = QString("%1/%2/%3").arg(outputFormat).arg(index).arg(codec); + bool modified = false; + + for (auto it = codecOptions.begin(); + it != codecOptions.end(); + it++) + if (it.value() != this->d->m_codecOptions.value(optKey).value(it.key())) { + this->d->m_codecOptions[optKey][it.key()] = it.value(); + modified = true; + } + + if (modified) + emit this->codecOptionsChanged(optKey, this->d->m_codecOptions.value(optKey)); +} + +void MediaWriterNDKMedia::setMaxPacketQueueSize(qint64 maxPacketQueueSize) +{ + if (this->d->m_maxPacketQueueSize == maxPacketQueueSize) + return; + + this->d->m_maxPacketQueueSize = maxPacketQueueSize; + emit this->maxPacketQueueSizeChanged(maxPacketQueueSize); +} + +void MediaWriterNDKMedia::resetOutputFormat() +{ + this->setOutputFormat(""); +} + +void MediaWriterNDKMedia::resetFormatOptions() +{ +} + +void MediaWriterNDKMedia::resetCodecOptions(int index) +{ + auto outputFormat = this->d->guessFormat(); + + if (outputFormat.isEmpty()) + return; + + auto codec = this->d->m_streamConfigs.value(index).value("codec").toString(); + + if (codec.isEmpty()) + return; + + auto optKey = QString("%1/%2/%3").arg(outputFormat).arg(index).arg(codec); + + if (this->d->m_codecOptions.value(optKey).isEmpty()) + return; + + this->d->m_codecOptions.remove(optKey); + emit this->codecOptionsChanged(optKey, QVariantMap()); +} + +void MediaWriterNDKMedia::resetMaxPacketQueueSize() +{ + this->setMaxPacketQueueSize(15 * 1024 * 1024); +} + +void MediaWriterNDKMedia::enqueuePacket(const AkPacket &packet) +{ + if (this->d->m_isRecording && this->d->m_streamsMap.contains(packet.index())) + this->d->m_streamsMap[packet.index()]->packetEnqueue(packet); +} + +void MediaWriterNDKMedia::clearStreams() +{ + this->d->m_streamConfigs.clear(); + emit this->streamsChanged(this->streams()); +} + +bool MediaWriterNDKMedia::init() +{ + auto outputFormat = this->d->guessFormat(); + + if (outputFormat.isEmpty()) + return false; + + auto formatInfo = OutputFormatsInfo::byMimeType(outputFormat); + + if (!formatInfo) + return false; + + this->d->m_outputFile.setFileName(this->m_location); + + if (!this->d->m_outputFile.open(QIODevice::ReadWrite + | QIODevice::Truncate)) + return false; + + this->d->m_mediaMuxer = + AMediaMuxer_new(this->d->m_outputFile.handle(), + formatInfo->format); + + if (!this->d->m_mediaMuxer) { + this->d->m_outputFile.close(); + + return false; + } + + AMediaMuxer_setOrientationHint(this->d->m_mediaMuxer, 0); + auto streamConfigs = this->d->m_streamConfigs.toVector(); + + for (int i = 0; i < streamConfigs.count(); i++) { + auto configs = streamConfigs[i]; + + // Confihure streams parameters. + AkCaps streamCaps = configs["caps"].value(); + AbstractStreamPtr mediaStream; + int inputId = configs["index"].toInt(); + + if (streamCaps.mimeType() == "audio/x-raw") { + mediaStream = + AbstractStreamPtr(new AudioStream(this->d->m_mediaMuxer, + uint(i), inputId, + configs, + this->d->m_codecOptions, + this)); + } else if (streamCaps.mimeType() == "video/x-raw") { + mediaStream = + AbstractStreamPtr(new VideoStream(this->d->m_mediaMuxer, + uint(i), inputId, + configs, + this->d->m_codecOptions, + this)); + } else { + } + + if (mediaStream) { + this->d->m_streamsMap[inputId] = mediaStream; + + QObject::connect(mediaStream.data(), + SIGNAL(packetReady(size_t, + const uint8_t *, + const AMediaCodecBufferInfo *)), + this, + SLOT(writePacket(size_t, + const uint8_t *, + const AMediaCodecBufferInfo *)), + Qt::DirectConnection); + } + } + + for (auto &mediaStream: this->d->m_streamsMap) + if (!mediaStream->init()) { + this->d->m_streamsMap.clear(); + AMediaMuxer_stop(this->d->m_mediaMuxer); + AMediaMuxer_delete(this->d->m_mediaMuxer); + this->d->m_mediaMuxer = nullptr; + this->d->m_outputFile.close(); + + return false; + } + + this->d->m_isRecording = true; + + return true; +} + +void MediaWriterNDKMedia::uninit() +{ + if (!this->d->m_mediaMuxer) + return; + + this->d->m_isRecording = false; + this->d->m_streamsMap.clear(); + AMediaMuxer_stop(this->d->m_mediaMuxer); + AMediaMuxer_delete(this->d->m_mediaMuxer); + this->d->m_mediaMuxer = nullptr; + this->d->m_outputFile.close(); + this->d->m_muxingStarted = false; +} + +bool MediaWriterNDKMedia::startMuxing() +{ + this->d->m_startMuxingMutex.lock(); + + if (!this->d->m_muxingStarted) { + for (auto &stream: this->d->m_streamsMap) + if (!stream->ready()) { + this->d->m_startMuxingMutex.unlock(); + + return false; + } + + for (auto &stream: this->d->m_streamsMap) + AMediaMuxer_addTrack(this->d->m_mediaMuxer, stream->mediaFormat()); + + if (AMediaMuxer_start(this->d->m_mediaMuxer) != AMEDIA_OK) { + this->d->m_startMuxingMutex.unlock(); + + return false; + } + + this->d->m_muxingStarted = true; + } + + this->d->m_startMuxingMutex.unlock(); + + return true; +} + +void MediaWriterNDKMedia::writePacket(size_t trackIdx, + const uint8_t *data, + const AMediaCodecBufferInfo *info) +{ + this->d->m_writeMutex.lock(); + + if (this->d->m_muxingStarted) + AMediaMuxer_writeSampleData(this->d->m_mediaMuxer, + trackIdx, + data, + info); + + this->d->m_writeMutex.unlock(); +} + +const OutputFormatsInfoVector &OutputFormatsInfo::info() +{ + static const OutputFormatsInfoVector formatsInfo { + {"video/webm", AMEDIAMUXER_OUTPUT_FORMAT_WEBM , "WEBM", {"webm"}}, + {"video/mp4" , AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4, "MP4", {"mp4"}}, + }; + + return formatsInfo; +} + +const OutputFormatsInfo *OutputFormatsInfo::byMimeType(const QString &mimeType) +{ + for (auto &info: info()) + if (info.mimeType == mimeType) + return &info; + + return nullptr; +} + +const OutputFormatsInfo *OutputFormatsInfo::byFormat(OutputFormat format) +{ + for (auto &info: info()) + if (info.format == format) + return &info; + + return nullptr; +} + +const CodecsInfoVector &CodecsInfo::info() +{ + static const CodecsInfoVector codecsInfo { + // Video + {"video/x-vnd.on2.vp8", "VP8" }, + {"video/x-vnd.on2.vp9", "VP9" }, + {"video/avc" , "H.264 AVC" }, + {"video/hevc" , "H.265 HEVC" }, + {"video/mp4v-es" , "MPEG4" }, + {"video/3gpp" , "H.263" }, + {"video/mpeg2" , "MPEG-2" }, + {"video/raw" , "RAW" }, + {"video/dolby-vision" , "Dolby Vision"}, + {"video/scrambled" , "Scrambled" }, + + // Audio + {"audio/3gpp" , "AMR NB" }, + {"audio/amr-wb" , "AMR WB" }, + {"audio/mpeg" , "MPEG" }, + {"audio/mpeg-L1" , "MPEG Layer I" }, + {"audio/mpeg-L2" , "MPEG Layer II"}, + {"audio/midi" , "MIDI" }, + {"audio/mp4a-latm", "AAC" }, + {"audio/qcelp" , "QCELP" }, + {"audio/vorbis" , "Vorbis" }, + {"audio/opus" , "Opus" }, + {"audio/g711-alaw", "G.711 a-law" }, + {"audio/g711-mlaw", "G.711 mu-law" }, + {"audio/raw" , "RAW" }, + {"audio/flac" , "FLAC" }, + {"audio/aac-adts" , "AAC ADTS" }, + {"audio/gsm" , "MS GSM" }, + {"audio/ac3" , "AC3" }, + {"audio/eac3" , "EAC3" }, + {"audio/scrambled", "Scrambled" }, + {"audio/alac" , "ALAC" }, + }; + + return codecsInfo; +} + +const CodecsInfo *CodecsInfo::byMimeType(const QString &mimeType) +{ + for (auto &info: info()) + if (info.mimeType == mimeType) + return &info; + + return nullptr; +} + +#include "moc_mediawriterndkmedia.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/mediawriterndkmedia.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/mediawriterndkmedia.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/mediawriterndkmedia.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/mediawriterndkmedia.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,92 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef MEDIAWRITERNDKMEDIA_H +#define MEDIAWRITERNDKMEDIA_H + +#include "mediawriter.h" + +class MediaWriterNDKMediaPrivate; +class AkAudioCaps; +class AkVideoCaps; +struct AMediaCodecBufferInfo; +struct AMediaFormat; + +class MediaWriterNDKMedia: public MediaWriter +{ + Q_OBJECT + + public: + MediaWriterNDKMedia(QObject *parent=nullptr); + ~MediaWriterNDKMedia(); + + Q_INVOKABLE QString defaultFormat(); + Q_INVOKABLE QString outputFormat() const; + Q_INVOKABLE QVariantList streams() const; + Q_INVOKABLE qint64 maxPacketQueueSize() const; + Q_INVOKABLE QStringList supportedFormats(); + Q_INVOKABLE QStringList fileExtensions(const QString &format); + Q_INVOKABLE QString formatDescription(const QString &format); + Q_INVOKABLE QVariantList formatOptions(); + Q_INVOKABLE QStringList supportedCodecs(const QString &format); + Q_INVOKABLE QStringList supportedCodecs(const QString &format, + const QString &type); + Q_INVOKABLE QString defaultCodec(const QString &format, + const QString &type); + Q_INVOKABLE QString codecDescription(const QString &codec); + Q_INVOKABLE QString codecType(const QString &codec); + Q_INVOKABLE QVariantMap defaultCodecParams(const QString &codec); + Q_INVOKABLE QVariantMap addStream(int streamIndex, + const AkCaps &streamCaps); + Q_INVOKABLE QVariantMap addStream(int streamIndex, + const AkCaps &streamCaps, + const QVariantMap &codecParams); + Q_INVOKABLE QVariantMap updateStream(int index); + Q_INVOKABLE QVariantMap updateStream(int index, + const QVariantMap &codecParams); + Q_INVOKABLE QVariantList codecOptions(int index); + + private: + MediaWriterNDKMediaPrivate *d; + + public slots: + void setOutputFormat(const QString &outputFormat); + void setFormatOptions(const QVariantMap &formatOptions); + void setCodecOptions(int index, const QVariantMap &codecOptions); + void setMaxPacketQueueSize(qint64 maxPacketQueueSize); + void resetOutputFormat(); + void resetFormatOptions(); + void resetCodecOptions(int index); + void resetMaxPacketQueueSize(); + void enqueuePacket(const AkPacket &packet); + void clearStreams(); + bool init(); + void uninit(); + bool startMuxing(); + + private slots: + void writePacket(size_t trackIdx, + const uint8_t *data, + const AMediaCodecBufferInfo *info); + + friend class VideoStream; + friend class AudioStream; +}; + +#endif // MEDIAWRITERNDKMEDIA_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "mediawriterndkmedia.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new MediaWriterNDKMedia(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return QStringList(); +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/videostream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/videostream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/videostream.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/videostream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,309 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "videostream.h" +#include "mediawriterndkmedia.h" + +#define COLOR_FormatMonochrome 1 +#define COLOR_Format8bitRGB332 2 +#define COLOR_Format12bitRGB444 3 +#define COLOR_Format16bitARGB4444 4 +#define COLOR_Format16bitARGB1555 5 +#define COLOR_Format16bitRGB565 6 +#define COLOR_Format16bitBGR565 7 +#define COLOR_Format18bitRGB666 8 +#define COLOR_Format18bitARGB1665 9 +#define COLOR_Format19bitARGB1666 10 +#define COLOR_Format24bitRGB888 11 +#define COLOR_Format24bitBGR888 12 +#define COLOR_Format24bitARGB1887 13 +#define COLOR_Format25bitARGB1888 14 +#define COLOR_Format32bitBGRA8888 15 +#define COLOR_Format32bitARGB8888 16 +#define COLOR_FormatYUV411Planar 17 +#define COLOR_FormatYUV411PackedPlanar 18 +#define COLOR_FormatYUV420Planar 19 +#define COLOR_FormatYUV420PackedPlanar 20 +#define COLOR_FormatYUV420SemiPlanar 21 +#define COLOR_FormatYUV422Planar 22 +#define COLOR_FormatYUV422PackedPlanar 23 +#define COLOR_FormatYUV422SemiPlanar 24 +#define COLOR_FormatYCbYCr 25 +#define COLOR_FormatYCrYCb 26 +#define COLOR_FormatCbYCrY 27 +#define COLOR_FormatCrYCbY 28 +#define COLOR_FormatYUV444Interleaved 29 +#define COLOR_FormatRawBayer8bit 30 +#define COLOR_FormatRawBayer10bit 31 +#define COLOR_FormatRawBayer8bitcompressed 32 +#define COLOR_FormatL2 33 +#define COLOR_FormatL4 34 +#define COLOR_FormatL8 35 +#define COLOR_FormatL16 36 +#define COLOR_FormatL24 37 +#define COLOR_FormatL32 38 +#define COLOR_FormatYUV420PackedSemiPlanar 39 +#define COLOR_FormatYUV422PackedSemiPlanar 40 +#define COLOR_Format18BitBGR666 41 +#define COLOR_Format24BitARGB6666 42 +#define COLOR_Format24BitABGR6666 43 +#define COLOR_TI_FormatYUV420PackedSemiPlanar 0x7f000100 +#define COLOR_FormatSurface 0x7f000789 +#define COLOR_Format32bitABGR8888 0x7f00a000 +#define COLOR_FormatYUV420Flexible 0x7f420888 +#define COLOR_FormatYUV422Flexible 0x7f422888 +#define COLOR_FormatYUV444Flexible 0x7f444888 +#define COLOR_FormatRGBFlexible 0x7f36b888 +#define COLOR_FormatRGBAFlexible 0x7f36a888 +#define COLOR_QCOM_FormatYUV420SemiPlanar 0x7fa30c00 + +using ImageFormatToPixelFormatMap = QMap; + +inline const ImageFormatToPixelFormatMap &imageFormatToPixelFormat() +{ + static const ImageFormatToPixelFormatMap imgFmtToPixFmt { + {COLOR_FormatMonochrome , AkVideoCaps::Format_monob }, + {COLOR_Format8bitRGB332 , AkVideoCaps::Format_rgb8 }, + {COLOR_Format12bitRGB444 , AkVideoCaps::Format_rgb444le }, + {COLOR_Format16bitARGB4444 , AkVideoCaps::Format_argb444le }, + {COLOR_Format16bitARGB1555 , AkVideoCaps::Format_argb555le }, + {COLOR_Format16bitRGB565 , AkVideoCaps::Format_rgb565le }, + {COLOR_Format16bitBGR565 , AkVideoCaps::Format_bgr565le }, + {COLOR_Format18bitRGB666 , AkVideoCaps::Format_rgb666 }, + {COLOR_Format18bitARGB1665 , AkVideoCaps::Format_argb1665 }, + {COLOR_Format19bitARGB1666 , AkVideoCaps::Format_argb1666 }, + {COLOR_Format24bitRGB888 , AkVideoCaps::Format_rgb24 }, + {COLOR_Format24bitBGR888 , AkVideoCaps::Format_bgr24 }, + {COLOR_Format24bitARGB1887 , AkVideoCaps::Format_argb1887 }, + {COLOR_Format25bitARGB1888 , AkVideoCaps::Format_bgra1888 }, + {COLOR_Format32bitBGRA8888 , AkVideoCaps::Format_bgra }, + {COLOR_Format32bitARGB8888 , AkVideoCaps::Format_argb }, + {COLOR_FormatYUV411Planar , AkVideoCaps::Format_yuv411p }, + {COLOR_FormatYUV411PackedPlanar , AkVideoCaps::Format_yuv411p }, + {COLOR_FormatYUV420Planar , AkVideoCaps::Format_yuv420p }, + {COLOR_FormatYUV420PackedPlanar , AkVideoCaps::Format_yuv420p }, + {COLOR_FormatYUV420SemiPlanar , AkVideoCaps::Format_nv12 }, + {COLOR_FormatYUV422Planar , AkVideoCaps::Format_yuv422p }, + {COLOR_FormatYUV422PackedPlanar , AkVideoCaps::Format_yuv422p }, + {COLOR_FormatYUV422SemiPlanar , AkVideoCaps::Format_yuv422p }, + {COLOR_FormatYCbYCr , AkVideoCaps::Format_yuyv422 }, + {COLOR_FormatYCrYCb , AkVideoCaps::Format_yvyu422 }, + {COLOR_FormatCbYCrY , AkVideoCaps::Format_uyvy422 }, + {COLOR_FormatCrYCbY , AkVideoCaps::Format_vyuy422 }, + {COLOR_FormatYUV444Interleaved , AkVideoCaps::Format_yuv444 }, + {COLOR_FormatRawBayer8bit , AkVideoCaps::Format_bayer_rggb8}, +// {COLOR_FormatRawBayer10bit , AkVideoCaps::Format_ }, +// {COLOR_FormatRawBayer8bitcompressed , AkVideoCaps::Format_ }, + {COLOR_FormatL2 , AkVideoCaps::Format_gray2 }, + {COLOR_FormatL4 , AkVideoCaps::Format_gray4 }, + {COLOR_FormatL8 , AkVideoCaps::Format_gray }, + {COLOR_FormatL16 , AkVideoCaps::Format_gray16le }, + {COLOR_FormatL24 , AkVideoCaps::Format_gray24 }, + {COLOR_FormatL32 , AkVideoCaps::Format_gray32 }, + {COLOR_FormatYUV420PackedSemiPlanar , AkVideoCaps::Format_yuv420p }, + {COLOR_FormatYUV422PackedSemiPlanar , AkVideoCaps::Format_yuv422p }, + {COLOR_Format18BitBGR666 , AkVideoCaps::Format_bgr666 }, + {COLOR_Format24BitARGB6666 , AkVideoCaps::Format_argb6666 }, + {COLOR_Format24BitABGR6666 , AkVideoCaps::Format_abgr6666 }, +// {COLOR_TI_FormatYUV420PackedSemiPlanar, AkVideoCaps::Format_ }, +// {COLOR_FormatSurface , AkVideoCaps::Format_ }, + {COLOR_Format32bitABGR8888 , AkVideoCaps::Format_abgr }, + {COLOR_FormatYUV420Flexible , AkVideoCaps::Format_yuv420p }, + {COLOR_FormatYUV422Flexible , AkVideoCaps::Format_yuv422p }, + {COLOR_FormatYUV444Flexible , AkVideoCaps::Format_yuv444p }, + {COLOR_FormatRGBFlexible , AkVideoCaps::Format_rgbp }, + {COLOR_FormatRGBAFlexible , AkVideoCaps::Format_rgbap }, +// {COLOR_QCOM_FormatYUV420SemiPlanar , AkVideoCaps::Format_ }, + }; + + return imgFmtToPixFmt; +} + +const QVector &h263SupportedSize() +{ + static const QVector supportedSize { + QSize(1408, 1152), + QSize( 704, 576), + QSize( 352, 288), + QSize( 176, 144), + QSize( 128, 96) + }; + + return supportedSize; +} + +class VideoStreamPrivate +{ + public: + VideoStream *self; + AkVideoPacket m_frame; + QMutex m_frameMutex; + QWaitCondition m_frameReady; + AkVideoCaps m_caps; + + explicit VideoStreamPrivate(VideoStream *self); + static AkVideoCaps nearestH263Caps(const AkVideoCaps &caps); +}; + +VideoStream::VideoStream(AMediaMuxer *mediaMuxerformatContext, + uint index, + int streamIndex, + const QVariantMap &configs, + const QMap &codecOptions, + MediaWriterNDKMedia *mediaWriter, + QObject *parent): + AbstractStream(mediaMuxerformatContext, + index, streamIndex, + configs, + codecOptions, + mediaWriter, + parent) +{ + this->d = new VideoStreamPrivate(this); + this->d->m_caps = configs["caps"].value(); + auto codecName = configs["codec"].toString(); + auto defaultCodecParams = mediaWriter->defaultCodecParams(codecName); + auto pixelFormat = AkVideoCaps::pixelFormatToString(this->d->m_caps.format()); + auto supportedPixelFormats = + defaultCodecParams["supportedPixelFormats"].toStringList(); + + if (!supportedPixelFormats.isEmpty() + && !supportedPixelFormats.contains(pixelFormat)) { + auto defaultPixelFormat = defaultCodecParams["defaultPixelFormat"].toString(); + this->d->m_caps.setFormat(AkVideoCaps::pixelFormatFromString(defaultPixelFormat)); + } + + if (codecName == "video/3gpp") + this->d->m_caps = VideoStreamPrivate::nearestH263Caps(this->d->m_caps); + + int32_t interval = + qRound(configs["gop"].toInt() / this->d->m_caps.fps().value()); + + if (interval < 1) + interval = 1; + + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_COLOR_FORMAT, + VideoStream::colorFormatFromPixelFormat(this->d->m_caps.format())); + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_WIDTH, + this->d->m_caps.width()); + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_HEIGHT, + this->d->m_caps.height()); + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_FRAME_RATE, + qRound(this->d->m_caps.fps().value())); + AMediaFormat_setInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, + interval); +} + +VideoStream::~VideoStream() +{ + this->uninit(); + delete this->d; +} + +int32_t VideoStream::colorFormatFromPixelFormat(AkVideoCaps::PixelFormat format) +{ + return imageFormatToPixelFormat().key(format); +} + +void VideoStream::convertPacket(const AkPacket &packet) +{ + if (!packet) + return; + + AkVideoPacket videoPacket(packet); + videoPacket = videoPacket.scaled(this->d->m_caps.width(), + this->d->m_caps.height()); + videoPacket = videoPacket.convert(this->d->m_caps.format()); + + this->d->m_frameMutex.lock(); + this->d->m_frame = videoPacket; + this->d->m_frameReady.wakeAll(); + this->d->m_frameMutex.unlock(); +} + +AkPacket VideoStream::avPacketDequeue(size_t bufferSize) +{ + Q_UNUSED(bufferSize) + + this->d->m_frameMutex.lock(); + + if (!this->d->m_frame) + if (!this->d->m_frameReady.wait(&this->d->m_frameMutex, + THREAD_WAIT_LIMIT)) { + this->d->m_frameMutex.unlock(); + + return nullptr; + } + + auto frame = this->d->m_frame; + this->d->m_frame = AkVideoPacket(); + this->d->m_frameMutex.unlock(); + + return frame; +} + +VideoStreamPrivate::VideoStreamPrivate(VideoStream *self): + self(self) +{ + +} + +AkVideoCaps VideoStreamPrivate::nearestH263Caps(const AkVideoCaps &caps) +{ + QSize nearestSize; + auto q = std::numeric_limits::max(); + + for (auto &size: h263SupportedSize()) { + qreal dw = size.width() - caps.width(); + qreal dh = size.height() - caps.height(); + qreal k = dw * dw + dh * dh; + + if (k < q) { + nearestSize = size; + q = k; + + if (k == 0.) + break; + } + } + + AkVideoCaps nearestCaps(caps); + nearestCaps.setWidth(nearestSize.width()); + nearestCaps.setHeight(nearestSize.height()); + + return nearestCaps; +} + +#include "moc_videostream.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/videostream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/videostream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/videostream.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/ndkmedia/src/videostream.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,52 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef VIDEOSTREAM_H +#define VIDEOSTREAM_H + +#include + +#include "abstractstream.h" + +class VideoStreamPrivate; + +class VideoStream: public AbstractStream +{ + Q_OBJECT + + public: + VideoStream(AMediaMuxer *mediaMuxerformatContext=nullptr, + uint index=0, int streamIndex=-1, + const QVariantMap &configs={}, + const QMap &codecOptions={}, + MediaWriterNDKMedia *mediaWriter=nullptr, + QObject *parent=nullptr); + ~VideoStream(); + + Q_INVOKABLE static int32_t colorFormatFromPixelFormat(AkVideoCaps::PixelFormat format); + + private: + VideoStreamPrivate *d; + + protected: + void convertPacket(const AkPacket &packet); + AkPacket avPacketDequeue(size_t bufferSize); +}; + +#endif // VIDEOSTREAM_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/src.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/src.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSink/src/src.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSink/src/src.pro 2021-02-15 15:25:23.000000000 +0000 @@ -36,9 +36,10 @@ HEADERS = \ multisink.h \ multisinkelement.h \ - mediawriter.h \ + multisinkelementsettings.h \ multisinkglobals.h \ - multisinkutils.h + multisinkutils.h \ + mediawriter.h INCLUDEPATH += \ ../../../Lib/src @@ -55,9 +56,10 @@ SOURCES = \ multisink.cpp \ multisinkelement.cpp \ - mediawriter.cpp \ + multisinkelementsettings.cpp \ multisinkglobals.cpp \ - multisinkutils.cpp + multisinkutils.cpp \ + mediawriter.cpp lupdate_only { SOURCES += $$files(../share/qml/*.qml) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/MultiSrc.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/MultiSrc.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/MultiSrc.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/MultiSrc.pro 2021-02-15 15:25:23.000000000 +0000 @@ -23,3 +23,4 @@ SUBDIRS = src CONFIG(config_ffmpeg): SUBDIRS += src/ffmpeg CONFIG(config_gstreamer): SUBDIRS += src/gstreamer +CONFIG(config_ndk_media): SUBDIRS += src/ndkmedia diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/abstractstream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/abstractstream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/abstractstream.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/abstractstream.h 2021-02-15 15:25:23.000000000 +0000 @@ -25,8 +25,6 @@ extern "C" { #include -// #include -// #include } #ifdef PixelFormat diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/audiostream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/audiostream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/audiostream.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/audiostream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,11 +19,13 @@ #include #include +#include #include #include #include -#include +#include #include +#include #include extern "C" @@ -44,73 +46,7 @@ #define AUDIO_DIFF_AVG_NB 20 using SampleFormatMap = QMap; - -inline SampleFormatMap initSampleFormatMap() -{ - SampleFormatMap sampleFormat = { - {AV_SAMPLE_FMT_U8 , AkAudioCaps::SampleFormat_u8 }, - {AV_SAMPLE_FMT_S16 , AkAudioCaps::SampleFormat_s16 }, - {AV_SAMPLE_FMT_S32 , AkAudioCaps::SampleFormat_s32 }, - {AV_SAMPLE_FMT_FLT , AkAudioCaps::SampleFormat_flt }, - {AV_SAMPLE_FMT_DBL , AkAudioCaps::SampleFormat_dbl }, - {AV_SAMPLE_FMT_U8P , AkAudioCaps::SampleFormat_u8p }, - {AV_SAMPLE_FMT_S16P, AkAudioCaps::SampleFormat_s16p}, - {AV_SAMPLE_FMT_S32P, AkAudioCaps::SampleFormat_s32p}, - {AV_SAMPLE_FMT_FLTP, AkAudioCaps::SampleFormat_fltp}, - {AV_SAMPLE_FMT_DBLP, AkAudioCaps::SampleFormat_dblp}, - -#ifdef HAVE_SAMPLEFORMAT64 - {AV_SAMPLE_FMT_S64 , AkAudioCaps::SampleFormat_s64 }, - {AV_SAMPLE_FMT_S64P, AkAudioCaps::SampleFormat_s64p}, -#endif - }; - - return sampleFormat; -} - -Q_GLOBAL_STATIC_WITH_ARGS(SampleFormatMap, sampleFormats, (initSampleFormatMap())) - -using ChannelLayoutsMap = QMap; - -inline ChannelLayoutsMap initChannelFormatsMap() -{ - ChannelLayoutsMap channelLayouts = { - {AkAudioCaps::Layout_mono , AV_CH_LAYOUT_MONO }, - {AkAudioCaps::Layout_stereo , AV_CH_LAYOUT_STEREO }, - {AkAudioCaps::Layout_2p1 , AV_CH_LAYOUT_2POINT1 }, - {AkAudioCaps::Layout_3p0 , AV_CH_LAYOUT_SURROUND }, - {AkAudioCaps::Layout_3p0_back , AV_CH_LAYOUT_2_1 }, - {AkAudioCaps::Layout_3p1 , AV_CH_LAYOUT_3POINT1 }, - {AkAudioCaps::Layout_4p0 , AV_CH_LAYOUT_4POINT0 }, - {AkAudioCaps::Layout_quad , AV_CH_LAYOUT_QUAD }, - {AkAudioCaps::Layout_quad_side , AV_CH_LAYOUT_2_2 }, - {AkAudioCaps::Layout_4p1 , AV_CH_LAYOUT_4POINT1 }, - {AkAudioCaps::Layout_5p0 , AV_CH_LAYOUT_5POINT0_BACK }, - {AkAudioCaps::Layout_5p0_side , AV_CH_LAYOUT_5POINT0 }, - {AkAudioCaps::Layout_5p1 , AV_CH_LAYOUT_5POINT1_BACK }, - {AkAudioCaps::Layout_5p1_side , AV_CH_LAYOUT_5POINT1 }, - {AkAudioCaps::Layout_6p0 , AV_CH_LAYOUT_6POINT0 }, - {AkAudioCaps::Layout_6p0_front , AV_CH_LAYOUT_6POINT0_FRONT }, - {AkAudioCaps::Layout_hexagonal , AV_CH_LAYOUT_HEXAGONAL }, - {AkAudioCaps::Layout_6p1 , AV_CH_LAYOUT_6POINT1 }, - {AkAudioCaps::Layout_6p1_back , AV_CH_LAYOUT_6POINT1_BACK }, - {AkAudioCaps::Layout_6p1_front , AV_CH_LAYOUT_6POINT1_FRONT }, - {AkAudioCaps::Layout_7p0 , AV_CH_LAYOUT_7POINT0 }, - {AkAudioCaps::Layout_7p0_front , AV_CH_LAYOUT_7POINT0_FRONT }, - {AkAudioCaps::Layout_7p1 , AV_CH_LAYOUT_7POINT1 }, - {AkAudioCaps::Layout_7p1_wide , AV_CH_LAYOUT_7POINT1_WIDE }, - {AkAudioCaps::Layout_7p1_wide_side, AV_CH_LAYOUT_7POINT1_WIDE_BACK}, - {AkAudioCaps::Layout_octagonal , AV_CH_LAYOUT_OCTAGONAL }, -#ifdef AV_CH_LAYOUT_HEXADECAGONAL - {AkAudioCaps::Layout_hexadecagonal, AV_CH_LAYOUT_HEXADECAGONAL }, -#endif - {AkAudioCaps::Layout_downmix , AV_CH_LAYOUT_STEREO_DOWNMIX }, - }; - - return channelLayouts; -} - -Q_GLOBAL_STATIC_WITH_ARGS(ChannelLayoutsMap, channelLayouts, (initChannelFormatsMap())) +using ChannelLayoutsMap = QMap; class AudioStreamPrivate { @@ -124,9 +60,88 @@ explicit AudioStreamPrivate(AudioStream *self); bool compensate(AVFrame *oFrame, AVFrame *iFrame, int wantedSamples); - AkPacket frameToPacket(AVFrame *iFrame); + AkAudioPacket frameToPacket(AVFrame *iFrame); AkPacket convert(AVFrame *iFrame); AVFrame *copyFrame(AVFrame *frame) const; + + inline static const SampleFormatMap &sampleFormats() + { + static const SampleFormatMap sampleFormat { + {AV_SAMPLE_FMT_U8 , AkAudioCaps::SampleFormat_u8 }, + {AV_SAMPLE_FMT_S16 , AkAudioCaps::SampleFormat_s16}, + {AV_SAMPLE_FMT_S32 , AkAudioCaps::SampleFormat_s32}, + {AV_SAMPLE_FMT_FLT , AkAudioCaps::SampleFormat_flt}, + {AV_SAMPLE_FMT_DBL , AkAudioCaps::SampleFormat_dbl}, + + {AV_SAMPLE_FMT_U8P , AkAudioCaps::SampleFormat_u8 }, + {AV_SAMPLE_FMT_S16P, AkAudioCaps::SampleFormat_s16}, + {AV_SAMPLE_FMT_S32P, AkAudioCaps::SampleFormat_s32}, + {AV_SAMPLE_FMT_FLTP, AkAudioCaps::SampleFormat_flt}, + {AV_SAMPLE_FMT_DBLP, AkAudioCaps::SampleFormat_dbl}, + +#ifdef HAVE_SAMPLEFORMAT64 + {AV_SAMPLE_FMT_S64 , AkAudioCaps::SampleFormat_s64}, + {AV_SAMPLE_FMT_S64P, AkAudioCaps::SampleFormat_s64}, +#endif + }; + + return sampleFormat; + } + + inline static const QVector &planarFormats() + { + static const QVector formats { + AV_SAMPLE_FMT_U8P , + AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBLP, + +#ifdef HAVE_SAMPLEFORMAT64 + AV_SAMPLE_FMT_S64P, +#endif + }; + + return formats; + } + + inline static const ChannelLayoutsMap &channelLayouts() + { + static const ChannelLayoutsMap channelLayouts { + {AV_CH_LAYOUT_MONO , AkAudioCaps::Layout_mono }, + {AV_CH_LAYOUT_STEREO , AkAudioCaps::Layout_stereo }, + {AV_CH_LAYOUT_2POINT1 , AkAudioCaps::Layout_2p1 }, + {AV_CH_LAYOUT_SURROUND , AkAudioCaps::Layout_3p0 }, + {AV_CH_LAYOUT_2_1 , AkAudioCaps::Layout_3p0_back }, + {AV_CH_LAYOUT_3POINT1 , AkAudioCaps::Layout_3p1 }, + {AV_CH_LAYOUT_4POINT0 , AkAudioCaps::Layout_4p0 }, + {AV_CH_LAYOUT_QUAD , AkAudioCaps::Layout_quad }, + {AV_CH_LAYOUT_2_2 , AkAudioCaps::Layout_quad_side }, + {AV_CH_LAYOUT_4POINT1 , AkAudioCaps::Layout_4p1 }, + {AV_CH_LAYOUT_5POINT0_BACK , AkAudioCaps::Layout_5p0 }, + {AV_CH_LAYOUT_5POINT0 , AkAudioCaps::Layout_5p0_side }, + {AV_CH_LAYOUT_5POINT1_BACK , AkAudioCaps::Layout_5p1 }, + {AV_CH_LAYOUT_5POINT1 , AkAudioCaps::Layout_5p1_side }, + {AV_CH_LAYOUT_6POINT0 , AkAudioCaps::Layout_6p0 }, + {AV_CH_LAYOUT_6POINT0_FRONT , AkAudioCaps::Layout_6p0_front }, + {AV_CH_LAYOUT_HEXAGONAL , AkAudioCaps::Layout_hexagonal }, + {AV_CH_LAYOUT_6POINT1 , AkAudioCaps::Layout_6p1 }, + {AV_CH_LAYOUT_6POINT1_BACK , AkAudioCaps::Layout_6p1_back }, + {AV_CH_LAYOUT_6POINT1_FRONT , AkAudioCaps::Layout_6p1_front }, + {AV_CH_LAYOUT_7POINT0 , AkAudioCaps::Layout_7p0 }, + {AV_CH_LAYOUT_7POINT0_FRONT , AkAudioCaps::Layout_7p0_front }, + {AV_CH_LAYOUT_7POINT1 , AkAudioCaps::Layout_7p1 }, + {AV_CH_LAYOUT_7POINT1_WIDE , AkAudioCaps::Layout_7p1_wide }, + {AV_CH_LAYOUT_7POINT1_WIDE_BACK, AkAudioCaps::Layout_7p1_wide_back}, + {AV_CH_LAYOUT_OCTAGONAL , AkAudioCaps::Layout_octagonal }, + #ifdef AV_CH_LAYOUT_HEXADECAGONAL + {AV_CH_LAYOUT_HEXADECAGONAL , AkAudioCaps::Layout_hexadecagonal}, + #endif + {AV_CH_LAYOUT_STEREO_DOWNMIX , AkAudioCaps::Layout_downmix }, + }; + + return channelLayouts; + } }; AudioStream::AudioStream(const AVFormatContext *formatContext, @@ -148,22 +163,17 @@ { auto iFormat = AVSampleFormat(this->codecContext()->sample_fmt); auto oFormat = av_get_packed_sample_fmt(iFormat); - oFormat = sampleFormats->contains(oFormat)? oFormat: AV_SAMPLE_FMT_FLT; + oFormat = AudioStreamPrivate::sampleFormats().contains(oFormat)? + oFormat: AV_SAMPLE_FMT_FLT; - AkAudioCaps::ChannelLayout layout = channelLayouts->key(this->codecContext()->channel_layout, - AkAudioCaps::Layout_stereo); - uint64_t channelLayout = - channelLayouts->value(layout, AV_CH_LAYOUT_STEREO); - - AkAudioCaps caps; - caps.isValid() = true; - caps.format() = sampleFormats->value(oFormat);; - caps.bps() = 8 * av_get_bytes_per_sample(oFormat); - caps.channels() = av_get_channel_layout_nb_channels(channelLayout); - caps.rate() = this->codecContext()->sample_rate; - caps.layout() = layout; + AkAudioCaps caps(AudioStreamPrivate::sampleFormats().value(oFormat), + AudioStreamPrivate::channelLayouts() + .value(this->codecContext()->channel_layout, + AkAudioCaps::Layout_stereo), + this->codecContext()->sample_rate, + AudioStreamPrivate::planarFormats().contains(oFormat)); - return caps.toCaps(); + return caps; } void AudioStream::processPacket(AVPacket *packet) @@ -257,7 +267,7 @@ return true; } -AkPacket AudioStreamPrivate::frameToPacket(AVFrame *iFrame) +AkAudioPacket AudioStreamPrivate::frameToPacket(AVFrame *iFrame) { int iChannels = av_get_channel_layout_nb_channels(iFrame->channel_layout); @@ -293,11 +303,15 @@ } AkAudioPacket packet; - packet.caps() = AkAudioCaps(sampleFormats->value(AVSampleFormat(iFrame->format)), - iChannels, - iFrame->sample_rate); - packet.caps().layout() = channelLayouts->key(iFrame->channel_layout); - packet.caps().samples() = iFrame->nb_samples; + packet.caps() = + AkAudioCaps(AudioStreamPrivate::sampleFormats() + .value(AVSampleFormat(iFrame->format)), + AudioStreamPrivate::channelLayouts() + .value(iFrame->channel_layout), + iFrame->sample_rate, + iFrame->nb_samples, + AudioStreamPrivate::planarFormats() + .contains(AVSampleFormat(iFrame->format))); packet.buffer() = iBuffer; packet.pts() = iFrame->pts; @@ -305,31 +319,19 @@ packet.index() = int(self->index()); packet.id() = self->id(); - return packet.toPacket(); + return packet; } AkPacket AudioStreamPrivate::convert(AVFrame *iFrame) { - if (this->m_audioConvert->state() != AkElement::ElementStatePlaying) { - auto format = sampleFormats->value(AVSampleFormat(iFrame->format), - AkAudioCaps::SampleFormat_flt); + auto packet = this->frameToPacket(iFrame); - if (AkAudioCaps::bitsPerSample(format) > 32 - || AkAudioCaps::isPlanar(format)) - format = AkAudioCaps::SampleFormat_flt; - - int iChannels = - av_get_channel_layout_nb_channels(iFrame->channel_layout); - - AkAudioCaps caps(format, - iChannels > 1? 2: 1, - iFrame->sample_rate); - this->m_audioConvert->setProperty("caps", caps.toString()); + if (this->m_audioConvert->state() != AkElement::ElementStatePlaying) { + this->m_audioConvert->setProperty("caps", + QVariant::fromValue(packet.caps())); this->m_audioConvert->setState(AkElement::ElementStatePlaying); } - auto packet = this->frameToPacket(iFrame); - // Synchronize audio qreal pts = iFrame->pts * self->timeBase().value(); qreal diff = pts - self->globalClock()->clock(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/mediasourceffmpeg.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/mediasourceffmpeg.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/mediasourceffmpeg.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/mediasourceffmpeg.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -30,10 +30,10 @@ #include #include "mediasourceffmpeg.h" -#include "videostream.h" #include "audiostream.h" -#include "subtitlestream.h" #include "clock.h" +#include "subtitlestream.h" +#include "videostream.h" using FormatContextPtr = QSharedPointer; using AbstractStreamPtr = QSharedPointer; @@ -300,28 +300,32 @@ AbstractStreamPtr MediaSourceFFmpegPrivate::createStream(int index, bool noModify) { - AVMediaType type = AbstractStream::type(this->m_inputContext.data(), uint(index)); + auto type = AbstractStream::type(this->m_inputContext.data(), uint(index)); AbstractStreamPtr stream; - qint64 id = Ak::id(); + auto id = Ak::id(); if (type == AVMEDIA_TYPE_VIDEO) stream = AbstractStreamPtr(new VideoStream(this->m_inputContext.data(), - uint(index), id, + uint(index), + id, &this->m_globalClock, noModify)); else if (type == AVMEDIA_TYPE_AUDIO) stream = AbstractStreamPtr(new AudioStream(this->m_inputContext.data(), - uint(index), id, + uint(index), + id, &this->m_globalClock, noModify)); else if (type == AVMEDIA_TYPE_SUBTITLE) stream = AbstractStreamPtr(new SubtitleStream(this->m_inputContext.data(), - uint(index), id, + uint(index), + id, &this->m_globalClock, noModify)); else stream = AbstractStreamPtr(new AbstractStream(this->m_inputContext.data(), - uint(index), id, + uint(index), + id, &this->m_globalClock, noModify)); @@ -334,7 +338,8 @@ this->m_dataMutex.lock(); if (this->packetQueueSize() >= this->m_maxPacketQueueSize) - if (!this->m_packetQueueNotFull.wait(&this->m_dataMutex, THREAD_WAIT_LIMIT)) { + if (!this->m_packetQueueNotFull.wait(&this->m_dataMutex, + THREAD_WAIT_LIMIT)) { this->m_dataMutex.unlock(); continue; @@ -502,7 +507,7 @@ filterStreams = this->d->m_streams; for (auto &i: filterStreams) { - AbstractStreamPtr stream = this->d->createStream(i); + auto stream = this->d->createStream(i); if (stream) { this->d->m_streamsMap[i] = stream; @@ -512,17 +517,14 @@ this, SIGNAL(oStream(AkPacket)), Qt::DirectConnection); - QObject::connect(stream.data(), SIGNAL(notify()), this, SLOT(packetConsumed())); - QObject::connect(stream.data(), SIGNAL(frameSent()), this, SLOT(log())); - QObject::connect(stream.data(), SIGNAL(eof()), this, diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/subtitlestream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/subtitlestream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/subtitlestream.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/subtitlestream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include extern "C" @@ -39,7 +40,7 @@ AkCaps SubtitleStream::caps() const { - return AkCaps("text/x-raw"); + return {"text/x-raw"}; } void SubtitleStream::processPacket(AVPacket *packet) @@ -74,8 +75,8 @@ QByteArray oBuffer(packet->size, 0); memcpy(oBuffer.data(), packet->data, size_t(packet->size)); - AkPacket oPacket(caps, oBuffer); - + AkPacket oPacket(caps); + oPacket.setBuffer(oBuffer); oPacket.setPts(packet->pts); oPacket.setTimeBase(this->timeBase()); oPacket.setIndex(int(this->index())); @@ -167,7 +168,8 @@ memcpy(oBuffer.data(), subtitle->rects[i]->ass, size_t(assLenght)); } - AkPacket oPacket(caps, oBuffer); + AkPacket oPacket(caps); + oPacket.setBuffer(oBuffer); oPacket.setPts(subtitle->pts); oPacket.setTimeBase(this->timeBase()); oPacket.setIndex(int(this->index())); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/videostream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/videostream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/videostream.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ffmpeg/src/videostream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,8 +20,8 @@ #include #include #include -#include #include +#include #include extern "C" @@ -84,15 +84,10 @@ AkCaps VideoStream::caps() const { - AkVideoCaps caps; - caps.isValid() = true; - caps.format() = AkVideoCaps::Format_rgb24; - caps.bpp() = AkVideoCaps::bitsPerPixel(caps.format()); - caps.width() = this->codecContext()->width; - caps.height() = this->codecContext()->height; - caps.fps() = this->d->fps(); - - return caps.toCaps(); + return AkVideoCaps(AkVideoCaps::Format_rgb24, + this->codecContext()->width, + this->codecContext()->height, + this->d->fps()); } void VideoStream::processPacket(AVPacket *packet) @@ -171,7 +166,7 @@ this->globalClock()->setClock(pts); this->m_clockDiff = diff; - AkPacket oPacket = this->d->convert(frame); + auto oPacket = this->d->convert(frame); emit this->oStream(oPacket); emit this->frameSent(); @@ -245,7 +240,7 @@ nullptr, oFrame.linesize); - QByteArray oBuffer(frameSize, 0); + QByteArray oBuffer(frameSize, Qt::Uninitialized); if (av_image_fill_pointers(reinterpret_cast(oFrame.data), outPixFormat, @@ -264,24 +259,20 @@ oFrame.data, oFrame.linesize); - AkVideoCaps caps; - caps.isValid() = true; - caps.format() = AkVideoCaps::Format_rgb24; - caps.bpp() = AkVideoCaps::bitsPerPixel(caps.format()); - caps.width() = width; - caps.height() = iFrame->height; - caps.fps() = this->fps(); - // Create packet + AkVideoPacket oPacket; - oPacket.caps() = caps; + oPacket.caps() = {AkVideoCaps::Format_rgb24, + width, + iFrame->height, + this->fps()}; oPacket.buffer() = oBuffer; oPacket.pts() = iFrame->pts; oPacket.timeBase() = self->timeBase(); oPacket.index() = int(self->index()); oPacket.id() = self->id(); - return oPacket.toPacket(); + return oPacket; } int64_t VideoStreamPrivate::bestEffortTimestamp(const AVFrame *frame) const diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/gstreamer/src/mediasourcegstreamer.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/gstreamer/src/mediasourcegstreamer.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/gstreamer/src/mediasourcegstreamer.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/gstreamer/src/mediasourcegstreamer.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -26,10 +26,12 @@ #include #include #include -#include -#include +#include +#include #include #include +#include +#include #include "mediasourcegstreamer.h" #include "stream.h" @@ -114,11 +116,14 @@ this->setState(AkElement::ElementStatePaused); QList tracks; + int i = 0; + + for (auto &streamInfo: this->d->m_streamInfo) { + if (mimeType.isEmpty() || streamInfo.caps.mimeType() == mimeType) + tracks << i; - for (int stream = 0; stream < this->d->m_streamInfo.size(); stream++) - if (mimeType.isEmpty() - || this->d->m_streamInfo[stream].caps.mimeType() == mimeType) - tracks << stream; + i++; + } if (!isRunning) this->setState(AkElement::ElementStateNull); @@ -133,7 +138,7 @@ if (!isRunning) this->setState(AkElement::ElementStatePaused); - Stream streamInfo = this->d->m_streamInfo.value(stream, Stream()); + auto streamInfo = this->d->m_streamInfo.value(stream, Stream()); if (!isRunning) this->setState(AkElement::ElementStateNull); @@ -154,14 +159,18 @@ this->setState(AkElement::ElementStatePaused); int defaultStream = -1; + int i = 0; - for (int stream = 0; stream < this->d->m_streamInfo.size(); stream++) - if (this->d->m_streamInfo[stream].caps.mimeType() == mimeType) { - defaultStream = stream; + for (auto &streamInfo: this->d->m_streamInfo) { + if (streamInfo.caps.mimeType() == mimeType) { + defaultStream = i; break; } + i++; + } + if (!isRunning) this->setState(AkElement::ElementStateNull); @@ -382,13 +391,11 @@ GstAudioInfo *audioInfo = gst_audio_info_new(); gst_audio_info_from_caps(audioInfo, caps); + AkAudioCaps audioCaps(AkAudioCaps::SampleFormat_s32, + AkAudioCaps::Layout_stereo, + audioInfo->rate); AkAudioPacket packet; - packet.caps().isValid() = true; - packet.caps().format() = AkAudioCaps::SampleFormat_flt; - packet.caps().bps() = 8 * audioInfo->bpf / audioInfo->channels; - packet.caps().channels() = audioInfo->channels; - packet.caps().rate() = audioInfo->rate; - packet.caps().layout() = AkAudioCaps::Layout_stereo; + packet.caps() = audioCaps; GstBuffer *buf = gst_sample_get_buffer(sample); GstMapInfo map; @@ -397,7 +404,7 @@ QByteArray oBuffer(int(map.size), 0); memcpy(oBuffer.data(), map.data, map.size); - packet.caps().samples() = gint(map.size) / audioInfo->bpf; + packet.caps().setSamples(gint(map.size) / audioInfo->bpf); gst_audio_info_free(audioInfo); packet.buffer() = oBuffer; @@ -409,7 +416,7 @@ gst_buffer_unmap(buf, &map); gst_sample_unref(sample); - emit self->oStream(packet.toPacket()); + emit self->oStream(packet); return GST_FLOW_OK; } @@ -432,23 +439,19 @@ GstVideoInfo *videoInfo = gst_video_info_new(); gst_video_info_from_caps(videoInfo, caps); - AkVideoPacket packet; - packet.caps().isValid() = true; - packet.caps().format() = AkVideoCaps::Format_rgb24; - packet.caps().bpp() = AkVideoCaps::bitsPerPixel(packet.caps().format()); - packet.caps().width() = videoInfo->width; - packet.caps().height() = videoInfo->height; - packet.caps().fps() = AkFrac(videoInfo->fps_n, videoInfo->fps_d); - gst_video_info_free(videoInfo); GstBuffer *buf = gst_sample_get_buffer(sample); GstMapInfo map; gst_buffer_map(buf, &map, GST_MAP_READ); - - QByteArray oBuffer(int(map.size), 0); + QByteArray oBuffer(int(map.size), Qt::Uninitialized); memcpy(oBuffer.data(), map.data, map.size); + AkVideoPacket packet; + packet.caps() = {AkVideoCaps::Format_rgb24, + videoInfo->width, + videoInfo->height, + AkFrac(videoInfo->fps_n, videoInfo->fps_d)}; packet.buffer() = oBuffer; packet.pts() = qint64(GST_BUFFER_PTS(buf)); packet.timeBase() = AkFrac(1, GST_SECOND); @@ -458,7 +461,7 @@ gst_buffer_unmap(buf, &map); gst_sample_unref(sample); - emit self->oStream(packet.toPacket()); + emit self->oStream(packet); return GST_FLOW_OK; } @@ -482,7 +485,6 @@ const gchar *format = gst_structure_get_string(capsStructure, "format"); AkPacket packet; - packet.caps().isValid() = true; packet.caps().setMimeType("text/x-raw"); packet.caps().setProperty("type", format); @@ -705,10 +707,16 @@ g_object_set(G_OBJECT(videoOutput), "emit-signals", TRUE, nullptr); g_object_set(G_OBJECT(subtitlesOutput), "emit-signals", TRUE, nullptr); +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + const char gstFormat[] = "S32LE"; +#else + const char gstFormat[] = "S32BE"; +#endif + // Convert audio to a standard format. GstCaps *audioCaps = gst_caps_new_simple("audio/x-raw", - "format", G_TYPE_STRING, "F32LE", + "format", G_TYPE_STRING, gstFormat, "channels", G_TYPE_INT, 2, "layout", G_TYPE_STRING, "interleaved", nullptr); @@ -811,14 +819,10 @@ GstAudioInfo *audioInfo = gst_audio_info_new(); gst_audio_info_from_caps(audioInfo, caps); - AkAudioCaps audioCaps; - audioCaps.isValid() = true; - audioCaps.format() = AkAudioCaps::SampleFormat_flt; - audioCaps.bps() = 8 * audioInfo->bpf / audioInfo->channels; - audioCaps.channels() = audioInfo->channels; - audioCaps.rate() = audioInfo->rate; - audioCaps.layout() = AkAudioCaps::Layout_stereo; - this->d->m_streamInfo << Stream(audioCaps.toCaps(), + AkAudioCaps audioCaps(AkAudioCaps::SampleFormat_s32, + AkAudioCaps::Layout_stereo, + audioInfo->rate); + this->d->m_streamInfo << Stream(audioCaps, languages[stream]); gst_audio_info_free(audioInfo); @@ -847,21 +851,20 @@ &pad); if (pad) { - GstCaps *caps = gst_pad_get_current_caps(pad); - GstVideoInfo *videoInfo = gst_video_info_new(); - gst_video_info_from_caps(videoInfo, caps); - - AkVideoCaps videoCaps; - videoCaps.isValid() = true; - videoCaps.format() = AkVideoCaps::Format_rgb24; - videoCaps.bpp() = AkVideoCaps::bitsPerPixel(videoCaps.format()); - videoCaps.width() = videoInfo->width; - videoCaps.height() = videoInfo->height; - videoCaps.fps() = AkFrac(videoInfo->fps_n, videoInfo->fps_d); - this->d->m_streamInfo << Stream(videoCaps.toCaps(), - languages[stream]); + if (auto caps = gst_pad_get_current_caps(pad)) { + auto videoInfo = gst_video_info_new(); + gst_video_info_from_caps(videoInfo, caps); + + AkVideoCaps videoCaps(AkVideoCaps::Format_rgb24, + videoInfo->width, + videoInfo->height, + AkFrac(videoInfo->fps_n, + videoInfo->fps_d)); + this->d->m_streamInfo << Stream(videoCaps, + languages[stream]); - gst_video_info_free(videoInfo); + gst_video_info_free(videoInfo); + } } g_object_set(G_OBJECT(this->d->m_pipeline), @@ -891,9 +894,7 @@ GstStructure *capsStructure = gst_caps_get_structure(caps, 0); const gchar *format = gst_structure_get_string(capsStructure, "format"); - AkCaps subtitlesCaps; - subtitlesCaps.isValid() = true; - subtitlesCaps.setMimeType("text/x-raw"); + AkCaps subtitlesCaps("text/x-raw"); subtitlesCaps.setProperty("type", format); this->d->m_streamInfo << Stream(subtitlesCaps, languages[stream]); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/gstreamer/src/stream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/gstreamer/src/stream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/gstreamer/src/stream.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/gstreamer/src/stream.h 2021-02-15 15:25:23.000000000 +0000 @@ -17,8 +17,8 @@ * Web-Site: http://webcamoid.github.io/ */ -#ifndef STREAM -#define STREAM +#ifndef STREAM_H +#define STREAM_H #include @@ -30,9 +30,9 @@ } Stream(const AkCaps &caps, - const QString &description): + const QString &language): caps(caps), - language(description) + language(language) { } @@ -40,5 +40,4 @@ QString language; }; -#endif // STREAM - +#endif // STREAM_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrc.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrc.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrc.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrc.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include "multisrc.h" #include "multisrcelement.h" +#include "multisrcelementsettings.h" QObject *MultiSrc::create(const QString &key, const QString &specification) { @@ -26,13 +27,16 @@ if (key == AK_PLUGIN_TYPE_ELEMENT) return new MultiSrcElement(); + else if (key == AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + return new MultiSrcElementSettings(); return nullptr; } QStringList MultiSrc::keys() const { - return QStringList(); + return {AK_PLUGIN_TYPE_ELEMENT, + AK_PLUGIN_TYPE_ELEMENT_SETTINGS}; } #include "moc_multisrc.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -23,11 +23,9 @@ #include #include "multisrcelement.h" -#include "multisrcglobals.h" +#include "multisrcelementsettings.h" #include "mediasource.h" -Q_GLOBAL_STATIC(MultiSrcGlobals, globalMultiSrc) - template inline QSharedPointer ptr_cast(QObject *obj=nullptr) { @@ -39,25 +37,26 @@ class MultiSrcElementPrivate { public: + MultiSrcElement *self; + MultiSrcElementSettings m_settings; MediaSourcePtr m_mediaSource; QMutex m_mutexLib; + + explicit MultiSrcElementPrivate(MultiSrcElement *self); + void codecLibUpdated(const QString &codecLib); }; MultiSrcElement::MultiSrcElement(): AkMultimediaSourceElement() { - this->d = new MultiSrcElementPrivate; - - QObject::connect(globalMultiSrc, - SIGNAL(codecLibChanged(const QString &)), - this, - SIGNAL(codecLibChanged(const QString &))); - QObject::connect(globalMultiSrc, - SIGNAL(codecLibChanged(const QString &)), - this, - SLOT(codecLibUpdated(const QString &))); + this->d = new MultiSrcElementPrivate(this); + QObject::connect(&this->d->m_settings, + &MultiSrcElementSettings::codecLibChanged, + [this] (const QString &codecLib) { + this->d->codecLibUpdated(codecLib); + }); - this->codecLibUpdated(globalMultiSrc->codecLib()); + this->d->codecLibUpdated(this->d->m_settings.codecLib()); } MultiSrcElement::~MultiSrcElement() @@ -154,11 +153,6 @@ return this->d->m_mediaSource->showLog(); } -QString MultiSrcElement::codecLib() const -{ - return globalMultiSrc->codecLib(); -} - QString MultiSrcElement::controlInterfaceProvide(const QString &controlId) const { Q_UNUSED(controlId) @@ -205,11 +199,6 @@ this->d->m_mediaSource->setShowLog(showLog); } -void MultiSrcElement::setCodecLib(const QString &codecLib) -{ - globalMultiSrc->setCodecLib(codecLib); -} - void MultiSrcElement::resetMedia() { if (this->d->m_mediaSource) @@ -240,11 +229,6 @@ this->d->m_mediaSource->resetShowLog(); } -void MultiSrcElement::resetCodecLib() -{ - globalMultiSrc->resetCodecLib(); -} - bool MultiSrcElement::setState(AkElement::ElementState state) { if (!this->d->m_mediaSource || !this->d->m_mediaSource->setState(state)) @@ -253,77 +237,83 @@ return AkElement::setState(state); } -void MultiSrcElement::codecLibUpdated(const QString &codecLib) +MultiSrcElementPrivate::MultiSrcElementPrivate(MultiSrcElement *self): + self(self) { - auto state = this->state(); - this->setState(AkElement::ElementStateNull); + +} + +void MultiSrcElementPrivate::codecLibUpdated(const QString &codecLib) +{ + auto state = self->state(); + self->setState(AkElement::ElementStateNull); QString media; bool loop = false; bool showLog = false; - if (this->d->m_mediaSource) { - media = this->d->m_mediaSource->media(); - loop = this->d->m_mediaSource->loop(); - showLog = this->d->m_mediaSource->showLog(); + if (this->m_mediaSource) { + media = this->m_mediaSource->media(); + loop = this->m_mediaSource->loop(); + showLog = this->m_mediaSource->showLog(); } - this->d->m_mutexLib.lock(); + this->m_mutexLib.lock(); - this->d->m_mediaSource = + this->m_mediaSource = ptr_cast(MultiSrcElement::loadSubModule("MultiSrc", codecLib)); - if (!this->d->m_mediaSource) { - this->d->m_mutexLib.unlock(); + if (!this->m_mediaSource) { + this->m_mutexLib.unlock(); return; } - QObject::connect(this->d->m_mediaSource.data(), + QObject::connect(this->m_mediaSource.data(), SIGNAL(oStream(const AkPacket &)), - this, + self, SIGNAL(oStream(const AkPacket &)), Qt::DirectConnection); - QObject::connect(this->d->m_mediaSource.data(), + QObject::connect(this->m_mediaSource.data(), SIGNAL(error(const QString &)), - this, + self, SIGNAL(error(const QString &))); - QObject::connect(this->d->m_mediaSource.data(), + QObject::connect(this->m_mediaSource.data(), SIGNAL(maxPacketQueueSizeChanged(qint64)), - this, + self, SIGNAL(maxPacketQueueSizeChanged(qint64))); - QObject::connect(this->d->m_mediaSource.data(), + QObject::connect(this->m_mediaSource.data(), SIGNAL(showLogChanged(bool)), - this, + self, SIGNAL(showLogChanged(bool))); - QObject::connect(this->d->m_mediaSource.data(), + QObject::connect(this->m_mediaSource.data(), SIGNAL(loopChanged(bool)), - this, + self, SIGNAL(loopChanged(bool))); - QObject::connect(this->d->m_mediaSource.data(), + QObject::connect(this->m_mediaSource.data(), SIGNAL(mediasChanged(const QStringList &)), - this, + self, SIGNAL(mediasChanged(const QStringList &))); - QObject::connect(this->d->m_mediaSource.data(), + QObject::connect(this->m_mediaSource.data(), SIGNAL(mediaChanged(const QString &)), - this, + self, SIGNAL(mediaChanged(const QString &))); - QObject::connect(this->d->m_mediaSource.data(), + QObject::connect(this->m_mediaSource.data(), SIGNAL(streamsChanged(const QList &)), - this, + self, SIGNAL(streamsChanged(const QList &))); - this->d->m_mutexLib.unlock(); + this->m_mutexLib.unlock(); - this->d->m_mediaSource->setMedia(media); - this->d->m_mediaSource->setLoop(loop); - this->d->m_mediaSource->setShowLog(showLog); + this->m_mediaSource->setMedia(media); + this->m_mediaSource->setLoop(loop); + this->m_mediaSource->setShowLog(showLog); - emit this->streamsChanged(this->streams()); - emit this->maxPacketQueueSizeChanged(this->maxPacketQueueSize()); + emit self->streamsChanged(self->streams()); + emit self->maxPacketQueueSizeChanged(self->maxPacketQueueSize()); - this->setState(state); + self->setState(state); } #include "moc_multisrcelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -55,11 +55,6 @@ WRITE setShowLog RESET resetShowLog NOTIFY showLogChanged) - Q_PROPERTY(QString codecLib - READ codecLib - WRITE setCodecLib - RESET resetCodecLib - NOTIFY codecLibChanged) public: MultiSrcElement(); @@ -76,7 +71,6 @@ Q_INVOKABLE AkCaps caps(int stream); Q_INVOKABLE qint64 maxPacketQueueSize() const; Q_INVOKABLE bool showLog() const; - Q_INVOKABLE QString codecLib() const; private: MultiSrcElementPrivate *d; @@ -94,7 +88,6 @@ void error(const QString &message); void maxPacketQueueSizeChanged(qint64 maxPacketQueue); void showLogChanged(bool showLog); - void codecLibChanged(const QString &codecLib); public slots: void setMedia(const QString &media); @@ -102,17 +95,12 @@ void setLoop(bool loop); void setMaxPacketQueueSize(qint64 maxPacketQueueSize); void setShowLog(bool showLog); - void setCodecLib(const QString &codecLib); void resetMedia(); void resetStreams(); void resetLoop(); void resetMaxPacketQueueSize(); void resetShowLog(); - void resetCodecLib(); bool setState(AkElement::ElementState state); - - private slots: - void codecLibUpdated(const QString &codecLib); }; #endif // MULTISRCELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelementsettings.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelementsettings.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelementsettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelementsettings.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,54 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "multisrcelementsettings.h" +#include "multisrcglobals.h" + +Q_GLOBAL_STATIC(MultiSrcGlobals, globalMultiSrc) + +MultiSrcElementSettings::MultiSrcElementSettings(QObject *parent): + QObject(parent) +{ + QObject::connect(globalMultiSrc, + &MultiSrcGlobals::codecLibChanged, + this, + &MultiSrcElementSettings::codecLibChanged); +} + +QString MultiSrcElementSettings::codecLib() const +{ + return globalMultiSrc->codecLib(); +} + +QStringList MultiSrcElementSettings::subModules() const +{ + return globalMultiSrc->subModules(); +} + +void MultiSrcElementSettings::setCodecLib(const QString &codecLib) +{ + globalMultiSrc->setCodecLib(codecLib); +} + +void MultiSrcElementSettings::resetCodecLib() +{ + globalMultiSrc->resetCodecLib(); +} + +#include "moc_multisrcelementsettings.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelementsettings.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelementsettings.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelementsettings.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcelementsettings.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,52 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef MULTISRCELEMENTSETTINGS_H +#define MULTISRCELEMENTSETTINGS_H + +#include + +class MultiSrcElementSettings: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString codecLib + READ codecLib + WRITE setCodecLib + RESET resetCodecLib + NOTIFY codecLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules + NOTIFY subModulesChanged) + + public: + MultiSrcElementSettings(QObject *parent=nullptr); + + Q_INVOKABLE QString codecLib() const; + Q_INVOKABLE QStringList subModules() const; + + signals: + void codecLibChanged(const QString &codecLib); + void subModulesChanged(const QStringList &subModules); + + public slots: + void setCodecLib(const QString &codecLib); + void resetCodecLib(); +}; + +#endif // MULTISRCELEMENTSETTINGS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcglobals.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcglobals.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcglobals.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcglobals.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,28 +21,43 @@ #include "multisrcglobals.h" +class MultiSrcGlobalsPrivate +{ + public: + QString m_codecLib; + QStringList m_preferredFramework; + + MultiSrcGlobalsPrivate(); +}; + MultiSrcGlobals::MultiSrcGlobals(QObject *parent): QObject(parent) { - this->m_preferredFramework = QStringList { - "ffmpeg", - "gstreamer" - }; - + this->d = new MultiSrcGlobalsPrivate; this->resetCodecLib(); } +MultiSrcGlobals::~MultiSrcGlobals() +{ + delete this->d; +} + QString MultiSrcGlobals::codecLib() const { - return this->m_codecLib; + return this->d->m_codecLib; +} + +QStringList MultiSrcGlobals::subModules() const +{ + return AkElement::listSubModules("MultiSrc"); } void MultiSrcGlobals::setCodecLib(const QString &codecLib) { - if (this->m_codecLib == codecLib) + if (this->d->m_codecLib == codecLib) return; - this->m_codecLib = codecLib; + this->d->m_codecLib = codecLib; emit this->codecLibChanged(codecLib); } @@ -50,15 +65,26 @@ { auto subModules = AkElement::listSubModules("MultiSrc"); - for (auto &framework: this->m_preferredFramework) + for (auto &framework: this->d->m_preferredFramework) if (subModules.contains(framework)) { this->setCodecLib(framework); return; } - if (this->m_codecLib.isEmpty() && !subModules.isEmpty()) + if (this->d->m_codecLib.isEmpty() && !subModules.isEmpty()) this->setCodecLib(subModules.first()); else this->setCodecLib(""); } + +MultiSrcGlobalsPrivate::MultiSrcGlobalsPrivate() +{ + this->m_preferredFramework = QStringList { + "ffmpeg", + "gstreamer", + "ndkmedia", + }; +} + +#include "moc_multisrcglobals.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcglobals.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcglobals.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcglobals.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/multisrcglobals.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,6 +22,8 @@ #include +class MultiSrcGlobalsPrivate; + class MultiSrcGlobals: public QObject { Q_OBJECT @@ -30,15 +32,18 @@ WRITE setCodecLib RESET resetCodecLib NOTIFY codecLibChanged) + Q_PROPERTY(QStringList subModules + READ subModules) public: MultiSrcGlobals(QObject *parent=nullptr); + ~MultiSrcGlobals(); Q_INVOKABLE QString codecLib() const; + Q_INVOKABLE QStringList subModules() const; private: - QString m_codecLib; - QStringList m_preferredFramework; + MultiSrcGlobalsPrivate *d; signals: void codecLibChanged(const QString &codecLib); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/ndkmedia.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/ndkmedia.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/ndkmedia.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/ndkmedia.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,74 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../akcommons.pri) { + include(../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +CONFIG += plugin + +HEADERS += \ + src/abstractstream.h \ + src/audiostream.h \ + src/clock.h \ + src/plugin.h \ + src/mediasourcendkmedia.h \ + src/stream.h \ + src/videostream.h \ + ../mediasource.h + +INCLUDEPATH += \ + ../../../../Lib/src \ + ../ + +LIBS += -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} +LIBS += \ + -lmediandk + +OTHER_FILES += pspec.json + +QT += qml concurrent + +SOURCES += \ + src/abstractstream.cpp \ + src/audiostream.cpp \ + src/clock.cpp \ + src/plugin.cpp \ + src/mediasourcendkmedia.cpp \ + src/videostream.cpp \ + ../mediasource.cpp + +akModule = MultiSrc +DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,3 @@ +{ + "pluginType": "Ak.SubModule" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/abstractstream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/abstractstream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/abstractstream.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/abstractstream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,393 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "abstractstream.h" +#include "clock.h" + +template +inline void waitLoop(const QFuture &loop) +{ + while (!loop.isFinished()) { + auto eventDispatcher = QThread::currentThread()->eventDispatcher(); + + if (eventDispatcher) + eventDispatcher->processEvents(QEventLoop::AllEvents); + } +} + +class AbstractStreamPrivate +{ + public: + AbstractStream *self; + AkFrac m_timeBase; + AMediaExtractor *m_mediaExtractor {nullptr}; + AMediaCodec *m_codec {nullptr}; + AMediaFormat *m_mediaFormat {nullptr}; + QThreadPool m_threadPool; + QMutex m_dataMutex; + QWaitCondition m_dataQueueNotEmpty; + QWaitCondition m_dataQueueNotFull; + QQueue m_packets; + qint64 m_packetQueueSize {-1}; + Clock *m_globalClock {nullptr}; + QFuture m_dataLoopResult; + QString m_mimeType; + qint64 m_id {-1}; + uint m_index {0}; + bool m_runDataLoop {false}; + + explicit AbstractStreamPrivate(AbstractStream *self); + void dataLoop(); +}; + +AbstractStream::AbstractStream(AMediaExtractor *mediaExtractor, + uint index, qint64 id, Clock *globalClock, + QObject *parent): + QObject(parent) +{ + this->d = new AbstractStreamPrivate(this); + this->d->m_mediaExtractor = mediaExtractor; + this->m_paused = false; + this->m_isValid = false; + this->m_clockDiff = 0; + this->m_maxData = 0; + this->d->m_index = index; + this->d->m_id = id; + + this->d->m_mediaFormat = + AMediaExtractor_getTrackFormat(this->d->m_mediaExtractor, + index); + const char *mime = nullptr; + AMediaFormat_getString(this->d->m_mediaFormat, + AMEDIAFORMAT_KEY_MIME, + &mime); + this->d->m_codec = AMediaCodec_createDecoderByType(mime); + + if (!this->d->m_codec) + return; + + if (QString(mime).startsWith("audio/")) { + this->d->m_mimeType = "audio/x-raw"; + int32_t rate = 0; + AMediaFormat_getInt32(this->d->m_mediaFormat, + AMEDIAFORMAT_KEY_SAMPLE_RATE, + &rate); + this->d->m_timeBase = AkFrac(1, rate); + } else if (QString(mime).startsWith("video/")) { + this->d->m_mimeType = "video/x-raw"; + int32_t frameRate; + AMediaFormat_getInt32(this->d->m_mediaFormat, + AMEDIAFORMAT_KEY_FRAME_RATE, + &frameRate); + this->d->m_timeBase = AkFrac(1, frameRate); + } + + this->d->m_packetQueueSize = 0; + this->d->m_globalClock = globalClock; + + this->m_isValid = true; + + if (this->d->m_threadPool.maxThreadCount() < 2) + this->d->m_threadPool.setMaxThreadCount(2); +} + +AbstractStream::~AbstractStream() +{ + if (this->d->m_codec) + AMediaCodec_delete(this->d->m_codec); + + if (this->d->m_mediaFormat) + AMediaFormat_delete(this->d->m_mediaFormat); + + delete this->d; +} + +bool AbstractStream::paused() const +{ + return this->m_paused; +} + +bool AbstractStream::isValid() const +{ + return this->m_isValid; +} + +uint AbstractStream::index() const +{ + return this->d->m_index; +} + +qint64 AbstractStream::id() const +{ + return this->d->m_id; +} + +AkFrac AbstractStream::timeBase() const +{ + return this->d->m_timeBase; +} + +QString AbstractStream::mimeType() const +{ + return this->d->m_mimeType; +} + +AMediaCodec *AbstractStream::codec() const +{ + return this->d->m_codec; +} + +AMediaFormat *AbstractStream::mediaFormat() const +{ + return this->d->m_mediaFormat; +} + +AkCaps AbstractStream::caps() const +{ + return AkCaps(); +} + +bool AbstractStream::packetEnqueue(bool eos) +{ + ssize_t timeOut = 5000; + auto bufferIndex = + AMediaCodec_dequeueInputBuffer(this->d->m_codec, timeOut); + + if (bufferIndex < 0) + return false; + + if (eos) { + AMediaCodec_queueInputBuffer(this->d->m_codec, + size_t(bufferIndex), + 0, + 0, + 0, + AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); + } else { + size_t buffersize = 0; + auto buffer = AMediaCodec_getInputBuffer(this->d->m_codec, + size_t(bufferIndex), + &buffersize); + + if (!buffer) + return false; + + auto sampleSize = + AMediaExtractor_readSampleData(this->d->m_mediaExtractor, + buffer, + buffersize); + + if (sampleSize < 1) + return false; + + auto presentationTimeUs = + AMediaExtractor_getSampleTime(this->d->m_mediaExtractor); + AMediaCodec_queueInputBuffer(this->d->m_codec, + size_t(bufferIndex), + 0, + size_t(sampleSize), + uint64_t(presentationTimeUs), + 0); + } + + return true; +} + +void AbstractStream::avPacketEnqueue(const AkPacket &packet) +{ + this->d->m_dataMutex.lock(); + + if (this->d->m_packets.size() >= this->m_maxData) + this->d->m_dataQueueNotFull.wait(&this->d->m_dataMutex); + + if (packet) + this->d->m_packets.enqueue(packet); + else + this->d->m_packets.enqueue({}); + + this->d->m_dataQueueNotEmpty.wakeAll(); + this->d->m_dataMutex.unlock(); +} + +qint64 AbstractStream::queueSize() +{ + return this->d->m_packetQueueSize; +} + +Clock *AbstractStream::globalClock() +{ + return this->d->m_globalClock; +} + +qreal AbstractStream::clockDiff() const +{ + return this->m_clockDiff; +} + +qreal &AbstractStream::clockDiff() +{ + return this->m_clockDiff; +} + +bool AbstractStream::decodeData() +{ + return false; +} + +QString AbstractStream::mimeType(AMediaExtractor *mediaExtractor, + uint index) +{ + auto format = AMediaExtractor_getTrackFormat(mediaExtractor, index); + + if (!format) + return {}; + + const char *mime = nullptr; + AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime); + auto mimeType = QString(mime).startsWith("audio/")? + "audio/x-raw": + QString(mime).startsWith("video/")? + "video/x-raw": + QString(); + AMediaFormat_delete(format); + + return mimeType; +} + +void AbstractStream::processPacket(const AkPacket &packet) +{ + Q_UNUSED(packet) +} + +AbstractStreamPrivate::AbstractStreamPrivate(AbstractStream *self): + self(self) +{ +} + +void AbstractStreamPrivate::dataLoop() +{ + if (this->m_mimeType == "audio/x-raw" + || this->m_mimeType == "video/x-raw") { + while (this->m_runDataLoop) { + this->m_dataMutex.lock(); + bool gotFrame = true; + + if (this->m_packets.isEmpty()) + gotFrame = this->m_dataQueueNotEmpty.wait(&this->m_dataMutex, + THREAD_WAIT_LIMIT); + + AkPacket packet; + + if (gotFrame) { + packet = this->m_packets.dequeue(); + + if (this->m_packets.size() < self->m_maxData) + this->m_dataQueueNotFull.wakeAll(); + } + + this->m_dataMutex.unlock(); + + if (gotFrame) { + if (packet) + self->processPacket(packet); + else { + emit self->eof(); + this->m_runDataLoop = false; + } + } + } + } +} + +void AbstractStream::setPaused(bool paused) +{ + if (this->m_paused == paused) + return; + + this->d->m_runDataLoop = !paused; + + if (paused) + this->d->m_dataLoopResult.waitForFinished(); + else + this->d->m_dataLoopResult = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &AbstractStreamPrivate::dataLoop); + + this->m_paused = paused; + emit this->pausedChanged(paused); +} + +void AbstractStream::resetPaused() +{ + this->setPaused(false); +} + +bool AbstractStream::init() +{ + if (!this->d->m_codec) + return false; + + if (AMediaCodec_configure(this->d->m_codec, + this->d->m_mediaFormat, + nullptr, + nullptr, + 0) != AMEDIA_OK) + return false; + + if (AMediaCodec_start(this->d->m_codec) != AMEDIA_OK) + return false; + + if (AMediaExtractor_selectTrack(this->d->m_mediaExtractor, + this->d->m_index) != AMEDIA_OK) + return false; + + this->m_clockDiff = 0; + this->d->m_runDataLoop = true; + this->d->m_dataLoopResult = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &AbstractStreamPrivate::dataLoop); + + return true; +} + +void AbstractStream::uninit() +{ + this->d->m_runDataLoop = false; + waitLoop(this->d->m_dataLoopResult); + + AMediaCodec_stop(this->d->m_codec); + this->d->m_packets.clear(); +} + +#include "moc_abstractstream.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/abstractstream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/abstractstream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/abstractstream.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/abstractstream.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,96 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef ABSTRACTSTREAM_H +#define ABSTRACTSTREAM_H + +#include + +class AbstractStream; +class AbstractStreamPrivate; +class AkFrac; +class AkCaps; +class AkPacket; +class Clock; +struct AMediaExtractor; +struct AMediaFormat; +struct AMediaCodec; +using AbstractStreamPtr = QSharedPointer; + +class AbstractStream: public QObject +{ + Q_OBJECT + Q_PROPERTY(bool paused + READ paused + WRITE setPaused + RESET resetPaused + NOTIFY pausedChanged) + + public: + AbstractStream(AMediaExtractor *mediaExtractor=nullptr, + uint index=0, qint64 id=-1, + Clock *globalClock=nullptr, + QObject *parent=nullptr); + virtual ~AbstractStream(); + + Q_INVOKABLE bool paused() const; + Q_INVOKABLE bool isValid() const; + Q_INVOKABLE uint index() const; + Q_INVOKABLE qint64 id() const; + Q_INVOKABLE AkFrac timeBase() const; + Q_INVOKABLE QString mimeType() const; + Q_INVOKABLE AMediaCodec *codec() const; + Q_INVOKABLE AMediaFormat *mediaFormat() const; + Q_INVOKABLE virtual AkCaps caps() const; + Q_INVOKABLE bool packetEnqueue(bool eos=false); + Q_INVOKABLE void avPacketEnqueue(const AkPacket &packet); + Q_INVOKABLE qint64 queueSize(); + Q_INVOKABLE Clock *globalClock(); + Q_INVOKABLE qreal clockDiff() const; + Q_INVOKABLE qreal &clockDiff(); + Q_INVOKABLE virtual bool decodeData(); + Q_INVOKABLE static QString mimeType(AMediaExtractor *mediaExtractor, + uint index); + + protected: + bool m_paused; + bool m_isValid; + qreal m_clockDiff; + int m_maxData; + + virtual void processPacket(const AkPacket &packet); + + private: + AbstractStreamPrivate *d; + + signals: + void pausedChanged(bool paused); + void oStream(const AkPacket &packet); + void eof(); + + public slots: + void setPaused(bool paused); + void resetPaused(); + virtual bool init(); + virtual void uninit(); + + friend class AbstractStreamPrivate; +}; + +#endif // ABSTRACTSTREAM_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/audiostream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/audiostream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/audiostream.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/audiostream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,329 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audiostream.h" +#include "clock.h" + +// No AV correction is done if too big error. +#define AV_NOSYNC_THRESHOLD 10.0 + +// Maximum audio speed change to get correct sync +#define SAMPLE_CORRECTION_PERCENT_MAX 10 + +// We use about AUDIO_DIFF_AVG_NB A-V differences to make the average +#define AUDIO_DIFF_AVG_NB 20 + +#define ENCODING_PCM_16BIT 0x2 +#define ENCODING_PCM_8BIT 0x3 +#define ENCODING_PCM_FLOAT 0x4 + +#define CHANNEL_MASK_MONO 0x2 +#define CHANNEL_MASK_FRONT_LEFT 0x4 +#define CHANNEL_MASK_FRONT_RIGHT 0x8 +#define CHANNEL_MASK_FRONT_CENTER 0x10 +#define CHANNEL_MASK_LOW_FREQUENCY 0x20 +#define CHANNEL_MASK_BACK_LEFT 0x40 +#define CHANNEL_MASK_BACK_RIGHT 0x80 +#define CHANNEL_MASK_FRONT_LEFT_OF_CENTER 0x100 +#define CHANNEL_MASK_FRONT_RIGHT_OF_CENTER 0x200 +#define CHANNEL_MASK_BACK_CENTER 0x400 +#define CHANNEL_MASK_SIDE_LEFT 0x800 +#define CHANNEL_MASK_SIDE_RIGHT 0x1000 + +using ChannelMaskToPositionMap = QMap; + +inline const ChannelMaskToPositionMap &channelMaskToPosition() +{ + static const ChannelMaskToPositionMap channelMaskToPosition { + {CHANNEL_MASK_MONO , AkAudioCaps::Position_FrontCenter }, + {CHANNEL_MASK_FRONT_LEFT , AkAudioCaps::Position_FrontLeft }, + {CHANNEL_MASK_FRONT_RIGHT , AkAudioCaps::Position_FrontRight }, + {CHANNEL_MASK_FRONT_CENTER , AkAudioCaps::Position_FrontCenter }, + {CHANNEL_MASK_LOW_FREQUENCY , AkAudioCaps::Position_LowFrequency1 }, + {CHANNEL_MASK_BACK_LEFT , AkAudioCaps::Position_BackLeft }, + {CHANNEL_MASK_BACK_RIGHT , AkAudioCaps::Position_BackRight }, + {CHANNEL_MASK_FRONT_LEFT_OF_CENTER , AkAudioCaps::Position_FrontLeftOfCenter }, + {CHANNEL_MASK_FRONT_RIGHT_OF_CENTER, AkAudioCaps::Position_FrontRightOfCenter}, + {CHANNEL_MASK_BACK_CENTER , AkAudioCaps::Position_BackCenter }, + {CHANNEL_MASK_SIDE_LEFT , AkAudioCaps::Position_SideLeft }, + {CHANNEL_MASK_SIDE_RIGHT , AkAudioCaps::Position_SideRight }, + }; + + return channelMaskToPosition; +} + +class AudioStreamPrivate +{ + public: + AudioStream *self; + AkElementPtr m_audioConvert; + qreal audioDiffCum {0.0}; // used for AV difference average computation + qreal audioDiffAvgCoef {exp(log(0.01) / AUDIO_DIFF_AVG_NB)}; + int audioDiffAvgCount {0}; + + explicit AudioStreamPrivate(AudioStream *self); + AkPacket readPacket(size_t bufferIndex, + const AMediaCodecBufferInfo &info); + AkAudioPacket convert(const AkAudioPacket &packet); +}; + +AudioStream::AudioStream(AMediaExtractor *mediaExtractor, + uint index, qint64 id, Clock *globalClock, + QObject *parent): + AbstractStream(mediaExtractor, index, id, globalClock, parent) +{ + this->d = new AudioStreamPrivate(this); + this->m_maxData = 9; + this->d->m_audioConvert = AkElement::create("ACapsConvert"); +} + +AudioStream::~AudioStream() +{ + delete this->d; +} + +AkCaps AudioStream::caps() const +{ + AkAudioCaps::SampleFormat sampleFormat = AkAudioCaps::SampleFormat_s16; +#if __ANDROID_API__ >= 28 + int32_t pcmEncoding = 0; + + if (AMediaFormat_getInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_PCM_ENCODING, + &pcmEncoding)) + sampleFormat = AudioStream::sampleFormatFromEncoding(pcmEncoding); +#endif + AkAudioCaps::ChannelLayout layout = AkAudioCaps::Layout_none; + int32_t channelMask = 0; + + if (AMediaFormat_getInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_CHANNEL_MASK, + &channelMask)) { + layout = AudioStream::layoutFromChannelMask(channelMask); + } else { + int32_t channels = 0; + AMediaFormat_getInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_CHANNEL_COUNT, + &channels); + layout = AkAudioCaps::defaultChannelLayout(channels); + } + + int32_t rate = 0; + AMediaFormat_getInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_SAMPLE_RATE, + &rate); + + return AkAudioCaps(sampleFormat, layout, rate); +} + +AkAudioCaps::SampleFormat AudioStream::sampleFormatFromEncoding(int32_t encoding) +{ + static const QMap sampleFormatFromEncoding { + {ENCODING_PCM_8BIT , AkAudioCaps::SampleFormat_u8 }, + {ENCODING_PCM_16BIT, AkAudioCaps::SampleFormat_s16}, + {ENCODING_PCM_FLOAT, AkAudioCaps::SampleFormat_flt}, + }; + + return sampleFormatFromEncoding.value(encoding); +} + +AkAudioCaps::ChannelLayout AudioStream::layoutFromChannelMask(int32_t channelMask) +{ + auto &channelMaskToPositionMap = channelMaskToPosition(); + QVector positions; + + for (auto it = channelMaskToPositionMap.constBegin(); + it != channelMaskToPositionMap.constEnd(); + it++) + if (channelMask & it.key()) + positions << it.value(); + + return AkAudioCaps::channelLayoutFromPositions(positions); +} + +bool AudioStream::decodeData() +{ + if (!this->isValid()) + return false; + + AMediaCodecBufferInfo info; + memset(&info, 0, sizeof(AMediaCodecBufferInfo)); + ssize_t timeOut = 5000; + auto bufferIndex = + AMediaCodec_dequeueOutputBuffer(this->codec(), &info, timeOut); + + if (bufferIndex == AMEDIACODEC_INFO_TRY_AGAIN_LATER) + return true; + else if (bufferIndex >= 0) { + auto packet = this->d->readPacket(size_t(bufferIndex), info); + + if (packet) + this->avPacketEnqueue(packet); + + AMediaCodec_releaseOutputBuffer(this->codec(), + size_t(bufferIndex), + info.size != 0); + } + + if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { + this->avPacketEnqueue({}); + + return false; + } + + return true; +} + +void AudioStream::processPacket(const AkPacket &packet) +{ + auto oPacket = this->d->convert(packet); + emit this->oStream(oPacket); +} + +AudioStreamPrivate::AudioStreamPrivate(AudioStream *self): + self(self) +{ +} + +AkPacket AudioStreamPrivate::readPacket(size_t bufferIndex, + const AMediaCodecBufferInfo &info) +{ + auto format = AMediaCodec_getOutputFormat(self->codec()); + AkAudioCaps::SampleFormat sampleFormat = AkAudioCaps::SampleFormat_s16; +#if __ANDROID_API__ >= 28 + int32_t pcmEncoding = 0; + + if (AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_PCM_ENCODING, + &pcmEncoding)) + sampleFormat = AudioStream::sampleFormatFromEncoding(pcmEncoding); +#endif + AkAudioCaps::ChannelLayout layout = AkAudioCaps::Layout_none; + int32_t channelMask = 0; + + if (AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_CHANNEL_MASK, + &channelMask)) { + layout = AudioStream::layoutFromChannelMask(channelMask); + } else { + int32_t channels = 0; + AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_CHANNEL_COUNT, + &channels); + layout = AkAudioCaps::defaultChannelLayout(channels); + } + + int32_t rate = 0; + AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_SAMPLE_RATE, + &rate); + + AMediaFormat_delete(format); + + size_t bufferSize = 0; + auto buffer = AMediaCodec_getOutputBuffer(self->codec(), + size_t(bufferIndex), + &bufferSize); + bufferSize = qMin(bufferSize, size_t(info.size)); + QByteArray oBuffer(int(bufferSize), Qt::Uninitialized); + memcpy(oBuffer.data(), buffer + info.offset, bufferSize); + + AkAudioPacket packet; + packet.caps() = {sampleFormat, + layout, + rate, + 8 + * int(bufferSize) + / (AkAudioCaps::channelCount(layout) + * AkAudioCaps::bitsPerSample(sampleFormat))}; + packet.buffer() = oBuffer; + packet.pts() = info.presentationTimeUs; + packet.timeBase() = AkFrac(1, 1e6); + packet.index() = int(self->index()); + packet.id() = self->id(); + + return packet; +} + +AkAudioPacket AudioStreamPrivate::convert(const AkAudioPacket &packet) +{ + if (this->m_audioConvert->state() != AkElement::ElementStatePlaying) { + this->m_audioConvert->setProperty("caps", + QVariant::fromValue(packet.caps())); + this->m_audioConvert->setState(AkElement::ElementStatePlaying); + } + + AkAudioPacket audioPacket = packet; + + // Synchronize audio + qreal pts = packet.pts() * packet.timeBase().value(); + qreal diff = pts - self->globalClock()->clock(); + int wantedSamples = audioPacket.caps().samples(); + + if (!qIsNaN(diff) && qAbs(diff) < AV_NOSYNC_THRESHOLD) { + this->audioDiffCum = diff + this->audioDiffAvgCoef * this->audioDiffCum; + + if (this->audioDiffAvgCount < AUDIO_DIFF_AVG_NB) { + // not enough measures to have a correct estimate + this->audioDiffAvgCount++; + } else { + // estimate the A-V difference + qreal avgDiff = this->audioDiffCum * (1.0 - this->audioDiffAvgCoef); + + // since we do not have a precise anough audio fifo fullness, + // we correct audio sync only if larger than this threshold + qreal diffThreshold = 2.0 * audioPacket.caps().samples() / audioPacket.caps().rate(); + + if (qAbs(avgDiff) >= diffThreshold) { + wantedSamples = audioPacket.caps().samples() + int(diff * audioPacket.caps().rate()); + int minSamples = audioPacket.caps().samples() * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100; + int maxSamples = audioPacket.caps().samples() * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100; + wantedSamples = qBound(minSamples, wantedSamples, maxSamples); + audioPacket = audioPacket.scale(wantedSamples); + } + } + } else { + // Too big difference: may be initial PTS errors, so + // reset A-V filter + this->audioDiffAvgCount = 0; + this->audioDiffCum = 0.0; + } + + if (qAbs(diff) >= AV_NOSYNC_THRESHOLD) + self->globalClock()->setClock(pts); + + self->clockDiff() = diff; + + return this->m_audioConvert->iStream(packet); +} + +#include "moc_audiostream.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/audiostream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/audiostream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/audiostream.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/audiostream.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,52 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef AUDIOSTREAM_H +#define AUDIOSTREAM_H + +#include + +#include "abstractstream.h" + +class AudioStreamPrivate; + +class AudioStream: public AbstractStream +{ + Q_OBJECT + + public: + AudioStream(AMediaExtractor *mediaExtractor=nullptr, + uint index=0, qint64 id=-1, + Clock *globalClock=nullptr, + QObject *parent=nullptr); + ~AudioStream(); + + Q_INVOKABLE AkCaps caps() const; + Q_INVOKABLE static AkAudioCaps::SampleFormat sampleFormatFromEncoding(int32_t encoding); + Q_INVOKABLE static AkAudioCaps::ChannelLayout layoutFromChannelMask(int32_t channelMask); + Q_INVOKABLE bool decodeData(); + + protected: + void processPacket(const AkPacket &packet); + + private: + AudioStreamPrivate *d; +}; + +#endif // AUDIOSTREAM_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/clock.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/clock.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/clock.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/clock.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,67 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include + +#include "clock.h" + +class ClockPrivate +{ + public: + QReadWriteLock m_mutex; + qreal m_timeDrift {0.0}; +}; + +Clock::Clock(QObject *parent): QObject(parent) +{ + this->d = new ClockPrivate; +} + +Clock::~Clock() +{ + delete this->d; +} + +qreal Clock::clock() +{ + this->d->m_mutex.lockForRead(); + qreal clock = QDateTime::currentMSecsSinceEpoch() * 1.0e-3 + - this->d->m_timeDrift; + this->d->m_mutex.unlock(); + + return clock; +} + +void Clock::setClock(qreal clock) +{ + this->d->m_mutex.lockForWrite(); + this->d->m_timeDrift = QDateTime::currentMSecsSinceEpoch() * 1.0e-3 + - clock; + this->d->m_mutex.unlock(); +} + +void Clock::resetClock() +{ + this->d->m_mutex.lockForWrite(); + this->d->m_timeDrift = 0.0; + this->d->m_mutex.unlock(); +} + +#include "moc_clock.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/clock.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/clock.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/clock.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/clock.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,51 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef CLOCK_H +#define CLOCK_H + +#include + +#define THREAD_WAIT_LIMIT 500 + +class ClockPrivate; + +class Clock: public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal clock + READ clock + WRITE setClock + RESET resetClock) + + public: + Clock(QObject *parent=nullptr); + ~Clock(); + + Q_INVOKABLE qreal clock(); + + private: + ClockPrivate *d; + + public slots: + void setClock(qreal clock); + void resetClock(); +}; + +#endif // CLOCK_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/mediasourcendkmedia.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/mediasourcendkmedia.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/mediasourcendkmedia.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/mediasourcendkmedia.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,589 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mediasourcendkmedia.h" +#include "audiostream.h" +#include "clock.h" +#include "stream.h" +#include "videostream.h" + +using MediaExtractorPtr = QSharedPointer; + +class MediaSourceNDKMediaPrivate +{ + public: + MediaSourceNDKMedia *self; + QString m_media; + QList m_streams; + qint64 m_maxPacketQueueSize {15 * 1024 * 1024}; + MediaExtractorPtr m_mediaExtractor; + QThreadPool m_threadPool; + QVector m_streamInfo; + QMap m_streamsMap; + Clock m_globalClock; + qreal m_curClockTime {0.0}; + QFuture m_multimediaLoopResult; + AkElement::ElementState m_curState {AkElement::ElementStateNull}; + bool m_paused {false}; + bool m_loop {false}; + bool m_run {false}; + bool m_showLog {false}; + + explicit MediaSourceNDKMediaPrivate(MediaSourceNDKMedia *self); + AbstractStreamPtr createStream(AMediaExtractor *mediaExtractor, + int index); + void multimediaLoop(); + static AkCaps capsFromMediaFormat(AMediaFormat *mediaFormat); + void updateStreams(); +}; + +MediaSourceNDKMedia::MediaSourceNDKMedia(QObject *parent): + MediaSource(parent) +{ + this->d = new MediaSourceNDKMediaPrivate(this); + + if (this->d->m_threadPool.maxThreadCount() < 2) + this->d->m_threadPool.setMaxThreadCount(2); +} + +MediaSourceNDKMedia::~MediaSourceNDKMedia() +{ + this->setState(AkElement::ElementStateNull); + delete this->d; +} + +QStringList MediaSourceNDKMedia::medias() const +{ + QStringList medias; + + if (!this->d->m_media.isEmpty()) + medias << this->d->m_media; + + return medias; +} + +QString MediaSourceNDKMedia::media() const +{ + return this->d->m_media; +} + +QList MediaSourceNDKMedia::streams() const +{ + return this->d->m_streams; +} + +QList MediaSourceNDKMedia::listTracks(const QString &mimeType) +{ + QList tracks; + int i = 0; + + for (auto &streamInfo: this->d->m_streamInfo) { + if (mimeType.isEmpty() || streamInfo.caps.mimeType() == mimeType) + tracks << i; + + i++; + } + + return tracks; +} + +QString MediaSourceNDKMedia::streamLanguage(int stream) +{ + return this->d->m_streamInfo.value(stream, Stream()).language; +} + +bool MediaSourceNDKMedia::loop() const +{ + return this->d->m_loop; +} + +int MediaSourceNDKMedia::defaultStream(const QString &mimeType) +{ + int defaultStream = -1; + int i = 0; + + for (auto &streamInfo: this->d->m_streamInfo) { + if (streamInfo.caps.mimeType() == mimeType) { + if (streamInfo.defaultStream) + return i; + + if (defaultStream < 0) + defaultStream = i; + } + + i++; + } + + return defaultStream; +} + +QString MediaSourceNDKMedia::description(const QString &media) const +{ + if (this->d->m_media != media) + return QString(); + + return QFileInfo(media).baseName(); +} + +AkCaps MediaSourceNDKMedia::caps(int stream) +{ + return this->d->m_streamInfo.value(stream, Stream()).caps; +} + +qint64 MediaSourceNDKMedia::maxPacketQueueSize() const +{ + return this->d->m_maxPacketQueueSize; +} + +bool MediaSourceNDKMedia::showLog() const +{ + return this->d->m_showLog; +} + +void MediaSourceNDKMedia::setMedia(const QString &media) +{ + if (media == this->d->m_media) + return; + + bool isRunning = this->d->m_run; + this->setState(AkElement::ElementStateNull); + this->d->m_media = media; + this->d->updateStreams(); + + if (isRunning && !this->d->m_media.isEmpty()) + this->setState(AkElement::ElementStatePlaying); + + emit this->mediaChanged(media); + emit this->mediasChanged(this->medias()); +} + +void MediaSourceNDKMedia::setStreams(const QList &streams) +{ + if (this->d->m_streams == streams) + return; + + this->d->m_streams = streams; + emit this->streamsChanged(streams); +} + +void MediaSourceNDKMedia::setMaxPacketQueueSize(qint64 maxPacketQueueSize) +{ + if (this->d->m_maxPacketQueueSize == maxPacketQueueSize) + return; + + this->d->m_maxPacketQueueSize = maxPacketQueueSize; + emit this->maxPacketQueueSizeChanged(maxPacketQueueSize); +} + +void MediaSourceNDKMedia::setShowLog(bool showLog) +{ + if (this->d->m_showLog == showLog) + return; + + this->d->m_showLog = showLog; + emit this->showLogChanged(showLog); +} + +void MediaSourceNDKMedia::setLoop(bool loop) +{ + if (this->d->m_loop == loop) + return; + + this->d->m_loop = loop; + emit this->loopChanged(loop); +} + +void MediaSourceNDKMedia::resetMedia() +{ + this->setMedia(""); +} + +void MediaSourceNDKMedia::resetStreams() +{ + if (this->d->m_streams.isEmpty()) + return; + + this->d->m_streams.clear(); + emit this->streamsChanged(this->d->m_streams); +} + +void MediaSourceNDKMedia::resetMaxPacketQueueSize() +{ + this->setMaxPacketQueueSize(15 * 1024 * 1024); +} + +void MediaSourceNDKMedia::resetShowLog() +{ + this->setShowLog(false); +} + +void MediaSourceNDKMedia::resetLoop() +{ + this->setLoop(false); +} + +bool MediaSourceNDKMedia::setState(AkElement::ElementState state) +{ + switch (this->d->m_curState) { + case AkElement::ElementStateNull: { + if (state == AkElement::ElementStatePaused + || state == AkElement::ElementStatePlaying) { + this->d->m_mediaExtractor = + MediaExtractorPtr(AMediaExtractor_new(), + [] (AMediaExtractor *mediaExtractor) { + AMediaExtractor_delete(mediaExtractor); + }); + + if (AMediaExtractor_setDataSource(this->d->m_mediaExtractor.data(), + this->d->m_media.toStdString().c_str()) != AMEDIA_OK) { + return false; + } + + QList filterStreams; + + if (this->d->m_streams.isEmpty()) + filterStreams << this->defaultStream("audio/x-raw") + << this->defaultStream("video/x-raw"); + else + filterStreams = this->d->m_streams; + + for (auto &i: filterStreams) { + auto stream = + this->d->createStream(this->d->m_mediaExtractor.data(), + i); + + if (stream) { + this->d->m_streamsMap[i] = stream; + + QObject::connect(stream.data(), + SIGNAL(oStream(AkPacket)), + this, + SIGNAL(oStream(AkPacket)), + Qt::DirectConnection); + QObject::connect(stream.data(), + SIGNAL(oStream(AkPacket)), + this, + SLOT(log())); + QObject::connect(stream.data(), + SIGNAL(eof()), + this, + SLOT(doLoop())); + + stream->init(); + } + } + + if (state == AkElement::ElementStatePaused) + this->d->m_curClockTime = 0.; + + this->d->m_globalClock.setClock(0.); + this->d->m_run = true; + this->d->m_paused = state == AkElement::ElementStatePaused; + this->d->m_multimediaLoopResult = + QtConcurrent::run(&this->d->m_threadPool, + this->d, + &MediaSourceNDKMediaPrivate::multimediaLoop); + this->d->m_curState = state; + + return true; + } + + break; + } + case AkElement::ElementStatePaused: { + switch (state) { + case AkElement::ElementStateNull: { + this->d->m_globalClock.setClock(this->d->m_curClockTime); + this->d->m_run = false; + this->d->m_threadPool.waitForDone(); + this->d->m_streamsMap.clear(); + this->d->m_curState = state; + + return true; + } + case AkElement::ElementStatePlaying: { + this->d->m_globalClock.setClock(this->d->m_curClockTime); + this->d->m_paused = false; + this->d->m_curState = state; + + return true; + } + case AkElement::ElementStatePaused: + break; + } + + break; + } + case AkElement::ElementStatePlaying: { + switch (state) { + case AkElement::ElementStateNull: { + this->d->m_run = false; + this->d->m_multimediaLoopResult.waitForFinished(); + this->d->m_streamsMap.clear(); + this->d->m_curState = state; + + return true; + } + case AkElement::ElementStatePaused: { + this->d->m_curClockTime = this->d->m_globalClock.clock(); + this->d->m_paused = true; + this->d->m_curState = state; + + break; + } + case AkElement::ElementStatePlaying: + break; + } + + break; + } + } + + return false; +} + +void MediaSourceNDKMedia::doLoop() +{ + this->setState(AkElement::ElementStateNull); + this->setState(AkElement::ElementStatePlaying); +} + +void MediaSourceNDKMedia::packetConsumed() +{ +} + +void MediaSourceNDKMedia::log() +{ + if (!this->d->m_showLog) + return; + + AbstractStreamPtr audioStream; + AbstractStreamPtr videoStream; + + for (auto &stream: this->d->m_streamsMap) { + auto mimeType = stream->mimeType(); + + if (mimeType == "audio/x-raw" && !audioStream) + audioStream = stream; + + if (mimeType == "video/x-raw" && !videoStream) + videoStream = stream; + + if (audioStream && videoStream) + break; + } + + QString diffType; + qreal diff; + + if (audioStream && videoStream) { + diffType = "A-V"; + diff = audioStream->clockDiff() - videoStream->clockDiff(); + } else if (audioStream) { + diffType = "M-A"; + diff = -audioStream->clockDiff(); + } else if (videoStream) { + diffType = "M-V"; + diff = -videoStream->clockDiff(); + } else + return; + + QString logFmt("%1 %2: %3"); + QString log = logFmt.arg(this->d->m_globalClock.clock(), 7, 'f', 2) + .arg(diffType) + .arg(diff, 7, 'f', 3); + + qDebug() << log.toStdString().c_str(); +} + +MediaSourceNDKMediaPrivate::MediaSourceNDKMediaPrivate(MediaSourceNDKMedia *self): + self(self) +{ + +} + +AbstractStreamPtr MediaSourceNDKMediaPrivate::createStream(AMediaExtractor *mediaExtractor, + int index) +{ + auto type = AbstractStream::mimeType(mediaExtractor, uint(index)); + AbstractStreamPtr stream; + auto id = Ak::id(); + + if (type == "video/x-raw") + stream = AbstractStreamPtr(new VideoStream(mediaExtractor, + uint(index), + id, + &this->m_globalClock)); + else if (type == "audio/x-raw") + stream = AbstractStreamPtr(new AudioStream(mediaExtractor, + uint(index), + id, + &this->m_globalClock)); + else + stream = AbstractStreamPtr(new AbstractStream(mediaExtractor, + uint(index), + id, + &this->m_globalClock)); + + return stream; +} + +void MediaSourceNDKMediaPrivate::multimediaLoop() +{ + bool eos = false; + + while (this->m_run) { + if (this->m_paused) { + QThread::msleep(500); + + continue; + } + + if (!eos) { + auto streamIndex = + AMediaExtractor_getSampleTrackIndex(this->m_mediaExtractor.data()); + + if (streamIndex < 0) { + for (auto &stream: this->m_streamsMap) + stream->packetEnqueue(true); + } else { + if (this->m_streamsMap.contains(streamIndex) + && (this->m_streams.isEmpty() + || this->m_streams.contains(streamIndex))) { + this->m_streamsMap[streamIndex]->packetEnqueue(); + } + } + } + + for (auto &stream: this->m_streamsMap) + stream->decodeData(); + + if (!eos) + eos = !AMediaExtractor_advance(this->m_mediaExtractor.data()); + } + + for (auto &stream: this->m_streamsMap) + stream->uninit(); + + this->m_streamsMap.clear(); +} + +AkCaps MediaSourceNDKMediaPrivate::capsFromMediaFormat(AMediaFormat *mediaFormat) +{ + AkCaps caps; + const char *mime = nullptr; + AMediaFormat_getString(mediaFormat, AMEDIAFORMAT_KEY_MIME, &mime); + + if (QString(mime).startsWith("audio/")) { + AkAudioCaps::SampleFormat sampleFormat = AkAudioCaps::SampleFormat_s16; +#if __ANDROID_API__ >= 28 + int32_t pcmEncoding = 0; + + if (AMediaFormat_getInt32(mediaFormat, + AMEDIAFORMAT_KEY_PCM_ENCODING, + &pcmEncoding)) + sampleFormat = AudioStream::sampleFormatFromEncoding(pcmEncoding); +#endif + AkAudioCaps::ChannelLayout layout = AkAudioCaps::Layout_none; + int32_t channelMask = 0; + + if (AMediaFormat_getInt32(mediaFormat, + AMEDIAFORMAT_KEY_CHANNEL_MASK, + &channelMask)) { + layout = AudioStream::layoutFromChannelMask(channelMask); + } else { + int32_t channels = 0; + AMediaFormat_getInt32(mediaFormat, + AMEDIAFORMAT_KEY_CHANNEL_COUNT, + &channels); + layout = AkAudioCaps::defaultChannelLayout(channels); + } + + int32_t rate = 0; + AMediaFormat_getInt32(mediaFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &rate); + caps = AkAudioCaps(sampleFormat, layout, rate); + } else if (QString(mime).startsWith("video/")) { + int32_t width = 0; + AMediaFormat_getInt32(mediaFormat, AMEDIAFORMAT_KEY_WIDTH, &width); + int32_t height = 0; + AMediaFormat_getInt32(mediaFormat, AMEDIAFORMAT_KEY_HEIGHT, &height); + int32_t frameRate; + AMediaFormat_getInt32(mediaFormat, + AMEDIAFORMAT_KEY_FRAME_RATE, + &frameRate); + caps = AkVideoCaps(AkVideoCaps::Format_rgb24, + width, + height, + AkFrac(frameRate, 1)); + } + + return caps; +} + +void MediaSourceNDKMediaPrivate::updateStreams() +{ + this->m_streamInfo.clear(); + + if (this->m_media.isEmpty()) + return; + + auto extractor = AMediaExtractor_new(); + + if (AMediaExtractor_setDataSource(extractor, + this->m_media.toStdString().c_str()) == AMEDIA_OK) { + for (size_t i = 0; i < AMediaExtractor_getTrackCount(extractor); i++) { + auto format = AMediaExtractor_getTrackFormat(extractor, i); + auto caps = MediaSourceNDKMediaPrivate::capsFromMediaFormat(format); + + if (caps) { + int32_t isDefault = false; + AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_IS_DEFAULT, + &isDefault); + const char *language = nullptr; + AMediaFormat_getString(format, + AMEDIAFORMAT_KEY_LANGUAGE, + &language); + this->m_streamInfo << Stream(caps, + language? + QString(language): QString(), + isDefault); + } + + AMediaFormat_delete(format); + } + } + + AMediaExtractor_delete(extractor); +} + +#include "moc_mediasourcendkmedia.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/mediasourcendkmedia.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/mediasourcendkmedia.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/mediasourcendkmedia.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/mediasourcendkmedia.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,90 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef MEDIASOURCENDKMEDIA_H +#define MEDIASOURCENDKMEDIA_H + +#include "mediasource.h" + +class MediaSourceNDKMediaPrivate; + +class MediaSourceNDKMedia: public MediaSource +{ + Q_OBJECT + Q_PROPERTY(qint64 maxPacketQueueSize + READ maxPacketQueueSize + WRITE setMaxPacketQueueSize + RESET resetMaxPacketQueueSize + NOTIFY maxPacketQueueSizeChanged) + Q_PROPERTY(bool showLog + READ showLog + WRITE setShowLog + RESET resetShowLog + NOTIFY showLogChanged) + + public: + MediaSourceNDKMedia(QObject *parent=nullptr); + ~MediaSourceNDKMedia(); + + Q_INVOKABLE QStringList medias() const; + Q_INVOKABLE QString media() const; + Q_INVOKABLE QList streams() const; + Q_INVOKABLE QList listTracks(const QString &mimeType); + Q_INVOKABLE QString streamLanguage(int stream); + Q_INVOKABLE bool loop() const; + + Q_INVOKABLE int defaultStream(const QString &mimeType); + Q_INVOKABLE QString description(const QString &media) const; + Q_INVOKABLE AkCaps caps(int stream); + Q_INVOKABLE qint64 maxPacketQueueSize() const; + Q_INVOKABLE bool showLog() const; + + private: + MediaSourceNDKMediaPrivate *d; + + signals: + void oStream(const AkPacket &packet); + void error(const QString &message); + void maxPacketQueueSizeChanged(qint64 maxPacketQueue); + void showLogChanged(bool showLog); + void loopChanged(bool loop); + void mediasChanged(const QStringList &medias); + void mediaChanged(const QString &media); + void streamsChanged(const QList &streams); + + public slots: + void setMedia(const QString &media); + void setStreams(const QList &streams); + void setMaxPacketQueueSize(qint64 maxPacketQueueSize); + void setShowLog(bool showLog); + void setLoop(bool loop); + void resetMedia(); + void resetStreams(); + void resetMaxPacketQueueSize(); + void resetShowLog(); + void resetLoop(); + bool setState(AkElement::ElementState state); + + private slots: + void doLoop(); + void packetConsumed(); + void log(); +}; + +#endif // MEDIASOURCENDKMEDIA_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "mediasourcendkmedia.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new MediaSourceNDKMedia(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return QStringList(); +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/stream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/stream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/stream.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/stream.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,47 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef STREAM_H +#define STREAM_H + +#include + +class Stream +{ + public: + Stream() + { + } + + Stream(const AkCaps &caps, + const QString &language, + bool defaultStream): + caps(caps), + language(language), + defaultStream(defaultStream) + { + } + + AkCaps caps; + QString language; + bool defaultStream; +}; + +#endif // STREAM_H + diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/videostream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/videostream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/videostream.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/videostream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,332 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "videostream.h" +#include "clock.h" + +// no AV sync correction is done if below the minimum AV sync threshold +#define AV_SYNC_THRESHOLD_MIN 0.04 + +// AV sync correction is done if above the maximum AV sync threshold +#define AV_SYNC_THRESHOLD_MAX 0.1 + +// If a frame duration is longer than this, it will not be duplicated to compensate AV sync +#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1 + +// no AV correction is done if too big error +#define AV_NOSYNC_THRESHOLD 10.0 + +#define COLOR_FormatMonochrome 1 +#define COLOR_Format8bitRGB332 2 +#define COLOR_Format12bitRGB444 3 +#define COLOR_Format16bitARGB4444 4 +#define COLOR_Format16bitARGB1555 5 +#define COLOR_Format16bitRGB565 6 +#define COLOR_Format16bitBGR565 7 +#define COLOR_Format18bitRGB666 8 +#define COLOR_Format18bitARGB1665 9 +#define COLOR_Format19bitARGB1666 10 +#define COLOR_Format24bitRGB888 11 +#define COLOR_Format24bitBGR888 12 +#define COLOR_Format24bitARGB1887 13 +#define COLOR_Format25bitARGB1888 14 +#define COLOR_Format32bitBGRA8888 15 +#define COLOR_Format32bitARGB8888 16 +#define COLOR_FormatYUV411Planar 17 +#define COLOR_FormatYUV411PackedPlanar 18 +#define COLOR_FormatYUV420Planar 19 +#define COLOR_FormatYUV420PackedPlanar 20 +#define COLOR_FormatYUV420SemiPlanar 21 +#define COLOR_FormatYUV422Planar 22 +#define COLOR_FormatYUV422PackedPlanar 23 +#define COLOR_FormatYUV422SemiPlanar 24 +#define COLOR_FormatYCbYCr 25 +#define COLOR_FormatYCrYCb 26 +#define COLOR_FormatCbYCrY 27 +#define COLOR_FormatCrYCbY 28 +#define COLOR_FormatYUV444Interleaved 29 +#define COLOR_FormatRawBayer8bit 30 +#define COLOR_FormatRawBayer10bit 31 +#define COLOR_FormatRawBayer8bitcompressed 32 +#define COLOR_FormatL2 33 +#define COLOR_FormatL4 34 +#define COLOR_FormatL8 35 +#define COLOR_FormatL16 36 +#define COLOR_FormatL24 37 +#define COLOR_FormatL32 38 +#define COLOR_FormatYUV420PackedSemiPlanar 39 +#define COLOR_FormatYUV422PackedSemiPlanar 40 +#define COLOR_Format18BitBGR666 41 +#define COLOR_Format24BitARGB6666 42 +#define COLOR_Format24BitABGR6666 43 +#define COLOR_TI_FormatYUV420PackedSemiPlanar 0x7f000100 +#define COLOR_FormatSurface 0x7f000789 +#define COLOR_Format32bitABGR8888 0x7f00a000 +#define COLOR_FormatYUV420Flexible 0x7f420888 +#define COLOR_FormatYUV422Flexible 0x7f422888 +#define COLOR_FormatYUV444Flexible 0x7f444888 +#define COLOR_FormatRGBFlexible 0x7f36b888 +#define COLOR_FormatRGBAFlexible 0x7f36a888 +#define COLOR_QCOM_FormatYUV420SemiPlanar 0x7fa30c00 + +using ImageFormatToPixelFormatMap = QMap; + +inline const ImageFormatToPixelFormatMap &imageFormatToPixelFormat() +{ + static const ImageFormatToPixelFormatMap imgFmtToPixFmt { + {COLOR_FormatMonochrome , AkVideoCaps::Format_monob }, + {COLOR_Format8bitRGB332 , AkVideoCaps::Format_rgb8 }, + {COLOR_Format12bitRGB444 , AkVideoCaps::Format_rgb444le }, + {COLOR_Format16bitARGB4444 , AkVideoCaps::Format_argb444le }, + {COLOR_Format16bitARGB1555 , AkVideoCaps::Format_argb555le }, + {COLOR_Format16bitRGB565 , AkVideoCaps::Format_rgb565le }, + {COLOR_Format16bitBGR565 , AkVideoCaps::Format_bgr565le }, + {COLOR_Format18bitRGB666 , AkVideoCaps::Format_rgb666 }, + {COLOR_Format18bitARGB1665 , AkVideoCaps::Format_argb1665 }, + {COLOR_Format19bitARGB1666 , AkVideoCaps::Format_argb1666 }, + {COLOR_Format24bitRGB888 , AkVideoCaps::Format_rgb24 }, + {COLOR_Format24bitBGR888 , AkVideoCaps::Format_bgr24 }, + {COLOR_Format24bitARGB1887 , AkVideoCaps::Format_argb1887 }, + {COLOR_Format25bitARGB1888 , AkVideoCaps::Format_bgra1888 }, + {COLOR_Format32bitBGRA8888 , AkVideoCaps::Format_bgra }, + {COLOR_Format32bitARGB8888 , AkVideoCaps::Format_argb }, + {COLOR_FormatYUV411Planar , AkVideoCaps::Format_yuv411p }, + {COLOR_FormatYUV411PackedPlanar , AkVideoCaps::Format_yuv411p }, + {COLOR_FormatYUV420Planar , AkVideoCaps::Format_yuv420p }, + {COLOR_FormatYUV420PackedPlanar , AkVideoCaps::Format_yuv420p }, + {COLOR_FormatYUV420SemiPlanar , AkVideoCaps::Format_yuv420p }, + {COLOR_FormatYUV422Planar , AkVideoCaps::Format_yuv422p }, + {COLOR_FormatYUV422PackedPlanar , AkVideoCaps::Format_yuv422p }, + {COLOR_FormatYUV422SemiPlanar , AkVideoCaps::Format_yuv422p }, + {COLOR_FormatYCbYCr , AkVideoCaps::Format_yuyv422 }, + {COLOR_FormatYCrYCb , AkVideoCaps::Format_yvyu422 }, + {COLOR_FormatCbYCrY , AkVideoCaps::Format_uyvy422 }, + {COLOR_FormatCrYCbY , AkVideoCaps::Format_vyuy422 }, + {COLOR_FormatYUV444Interleaved , AkVideoCaps::Format_yuv444 }, + {COLOR_FormatRawBayer8bit , AkVideoCaps::Format_bayer_rggb8}, +// {COLOR_FormatRawBayer10bit , AkVideoCaps::Format_ }, +// {COLOR_FormatRawBayer8bitcompressed , AkVideoCaps::Format_ }, + {COLOR_FormatL2 , AkVideoCaps::Format_gray2 }, + {COLOR_FormatL4 , AkVideoCaps::Format_gray4 }, + {COLOR_FormatL8 , AkVideoCaps::Format_gray }, + {COLOR_FormatL16 , AkVideoCaps::Format_gray16le }, + {COLOR_FormatL24 , AkVideoCaps::Format_gray24 }, + {COLOR_FormatL32 , AkVideoCaps::Format_gray32 }, + {COLOR_FormatYUV420PackedSemiPlanar , AkVideoCaps::Format_yuv420p }, + {COLOR_FormatYUV422PackedSemiPlanar , AkVideoCaps::Format_yuv422p }, + {COLOR_Format18BitBGR666 , AkVideoCaps::Format_bgr666 }, + {COLOR_Format24BitARGB6666 , AkVideoCaps::Format_argb6666 }, + {COLOR_Format24BitABGR6666 , AkVideoCaps::Format_abgr6666 }, +// {COLOR_TI_FormatYUV420PackedSemiPlanar, AkVideoCaps::Format_ }, +// {COLOR_FormatSurface , AkVideoCaps::Format_ }, + {COLOR_Format32bitABGR8888 , AkVideoCaps::Format_abgr }, +// {COLOR_FormatYUV420Flexible , AkVideoCaps::Format_ }, +// {COLOR_FormatYUV422Flexible , AkVideoCaps::Format_ }, +// {COLOR_FormatYUV444Flexible , AkVideoCaps::Format_ }, + {COLOR_FormatRGBFlexible , AkVideoCaps::Format_rgbp }, + {COLOR_FormatRGBAFlexible , AkVideoCaps::Format_rgbap }, +// {COLOR_QCOM_FormatYUV420SemiPlanar , AkVideoCaps::Format_ }, + }; + + return imgFmtToPixFmt; +} + +class VideoStreamPrivate +{ + public: + VideoStream *self; + qreal m_lastPts {0.0}; + + explicit VideoStreamPrivate(VideoStream *self); + AkPacket readPacket(size_t bufferIndex, + const AMediaCodecBufferInfo &info); +}; + +VideoStream::VideoStream(AMediaExtractor *mediaExtractor, + uint index, qint64 id, Clock *globalClock, + QObject *parent): + AbstractStream(mediaExtractor, index, id, globalClock, parent) +{ + this->d = new VideoStreamPrivate(this); + this->m_maxData = 3; +} + +VideoStream::~VideoStream() +{ + delete this->d; +} + +AkCaps VideoStream::caps() const +{ + int32_t width = 0; + AMediaFormat_getInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_WIDTH, + &width); + int32_t height = 0; + AMediaFormat_getInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_HEIGHT, + &height); + int32_t frameRate; + AMediaFormat_getInt32(this->mediaFormat(), + AMEDIAFORMAT_KEY_FRAME_RATE, + &frameRate); + + return AkVideoCaps(AkVideoCaps::Format_rgb24, + width, + height, + AkFrac(frameRate, 1)); +} + +bool VideoStream::decodeData() +{ + if (!this->isValid()) + return false; + + AMediaCodecBufferInfo info; + memset(&info, 0, sizeof(AMediaCodecBufferInfo)); + ssize_t timeOut = 5000; + auto bufferIndex = + AMediaCodec_dequeueOutputBuffer(this->codec(), &info, timeOut); + + if (bufferIndex == AMEDIACODEC_INFO_TRY_AGAIN_LATER) + return true; + else if (bufferIndex >= 0) { + auto packet = this->d->readPacket(size_t(bufferIndex), info); + + if (packet) + this->avPacketEnqueue(packet); + + AMediaCodec_releaseOutputBuffer(this->codec(), + size_t(bufferIndex), + info.size != 0); + } + + if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { + this->avPacketEnqueue({}); + + return false; + } + + return true; +} + +void VideoStream::processPacket(const AkPacket &packet) +{ + forever { + qreal pts = packet.pts() * packet.timeBase().value(); + qreal diff = pts - this->globalClock()->clock(); + qreal delay = pts - this->d->m_lastPts; + + // Skip or repeat frame. We take into account the + // delay to compute the threshold. I still don't know + // if it is the best guess. + qreal syncThreshold = qBound(AV_SYNC_THRESHOLD_MIN, + delay, + AV_SYNC_THRESHOLD_MAX); + + if (!qIsNaN(diff) + && qAbs(diff) < AV_NOSYNC_THRESHOLD + && delay < AV_SYNC_FRAMEDUP_THRESHOLD) { + // Video is backward the external clock. + if (diff <= -syncThreshold) { + // Drop frame. + this->d->m_lastPts = pts; + + break; + } + + if (diff > syncThreshold) { + // Video is ahead the external clock. + QThread::usleep(ulong(1e6 * (diff - syncThreshold))); + + continue; + } + } else { + this->globalClock()->setClock(pts); + } + + this->m_clockDiff = diff; + auto oPacket = AkVideoPacket(packet).convert(AkVideoCaps::Format_rgb24); + emit this->oStream(oPacket); + this->d->m_lastPts = pts; + + break; + } +} + +VideoStreamPrivate::VideoStreamPrivate(VideoStream *self): + self(self) +{ + +} + +AkPacket VideoStreamPrivate::readPacket(size_t bufferIndex, + const AMediaCodecBufferInfo &info) +{ + auto format = AMediaCodec_getOutputFormat(self->codec()); + int32_t colorFormat = 0; + AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_COLOR_FORMAT, + &colorFormat); + int32_t width = 0; + AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_WIDTH, + &width); + int32_t height = 0; + AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_HEIGHT, + &height); + int32_t frameRate; + AMediaFormat_getInt32(format, + AMEDIAFORMAT_KEY_FRAME_RATE, + &frameRate); + AMediaFormat_delete(format); + + size_t bufferSize = 0; + auto data = AMediaCodec_getOutputBuffer(self->codec(), + bufferIndex, + &bufferSize); + bufferSize = qMin(bufferSize, size_t(info.size)); + QByteArray oBuffer(int(bufferSize), Qt::Uninitialized); + memcpy(oBuffer.data(), data + info.offset, bufferSize); + + AkVideoPacket packet; + packet.setCaps({imageFormatToPixelFormat().value(colorFormat), + width, + height, + {AkFrac(frameRate, 1)}}); + packet.setBuffer(oBuffer); + packet.setPts(info.presentationTimeUs); + packet.setTimeBase({1, qint64(1e6)}); + packet.setIndex(int(self->index())); + packet.setId(self->id()); + + return packet; +} + +#include "moc_videostream.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/videostream.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/videostream.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/videostream.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/ndkmedia/src/videostream.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,48 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef VIDEOSTREAM_H +#define VIDEOSTREAM_H + +#include "abstractstream.h" + +class VideoStreamPrivate; + +class VideoStream: public AbstractStream +{ + Q_OBJECT + + public: + VideoStream(AMediaExtractor *mediaExtractor=nullptr, + uint index=0, qint64 id=-1, + Clock *globalClock=nullptr, + QObject *parent=nullptr); + ~VideoStream(); + + Q_INVOKABLE AkCaps caps() const; + Q_INVOKABLE bool decodeData(); + + protected: + void processPacket(const AkPacket &packet); + + private: + VideoStreamPrivate *d; +}; + +#endif // VIDEOSTREAM_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/src.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/src.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/MultiSrc/src/src.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/MultiSrc/src/src.pro 2021-02-15 15:25:23.000000000 +0000 @@ -36,8 +36,9 @@ HEADERS = \ multisrc.h \ multisrcelement.h \ - mediasource.h \ - multisrcglobals.h + multisrcelementsettings.h \ + multisrcglobals.h \ + mediasource.h INCLUDEPATH += \ ../../../Lib/src @@ -54,8 +55,9 @@ SOURCES = \ multisrc.cpp \ multisrcelement.cpp \ - mediasource.cpp \ - multisrcglobals.cpp + multisrcelementsettings.cpp \ + multisrcglobals.cpp \ + mediasource.cpp lupdate_only { SOURCES += $$files(../share/qml/*.qml) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Nervous/src/nervouselement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Nervous/src/nervouselement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Nervous/src/nervouselement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Nervous/src/nervouselement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,9 +17,12 @@ * Web-Site: http://webcamoid.github.io/ */ -#include +#include #include #include +#include +#include +#include #include #include "nervouselement.h" @@ -70,38 +73,9 @@ context->setContextProperty("controlId", this->objectName()); } -void NervousElement::setNFrames(int nFrames) -{ - if (this->d->m_nFrames == nFrames) - return; - - this->d->m_nFrames = nFrames; - this->nFramesChanged(nFrames); -} - -void NervousElement::setSimple(bool simple) -{ - if (this->d->m_simple == simple) - return; - - this->d->m_simple = simple; - this->simpleChanged(simple); -} - -void NervousElement::resetNFrames() -{ - this->setNFrames(32); -} - -void NervousElement::resetSimple() -{ - this->setSimple(false); -} - -AkPacket NervousElement::iStream(const AkPacket &packet) +AkPacket NervousElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -130,21 +104,49 @@ nFrame = qBound(0, nFrame, this->d->m_frames.size() - 1); timer--; } else { - nFrame = qrand() % this->d->m_frames.size(); - this->d->m_stride = qrand() % 5 - 2; + nFrame = QRandomGenerator::global()->bounded(this->d->m_frames.size()); + this->d->m_stride = QRandomGenerator::global()->bounded(2, 6); if (this->d->m_stride >= 0) this->d->m_stride++; - timer = qrand() % 6 + 2; + timer = QRandomGenerator::global()->bounded(2, 8); } } else if(!this->d->m_frames.isEmpty()) { - nFrame = qrand() % this->d->m_frames.size(); + nFrame = QRandomGenerator::global()->bounded(this->d->m_frames.size()); } - auto oPacket = AkVideoPacket::fromImage(this->d->m_frames[nFrame], - videoPacket).toPacket(); + auto oPacket = + AkVideoPacket::fromImage(this->d->m_frames[nFrame], packet); akSend(oPacket) } +void NervousElement::setNFrames(int nFrames) +{ + if (this->d->m_nFrames == nFrames) + return; + + this->d->m_nFrames = nFrames; + this->nFramesChanged(nFrames); +} + +void NervousElement::setSimple(bool simple) +{ + if (this->d->m_simple == simple) + return; + + this->d->m_simple = simple; + this->simpleChanged(simple); +} + +void NervousElement::resetNFrames() +{ + this->setNFrames(32); +} + +void NervousElement::resetSimple() +{ + this->setSimple(false); +} + #include "moc_nervouselement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Nervous/src/nervouselement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Nervous/src/nervouselement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Nervous/src/nervouselement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Nervous/src/nervouselement.h 2021-02-15 15:25:23.000000000 +0000 @@ -52,6 +52,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void nFramesChanged(int nFrames); @@ -62,7 +63,6 @@ void setSimple(bool simple); void resetNFrames(); void resetSimple(); - AkPacket iStream(const AkPacket &packet); }; #endif // NERVOUSELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Normalize/src/normalizeelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Normalize/src/normalizeelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Normalize/src/normalizeelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Normalize/src/normalizeelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -18,6 +18,7 @@ */ #include +#include #include #include "normalizeelement.h" @@ -27,15 +28,14 @@ { } -AkPacket NormalizeElement::iStream(const AkPacket &packet) +AkPacket NormalizeElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) - return AkPacket(); + return {}; - QImage oFrame = src.convertToFormat(QImage::Format_ARGB32); + auto oFrame = src.convertToFormat(QImage::Format_ARGB32); // form histogram QVector histogram(256, HistogramListItem()); @@ -44,11 +44,11 @@ const QRgb *dstLine = reinterpret_cast(oFrame.constScanLine(y)); for (int x = 0; x < oFrame.width(); x++) { - QRgb pixel = dstLine[x]; - histogram[qRed(pixel)].red++; - histogram[qGreen(pixel)].green++; - histogram[qBlue(pixel)].blue++; - histogram[qAlpha(pixel)].alpha++; + auto pixel = dstLine[x]; + histogram[qRed(pixel)].r++; + histogram[qGreen(pixel)].g++; + histogram[qBlue(pixel)].b++; + histogram[qAlpha(pixel)].a++; } } @@ -57,55 +57,55 @@ auto thresholdIntensity = qint32(oFrame.width() * oFrame.height() / 1e3); IntegerPixel intensity; - for (low.red = 0; low.red < 256; low.red++) { - intensity.red += histogram[low.red].red; + for (low.r = 0; low.r < 256; low.r++) { + intensity.r += histogram[low.r].r; - if (intensity.red > thresholdIntensity) + if (intensity.r > thresholdIntensity) break; } intensity.clear(); - for (high.red = 255; high.red > 0; high.red--) { - intensity.red += histogram[high.red].red; + for (high.r = 255; high.r > 0; high.r--) { + intensity.r += histogram[high.r].r; - if (intensity.red > thresholdIntensity) + if (intensity.r > thresholdIntensity) break; } intensity.clear(); - for (low.green = low.red; low.green < high.red; low.green++) { - intensity.green += histogram[low.green].green; + for (low.g = low.r; low.g < high.r; low.g++) { + intensity.g += histogram[low.g].g; - if (intensity.green > thresholdIntensity) + if (intensity.g > thresholdIntensity) break; } intensity.clear(); - for (high.green = high.red; high.green != low.red; high.green--) { - intensity.green += histogram[high.green].green; + for (high.g = high.r; high.g != low.r; high.g--) { + intensity.g += histogram[high.g].g; - if (intensity.green > thresholdIntensity) + if (intensity.g > thresholdIntensity) break; } intensity.clear(); - for (low.blue = low.green; low.blue < high.green; low.blue++) { - intensity.blue += histogram[low.blue].blue; + for (low.b = low.g; low.b < high.g; low.b++) { + intensity.b += histogram[low.b].b; - if (intensity.blue > thresholdIntensity) + if (intensity.b > thresholdIntensity) break; } intensity.clear(); - for (high.blue = high.green; high.blue != low.green; high.blue--) { - intensity.blue += histogram[high.blue].blue; + for (high.b = high.g; high.b != low.g; high.b--) { + intensity.b += histogram[high.b].b; - if (intensity.blue > thresholdIntensity) + if (intensity.b > thresholdIntensity) break; } @@ -113,58 +113,58 @@ QVector normalizeMap(256); for (int i = 0; i < 256; i++) { - if(i < low.red) - normalizeMap[i].red = 0; + if(i < low.r) + normalizeMap[i].r = 0; else { - if (i > high.red) - normalizeMap[i].red = 255; - else if (low.red != high.red) - normalizeMap[i].red = (255 * (i - low.red)) / - (high.red - low.red); + if (i > high.r) + normalizeMap[i].r = 255; + else if (low.r != high.r) + normalizeMap[i].r = (255 * (i - low.r)) / + (high.r - low.r); } - if (i < low.green) - normalizeMap[i].green = 0; + if (i < low.g) + normalizeMap[i].g = 0; else { - if(i > high.green) - normalizeMap[i].green = 255; - else if(low.green != high.green) - normalizeMap[i].green = (255 * (i - low.green)) / - (high.green - low.green); + if(i > high.g) + normalizeMap[i].g = 255; + else if(low.g != high.g) + normalizeMap[i].g = (255 * (i - low.g)) / + (high.g - low.g); } - if (i < low.blue) - normalizeMap[i].blue = 0; + if (i < low.b) + normalizeMap[i].b = 0; else { - if (i > high.blue) - normalizeMap[i].blue = 255; - else if (low.blue != high.blue) - normalizeMap[i].blue = (255*(i-low.blue)) / - (high.blue - low.blue); + if (i > high.b) + normalizeMap[i].b = 255; + else if (low.b != high.b) + normalizeMap[i].b = (255*(i-low.b)) / + (high.b - low.b); } } // write for (int y = 0; y < oFrame.height(); y++) { - QRgb *oLine = reinterpret_cast(oFrame.scanLine(y)); + auto oLine = reinterpret_cast(oFrame.scanLine(y)); for (int x = 0; x < oFrame.width(); x++) { - QRgb pixel = oLine[x]; + auto pixel = oLine[x]; - int r = (low.red != high.red)? normalizeMap[qRed(pixel)].red: + int r = (low.r != high.r)? normalizeMap[qRed(pixel)].r: qRed(pixel); - int g = (low.green != high.green)? normalizeMap[qGreen(pixel)].green: + int g = (low.g != high.g)? normalizeMap[qGreen(pixel)].g: qGreen(pixel); - int b = (low.blue != high.blue)? normalizeMap[qBlue(pixel)].blue: + int b = (low.b != high.b)? normalizeMap[qBlue(pixel)].b: qBlue(pixel); oLine[x] = qRgba(r, g, b, qAlpha(pixel)); } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Normalize/src/normalizeelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Normalize/src/normalizeelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Normalize/src/normalizeelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Normalize/src/normalizeelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -29,8 +29,8 @@ public: NormalizeElement(); - public slots: - AkPacket iStream(const AkPacket &packet); + protected: + AkPacket iVideoStream(const AkVideoPacket &packet); }; #endif // NORMALIZEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Normalize/src/pixelstructs.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Normalize/src/pixelstructs.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Normalize/src/pixelstructs.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Normalize/src/pixelstructs.h 2021-02-15 15:25:23.000000000 +0000 @@ -25,34 +25,29 @@ template struct Pixel { - Pixel(): - red(0), green(0), blue(0), alpha(0) - { - } + T r; + T g; + T b; + T a; - Pixel(T red, T green, T blue, T alpha): - red(red), green(green), blue(blue), alpha(alpha) + inline Pixel(T r=0, T g=0, T b=0, T a=0): + r(r), g(g), b(b), a(a) { } - void clear() { - this->red = 0; - this->green = 0; - this->blue = 0; - this->alpha = 0; + inline void clear() { + this->r = 0; + this->g = 0; + this->b = 0; + this->a = 0; } - - T red; - T green; - T blue; - T alpha; }; // These are used as accumulators -typedef struct Pixel IntegerPixel; -typedef struct Pixel UIntegerPixel; -typedef struct Pixel ShortPixel; -typedef struct Pixel CharPixel; +typedef Pixel IntegerPixel; +typedef Pixel UIntegerPixel; +typedef Pixel ShortPixel; +typedef Pixel CharPixel; typedef IntegerPixel HistogramListItem; #endif // PIXELSTRUCTS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/OilPaint/share/qml/main.qml webcamoid-8.8.0+dfsg/libAvKys/Plugins/OilPaint/share/qml/main.qml --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/OilPaint/share/qml/main.qml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/OilPaint/share/qml/main.qml 2021-02-15 15:25:23.000000000 +0000 @@ -34,6 +34,6 @@ } Layout.fillWidth: true - onTextChanged: OilPaint.radius = text + onTextChanged: OilPaint.radius = Number(text) } } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/OilPaint/src/oilpaintelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/OilPaint/src/oilpaintelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/OilPaint/src/oilpaintelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/OilPaint/src/oilpaintelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include "oilpaintelement.h" @@ -60,24 +61,9 @@ context->setContextProperty("controlId", this->objectName()); } -void OilPaintElement::setRadius(int radius) -{ - if (this->d->m_radius == radius) - return; - - this->d->m_radius = radius; - this->radiusChanged(radius); -} - -void OilPaintElement::resetRadius() -{ - this->setRadius(2); -} - -AkPacket OilPaintElement::iStream(const AkPacket &packet) +AkPacket OilPaintElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -94,7 +80,7 @@ QRgb *oLine = reinterpret_cast(oFrame.scanLine(y)); for (int j = 0, pos = y - radius; j < scanBlockLen; j++, pos++) { - int yp = qBound(0, pos, src.height()); + int yp = qBound(0, pos, src.height() - 1); scanBlock[j] = reinterpret_cast(src.constScanLine(yp)); } @@ -127,8 +113,22 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void OilPaintElement::setRadius(int radius) +{ + if (this->d->m_radius == radius) + return; + + this->d->m_radius = radius; + this->radiusChanged(radius); +} + +void OilPaintElement::resetRadius() +{ + this->setRadius(2); +} + #include "moc_oilpaintelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/OilPaint/src/oilpaintelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/OilPaint/src/oilpaintelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/OilPaint/src/oilpaintelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/OilPaint/src/oilpaintelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void radiusChanged(int radius); @@ -53,7 +54,6 @@ public slots: void setRadius(int radius); void resetRadius(); - AkPacket iStream(const AkPacket &packet); }; #endif // OILPAINTELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Photocopy/src/photocopyelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Photocopy/src/photocopyelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Photocopy/src/photocopyelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Photocopy/src/photocopyelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "photocopyelement.h" @@ -69,38 +70,9 @@ context->setContextProperty("controlId", this->objectName()); } -void PhotocopyElement::setBrightness(qreal brightness) -{ - if (qFuzzyCompare(this->d->m_brightness, brightness)) - return; - - this->d->m_brightness = brightness; - emit this->brightnessChanged(brightness); -} - -void PhotocopyElement::setContrast(qreal contrast) -{ - if (qFuzzyCompare(this->d->m_contrast, contrast)) - return; - - this->d->m_contrast = contrast; - emit this->contrastChanged(contrast); -} - -void PhotocopyElement::resetBrightness() -{ - this->setBrightness(0.75); -} - -void PhotocopyElement::resetContrast() -{ - this->setContrast(20); -} - -AkPacket PhotocopyElement::iStream(const AkPacket &packet) +AkPacket PhotocopyElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -130,10 +102,38 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void PhotocopyElement::setBrightness(qreal brightness) +{ + if (qFuzzyCompare(this->d->m_brightness, brightness)) + return; + + this->d->m_brightness = brightness; + emit this->brightnessChanged(brightness); +} + +void PhotocopyElement::setContrast(qreal contrast) +{ + if (qFuzzyCompare(this->d->m_contrast, contrast)) + return; + + this->d->m_contrast = contrast; + emit this->contrastChanged(contrast); +} + +void PhotocopyElement::resetBrightness() +{ + this->setBrightness(0.75); +} + +void PhotocopyElement::resetContrast() +{ + this->setContrast(20); +} + int PhotocopyElementPrivate::rgbToLuma(int red, int green, int blue) { int min; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Photocopy/src/photocopyelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Photocopy/src/photocopyelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Photocopy/src/photocopyelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Photocopy/src/photocopyelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -52,6 +52,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void brightnessChanged(qreal brightness); @@ -62,8 +63,6 @@ void setContrast(qreal contrast); void resetBrightness(); void resetContrast(); - - AkPacket iStream(const AkPacket &packet); }; #endif // PHOTOCOPYELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Pixelate/src/pixelateelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Pixelate/src/pixelateelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Pixelate/src/pixelateelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Pixelate/src/pixelateelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include "pixelateelement.h" @@ -65,29 +66,14 @@ context->setContextProperty("controlId", this->objectName()); } -void PixelateElement::setBlockSize(const QSize &blockSize) -{ - if (blockSize == this->d->m_blockSize) - return; - - this->d->m_blockSize = blockSize; - emit this->blockSizeChanged(blockSize); -} - -void PixelateElement::resetBlockSize() -{ - this->setBlockSize(QSize(8, 8)); -} - -AkPacket PixelateElement::iStream(const AkPacket &packet) +AkPacket PixelateElement::iVideoStream(const AkVideoPacket &packet) { QSize blockSize = this->d->m_blockSize; if (blockSize.isEmpty()) akSend(packet) - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -106,8 +92,22 @@ Qt::IgnoreAspectRatio, Qt::FastTransformation); - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void PixelateElement::setBlockSize(const QSize &blockSize) +{ + if (blockSize == this->d->m_blockSize) + return; + + this->d->m_blockSize = blockSize; + emit this->blockSizeChanged(blockSize); +} + +void PixelateElement::resetBlockSize() +{ + this->setBlockSize(QSize(8, 8)); +} + #include "moc_pixelateelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Pixelate/src/pixelateelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Pixelate/src/pixelateelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Pixelate/src/pixelateelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Pixelate/src/pixelateelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void blockSizeChanged(const QSize &blockSize); @@ -53,7 +54,6 @@ public slots: void setBlockSize(const QSize &blockSize); void resetBlockSize(); - AkPacket iStream(const AkPacket &packet); }; #endif // PIXELATEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Plugins.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/Plugins.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Plugins.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Plugins.pro 2021-02-15 15:25:23.000000000 +0000 @@ -25,12 +25,10 @@ ACapsConvert \ AudioDevice \ AudioGen \ - Bin \ DesktopCapture \ Multiplex \ MultiSink \ MultiSrc \ - Probe \ VideoCapture isEmpty(NOVCAM): { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/PrimariesColors/src/primariescolorselement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/PrimariesColors/src/primariescolorselement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/PrimariesColors/src/primariescolorselement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/PrimariesColors/src/primariescolorselement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include "primariescolorselement.h" @@ -60,24 +61,9 @@ context->setContextProperty("controlId", this->objectName()); } -void PrimariesColorsElement::setFactor(int factor) -{ - if (this->d->m_factor == factor) - return; - - this->d->m_factor = factor; - emit this->factorChanged(factor); -} - -void PrimariesColorsElement::resetFactor() -{ - this->setFactor(2); -} - -AkPacket PrimariesColorsElement::iStream(const AkPacket &packet) +AkPacket PrimariesColorsElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -118,8 +104,22 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void PrimariesColorsElement::setFactor(int factor) +{ + if (this->d->m_factor == factor) + return; + + this->d->m_factor = factor; + emit this->factorChanged(factor); +} + +void PrimariesColorsElement::resetFactor() +{ + this->setFactor(2); +} + #include "moc_primariescolorselement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/PrimariesColors/src/primariescolorselement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/PrimariesColors/src/primariescolorselement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/PrimariesColors/src/primariescolorselement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/PrimariesColors/src/primariescolorselement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void factorChanged(int factor); @@ -53,8 +54,6 @@ public slots: void setFactor(int factor); void resetFactor(); - - AkPacket iStream(const AkPacket &packet); }; #endif // PRIMARIESCOLORSELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/Probe.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/Probe.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/Probe.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/Probe.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -# Webcamoid, webcam capture application. -# Copyright (C) 2016 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -exists(akcommons.pri) { - include(akcommons.pri) -} else { - exists(../../akcommons.pri) { - include(../../akcommons.pri) - } else { - error("akcommons.pri file not found.") - } -} - -CONFIG += plugin - -HEADERS = \ - src/probe.h \ - src/probeelement.h - -INCLUDEPATH += \ - ../../Lib/src - -LIBS += -L$${OUT_PWD}/../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} - -OTHER_FILES += pspec.json - -QT += qml - -SOURCES = \ - src/probe.cpp \ - src/probeelement.cpp - -DESTDIR = $${OUT_PWD}/$${BIN_DIR} -android: TARGET = $${COMMONS_TARGET}_lib$${TARGET} - -TEMPLATE = lib - -INSTALLS += target -target.path = $${INSTALLPLUGINSDIR} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/pspec.json 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/pspec.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -{ - "pluginType": "Ak.Element" -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/src/probe.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/src/probe.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/src/probe.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/src/probe.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "probe.h" -#include "probeelement.h" - -QObject *Probe::create(const QString &key, const QString &specification) -{ - Q_UNUSED(specification) - - if (key == AK_PLUGIN_TYPE_ELEMENT) - return new ProbeElement(); - - return nullptr; -} - -QStringList Probe::keys() const -{ - return QStringList(); -} - -#include "moc_probe.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/src/probeelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/src/probeelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/src/probeelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/src/probeelement.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include -#include - -#include "probeelement.h" - -class ProbeElementPrivate -{ - public: - bool m_log {false}; -}; - -ProbeElement::ProbeElement(): AkElement() -{ - this->d = new ProbeElementPrivate; -} - -ProbeElement::~ProbeElement() -{ - delete this->d; -} - -bool ProbeElement::log() const -{ - return this->d->m_log; -} - -void ProbeElement::setLog(bool log) -{ - if (this->d->m_log == log) - return; - - this->d->m_log = log; - emit this->logChanged(log); -} - -void ProbeElement::resetLog() -{ - this->setLog(false); -} - -AkPacket ProbeElement::iStream(const AkPacket &packet) -{ - if (this->d->m_log) { - qDebug().nospace() << "\"" << this->objectName().toStdString().c_str() << "\""; - - for (auto &line: packet.toString().split('\n')) - qDebug().nospace() << "\t" - << line.toStdString().c_str(); - } - - akSend(packet); -} - -#include "moc_probeelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/src/probeelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/src/probeelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/src/probeelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/src/probeelement.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef PROBEELEMENT_H -#define PROBEELEMENT_H - -#include - -class ProbeElementPrivate; - -class ProbeElement: public AkElement -{ - Q_OBJECT - Q_PROPERTY(bool log - READ log - WRITE setLog - RESET resetLog - NOTIFY logChanged) - - public: - ProbeElement(); - ~ProbeElement(); - - Q_INVOKABLE bool log() const; - - private: - ProbeElementPrivate *d; - - signals: - void logChanged(bool log); - - public slots: - void setLog(bool log); - void resetLog(); - - AkPacket iStream(const AkPacket &packet); -}; - -#endif // PROBEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/src/probe.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/src/probe.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Probe/src/probe.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Probe/src/probe.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef PROBE_H -#define PROBE_H - -#include - -class Probe: public QObject, public AkPlugin -{ - Q_OBJECT - Q_INTERFACES(AkPlugin) - Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") - - public: - QObject *create(const QString &key, const QString &specification); - QStringList keys() const; -}; - -#endif // PROBE_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Quark/src/quarkelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Quark/src/quarkelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Quark/src/quarkelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Quark/src/quarkelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,8 +17,11 @@ * Web-Site: http://webcamoid.github.io/ */ +#include #include #include +#include +#include #include #include "quarkelement.h" @@ -61,24 +64,9 @@ context->setContextProperty("controlId", this->objectName()); } -void QuarkElement::setNFrames(int nFrames) -{ - if (this->d->m_nFrames == nFrames) - return; - - this->d->m_nFrames = nFrames; - emit this->nFramesChanged(nFrames); -} - -void QuarkElement::resetNFrames() -{ - this->setNFrames(16); -} - -AkPacket QuarkElement::iStream(const AkPacket &packet) +AkPacket QuarkElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -102,13 +90,27 @@ QRgb *dstLine = reinterpret_cast(oFrame.scanLine(y)); for (int x = 0; x < src.width(); x++) { - int frame = qrand() % this->d->m_frames.size(); + int frame = QRandomGenerator::global()->bounded(this->d->m_frames.size()); dstLine[x] = this->d->m_frames[frame].pixel(x, y); } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void QuarkElement::setNFrames(int nFrames) +{ + if (this->d->m_nFrames == nFrames) + return; + + this->d->m_nFrames = nFrames; + emit this->nFramesChanged(nFrames); +} + +void QuarkElement::resetNFrames() +{ + this->setNFrames(16); +} + #include "moc_quarkelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Quark/src/quarkelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Quark/src/quarkelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Quark/src/quarkelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Quark/src/quarkelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void nFramesChanged(int nFrames); @@ -53,8 +54,6 @@ public slots: void setNFrames(int nFrames); void resetNFrames(); - - AkPacket iStream(const AkPacket &packet); }; #endif // QUARKELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Radioactive/src/radioactiveelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Radioactive/src/radioactiveelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Radioactive/src/radioactiveelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Radioactive/src/radioactiveelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "radioactiveelement.h" @@ -217,6 +218,78 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket RadioactiveElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + if (src.size() != this->d->m_frameSize) { + this->d->m_blurZoomBuffer = QImage(); + this->d->m_prevFrame = QImage(); + this->d->m_frameSize = src.size(); + } + + if (this->d->m_prevFrame.isNull()) { + oFrame = src; + this->d->m_blurZoomBuffer = QImage(src.size(), src.format()); + this->d->m_blurZoomBuffer.fill(qRgba(0, 0, 0, 0)); + } else { + // Compute the difference between previous and current frame, + // and save it to the buffer. + QImage diff = + this->d->imageDiff(this->d->m_prevFrame, + src, + this->d->m_threshold, + this->d->m_lumaThreshold, + this->d->m_radColor, + this->d->m_mode); + + QPainter painter; + painter.begin(&this->d->m_blurZoomBuffer); + painter.drawImage(0, 0, diff); + painter.end(); + + // Blur buffer. + auto blurZoomPacket = + AkVideoPacket::fromImage(this->d->m_blurZoomBuffer, packet); + auto blurPacket = this->d->m_blurFilter->iStream(blurZoomPacket); + auto blur = AkVideoPacket(blurPacket).toImage(); + + // Zoom buffer. + QImage blurScaled = blur.scaled(this->d->m_zoom * blur.size()); + QSize diffSize = blur.size() - blurScaled.size(); + QPoint p(diffSize.width() >> 1, + diffSize.height() >> 1); + + QImage zoom(blur.size(), blur.format()); + zoom.fill(qRgba(0, 0, 0, 0)); + + painter.begin(&zoom); + painter.drawImage(p, blurScaled); + painter.end(); + + // Reduce alpha. + QImage alphaDiff = this->d->imageAlphaDiff(zoom, this->d->m_alphaDiff); + this->d->m_blurZoomBuffer = alphaDiff; + + // Apply buffer. + painter.begin(&oFrame); + painter.drawImage(0, 0, src); + painter.drawImage(0, 0, this->d->m_blurZoomBuffer); + painter.end(); + } + + this->d->m_prevFrame = src.copy(); + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void RadioactiveElement::setMode(const QString &mode) { RadiationMode modeEnum = radiationModeToStr->key(mode, @@ -314,77 +387,4 @@ this->setRadColor(qRgb(0, 255, 0)); } -AkPacket RadioactiveElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - if (src.size() != this->d->m_frameSize) { - this->d->m_blurZoomBuffer = QImage(); - this->d->m_prevFrame = QImage(); - this->d->m_frameSize = src.size(); - } - - if (this->d->m_prevFrame.isNull()) { - oFrame = src; - this->d->m_blurZoomBuffer = QImage(src.size(), src.format()); - this->d->m_blurZoomBuffer.fill(qRgba(0, 0, 0, 0)); - } else { - // Compute the difference between previous and current frame, - // and save it to the buffer. - QImage diff = - this->d->imageDiff(this->d->m_prevFrame, - src, - this->d->m_threshold, - this->d->m_lumaThreshold, - this->d->m_radColor, - this->d->m_mode); - - QPainter painter; - painter.begin(&this->d->m_blurZoomBuffer); - painter.drawImage(0, 0, diff); - painter.end(); - - // Blur buffer. - auto blurZoomPacket = AkVideoPacket::fromImage(this->d->m_blurZoomBuffer, - videoPacket); - auto blurPacket = this->d->m_blurFilter->iStream(blurZoomPacket.toPacket()); - auto blur = AkVideoPacket(blurPacket).toImage(); - - // Zoom buffer. - QImage blurScaled = blur.scaled(this->d->m_zoom * blur.size()); - QSize diffSize = blur.size() - blurScaled.size(); - QPoint p(diffSize.width() >> 1, - diffSize.height() >> 1); - - QImage zoom(blur.size(), blur.format()); - zoom.fill(qRgba(0, 0, 0, 0)); - - painter.begin(&zoom); - painter.drawImage(p, blurScaled); - painter.end(); - - // Reduce alpha. - QImage alphaDiff = this->d->imageAlphaDiff(zoom, this->d->m_alphaDiff); - this->d->m_blurZoomBuffer = alphaDiff; - - // Apply buffer. - painter.begin(&oFrame); - painter.drawImage(0, 0, src); - painter.drawImage(0, 0, this->d->m_blurZoomBuffer); - painter.end(); - } - - this->d->m_prevFrame = src.copy(); - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_radioactiveelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Radioactive/src/radioactiveelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Radioactive/src/radioactiveelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Radioactive/src/radioactiveelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Radioactive/src/radioactiveelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -92,6 +92,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void modeChanged(const QString &mode); @@ -117,8 +118,6 @@ void resetLumaThreshold(); void resetAlphaDiff(); void resetRadColor(); - - AkPacket iStream(const AkPacket &packet); }; #endif // RADIOACTIVEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Ripple/src/rippleelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Ripple/src/rippleelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Ripple/src/rippleelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Ripple/src/rippleelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,10 +17,12 @@ * Web-Site: http://webcamoid.github.io/ */ -#include #include #include +#include +#include #include +#include #include #include "rippleelement.h" @@ -279,35 +281,53 @@ QImage RippleElementPrivate::rainDrop(int width, int height, int strength) { if (this->m_period == 0) { - if (this->m_rainStat == 0) { - this->m_period = (qrand() >> 23) + 100; + switch (this->m_rainStat) { + case 0: + this->m_period = QRandomGenerator::global()->bounded(100, 612); this->m_dropProb = 0; this->m_dropProbIncrement = 0x00ffffff / this->m_period; - this->m_dropPower = qrand() % (strength << 1) - strength; - this->m_dropsPerFrameMax = 2 << (qrand() >> 30); // 2,4,8 or 16 + this->m_dropPower = QRandomGenerator::global()->bounded(-strength, strength); + this->m_dropsPerFrameMax = 2 << QRandomGenerator::global()->bounded(4); this->m_rainStat = 1; - } else if (this->m_rainStat == 1) { + + break; + + case 1: this->m_dropProb = 0x00ffffff; this->m_dropsPerFrame = 1; this->m_dropProbIncrement = 1; this->m_period = 16 * (this->m_dropsPerFrameMax - 1); this->m_rainStat = 2; - } else if (this->m_rainStat == 2) { - m_period = (qrand() >> 22) + 1000; + + break; + + case 2: + m_period = QRandomGenerator::global()->bounded(1000, 2024); m_dropProbIncrement = 0; m_rainStat = 3; - } else if (this->m_rainStat == 3) { + + break; + + case 3: this->m_period = 16 * (this->m_dropsPerFrameMax - 1); this->m_dropProbIncrement = -1; this->m_rainStat = 4; - } else if (this->m_rainStat == 4) { - this->m_period = (qrand() >> 24) + 60; + + break; + + case 4: + this->m_period = QRandomGenerator::global()->bounded(60, 316); this->m_dropProbIncrement = -int(this->m_dropProb) / this->m_period; this->m_rainStat = 5; - } else { - this->m_period = (qrand() >> 23) + 500; + + break; + + default: + this->m_period = QRandomGenerator::global()->bounded(500, 1012); this->m_dropProb = 0; this->m_rainStat = 0; + + break; } } @@ -316,7 +336,7 @@ if (this->m_rainStat == 1 || this->m_rainStat == 5) { - if ((qrand() >> 8) < int(this->m_dropProb)) + if ((QRandomGenerator::global()->generate() >> 8) < this->m_dropProb) rain = this->drop(width, height, this->m_dropPower); this->m_dropProb += uint(this->m_dropProbIncrement); @@ -349,8 +369,8 @@ int widthM1 = width - 1; int widthP1 = width + 1; - int x = qrand() % (width - 4) + 2; - int y = qrand() % (height - 4) + 2; + int x = QRandomGenerator::global()->bounded(2, width - 2); + int y = QRandomGenerator::global()->bounded(2, height - 2); int offset = x + y * width; @@ -383,6 +403,70 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket RippleElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + if (packet.caps() != this->d->m_caps) { + this->d->m_prevFrame = QImage(); + this->d->m_period = 0; + this->d->m_rainStat = 0; + this->d->m_dropProb = 0; + this->d->m_dropProbIncrement = 0; + this->d->m_dropsPerFrameMax = 0; + this->d->m_dropsPerFrame = 0; + this->d->m_dropPower = 0; + this->d->m_caps = packet.caps(); + } + + if (this->d->m_prevFrame.isNull()) { + oFrame = src; + this->d->m_rippleBuffer.clear(); + this->d->m_rippleBuffer << QImage(src.size(), src.format()); + this->d->m_rippleBuffer[0].fill(qRgba(0, 0, 0, 0)); + this->d->m_rippleBuffer << QImage(src.size(), src.format()); + this->d->m_rippleBuffer[1].fill(qRgba(0, 0, 0, 0)); + this->d->m_curRippleBuffer = 0; + } else { + QImage drops; + + if (this->d->m_mode == RippleModeMotionDetect) + // Compute the difference between previous and current frame, + // and save it to the buffer. + drops = this->d->imageDiff(this->d->m_prevFrame, + src, + this->d->m_threshold, + this->d->m_lumaThreshold, + this->d->m_amplitude); + else + drops = this->d->rainDrop(src.width(), + src.height(), + this->d->m_amplitude); + + this->d->addDrops(this->d->m_rippleBuffer[this->d->m_curRippleBuffer], drops); + this->d->addDrops(this->d->m_rippleBuffer[1 - this->d->m_curRippleBuffer], drops); + + this->d->ripple(this->d->m_rippleBuffer[this->d->m_curRippleBuffer], + this->d->m_rippleBuffer[1 - this->d->m_curRippleBuffer], + this->d->m_decay); + + // Apply buffer. + oFrame = this->d->applyWater(src, + this->d->m_rippleBuffer[this->d->m_curRippleBuffer]); + this->d->m_curRippleBuffer = 1 - this->d->m_curRippleBuffer; + } + + this->d->m_prevFrame = src.copy(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void RippleElement::setMode(const QString &mode) { RippleMode modeEnum = rippleModeToStr->key(mode, RippleModeMotionDetect); @@ -455,69 +539,4 @@ this->setLumaThreshold(15); } -AkPacket RippleElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - if (packet.caps() != this->d->m_caps) { - this->d->m_prevFrame = QImage(); - this->d->m_period = 0; - this->d->m_rainStat = 0; - this->d->m_dropProb = 0; - this->d->m_dropProbIncrement = 0; - this->d->m_dropsPerFrameMax = 0; - this->d->m_dropsPerFrame = 0; - this->d->m_dropPower = 0; - this->d->m_caps = packet.caps(); - } - - if (this->d->m_prevFrame.isNull()) { - oFrame = src; - this->d->m_rippleBuffer.clear(); - this->d->m_rippleBuffer << QImage(src.size(), src.format()); - this->d->m_rippleBuffer[0].fill(qRgba(0, 0, 0, 0)); - this->d->m_rippleBuffer << QImage(src.size(), src.format()); - this->d->m_rippleBuffer[1].fill(qRgba(0, 0, 0, 0)); - this->d->m_curRippleBuffer = 0; - } else { - QImage drops; - - if (this->d->m_mode == RippleModeMotionDetect) - // Compute the difference between previous and current frame, - // and save it to the buffer. - drops = this->d->imageDiff(this->d->m_prevFrame, - src, - this->d->m_threshold, - this->d->m_lumaThreshold, - this->d->m_amplitude); - else - drops = this->d->rainDrop(src.width(), - src.height(), - this->d->m_amplitude); - - this->d->addDrops(this->d->m_rippleBuffer[this->d->m_curRippleBuffer], drops); - this->d->addDrops(this->d->m_rippleBuffer[1 - this->d->m_curRippleBuffer], drops); - - this->d->ripple(this->d->m_rippleBuffer[this->d->m_curRippleBuffer], - this->d->m_rippleBuffer[1 - this->d->m_curRippleBuffer], - this->d->m_decay); - - // Apply buffer. - oFrame = this->d->applyWater(src, - this->d->m_rippleBuffer[this->d->m_curRippleBuffer]); - this->d->m_curRippleBuffer = 1 - this->d->m_curRippleBuffer; - } - - this->d->m_prevFrame = src.copy(); - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_rippleelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Ripple/src/rippleelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Ripple/src/rippleelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Ripple/src/rippleelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Ripple/src/rippleelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -77,6 +77,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void modeChanged(const QString &mode); @@ -96,8 +97,6 @@ void resetDecay(); void resetThreshold(); void resetLumaThreshold(); - - AkPacket iStream(const AkPacket &packet); }; #endif // RIPPLEELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ScanLines/src/scanlineselement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/ScanLines/src/scanlineselement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ScanLines/src/scanlineselement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ScanLines/src/scanlineselement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include "scanlineselement.h" @@ -72,6 +73,40 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket ScanLinesElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + QImage oFrame(src.size(), src.format()); + + int showSize = this->d->m_showSize; + int hideSize = this->d->m_hideSize; + + if (showSize < 1 && hideSize < 1) + akSend(packet) + + for (int y = 0; y < src.height(); y++) { + for (int i = 0; i < showSize && y < src.height(); i++, y++) + memcpy(oFrame.scanLine(y), src.scanLine(y), size_t(src.bytesPerLine())); + + for (int j = 0; j < hideSize && y < src.height(); j++, y++) { + QRgb *line = reinterpret_cast(oFrame.scanLine(y)); + + for (int x = 0; x < src.width(); x++) + line[x] = this->d->m_hideColor; + } + + y--; + } + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void ScanLinesElement::setShowSize(int showSize) { if (this->d->m_showSize == showSize) @@ -114,39 +149,4 @@ this->setHideColor(qRgb(0, 0, 0)); } -AkPacket ScanLinesElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame(src.size(), src.format()); - - int showSize = this->d->m_showSize; - int hideSize = this->d->m_hideSize; - - if (showSize < 1 && hideSize < 1) - akSend(packet) - - for (int y = 0; y < src.height(); y++) { - for (int i = 0; i < showSize && y < src.height(); i++, y++) - memcpy(oFrame.scanLine(y), src.scanLine(y), size_t(src.bytesPerLine())); - - for (int j = 0; j < hideSize && y < src.height(); j++, y++) { - QRgb *line = reinterpret_cast(oFrame.scanLine(y)); - - for (int x = 0; x < src.width(); x++) - line[x] = this->d->m_hideColor; - } - - y--; - } - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - #include "moc_scanlineselement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/ScanLines/src/scanlineselement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/ScanLines/src/scanlineselement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/ScanLines/src/scanlineselement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/ScanLines/src/scanlineselement.h 2021-02-15 15:25:23.000000000 +0000 @@ -59,6 +59,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void showSizeChanged(int showSize); @@ -72,8 +73,6 @@ void resetShowSize(); void resetHideSize(); void resetHideColor(); - - AkPacket iStream(const AkPacket &packet); }; #endif // SCANLINESELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Scroll/src/scrollelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Scroll/src/scrollelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Scroll/src/scrollelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Scroll/src/scrollelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,9 +17,11 @@ * Web-Site: http://webcamoid.github.io/ */ -#include #include #include +#include +#include +#include #include #include "scrollelement.h" @@ -38,8 +40,6 @@ ScrollElement::ScrollElement(): AkElement() { this->d = new ScrollElementPrivate; - - qsrand(uint(QTime::currentTime().msec())); } ScrollElement::~ScrollElement() @@ -73,38 +73,9 @@ context->setContextProperty("controlId", this->objectName()); } -void ScrollElement::setSpeed(qreal speed) -{ - if (qFuzzyCompare(speed, this->d->m_speed)) - return; - - this->d->m_speed = speed; - emit this->speedChanged(speed); -} - -void ScrollElement::setNoise(qreal noise) -{ - if (qFuzzyCompare(this->d->m_noise, noise)) - return; - - this->d->m_noise = noise; - emit this->noiseChanged(noise); -} - -void ScrollElement::resetSpeed() +AkPacket ScrollElement::iVideoStream(const AkVideoPacket &packet) { - this->setSpeed(0.25); -} - -void ScrollElement::resetNoise() -{ - this->setNoise(0.1); -} - -AkPacket ScrollElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -140,22 +111,50 @@ else if (this->d->m_offset < 0.0) this->d->m_offset = src.height(); - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void ScrollElement::setSpeed(qreal speed) +{ + if (qFuzzyCompare(speed, this->d->m_speed)) + return; + + this->d->m_speed = speed; + emit this->speedChanged(speed); +} + +void ScrollElement::setNoise(qreal noise) +{ + if (qFuzzyCompare(this->d->m_noise, noise)) + return; + + this->d->m_noise = noise; + emit this->noiseChanged(noise); +} + +void ScrollElement::resetSpeed() +{ + this->setSpeed(0.25); +} + +void ScrollElement::resetNoise() +{ + this->setNoise(0.1); +} + QImage ScrollElementPrivate::generateNoise(const QSize &size, qreal persent) const { QImage noise(size, QImage::Format_ARGB32); noise.fill(0); - int peper = int(persent * size.width() * size.height()); + auto peper = qRound(persent * size.width() * size.height()); for (int i = 0; i < peper; i++) { - int gray = qrand() % 256; - int alpha = qrand() % 256; - int x = qrand() % noise.width(); - int y = qrand() % noise.height(); + int gray = QRandomGenerator::global()->bounded(256); + int alpha = QRandomGenerator::global()->bounded(256); + int x = QRandomGenerator::global()->bounded(noise.width()); + int y = QRandomGenerator::global()->bounded(noise.height()); noise.setPixel(x, y, qRgba(gray, gray, gray, alpha)); } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Scroll/src/scrollelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Scroll/src/scrollelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Scroll/src/scrollelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Scroll/src/scrollelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -52,6 +52,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void speedChanged(qreal speed); @@ -62,7 +63,6 @@ void setNoise(qreal noise); void resetSpeed(); void resetNoise(); - AkPacket iStream(const AkPacket &packet); }; #endif // SCROLLELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Shagadelic/src/shagadelicelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Shagadelic/src/shagadelicelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Shagadelic/src/shagadelicelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Shagadelic/src/shagadelicelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,7 +19,9 @@ #include #include +#include #include +#include #include #include "shagadelicelement.h" @@ -77,24 +79,9 @@ context->setContextProperty("controlId", this->objectName()); } -void ShagadelicElement::setMask(quint32 mask) -{ - if (this->d->m_mask == mask) - return; - - this->d->m_mask = mask; - emit this->maskChanged(mask); -} - -void ShagadelicElement::resetMask() -{ - this->setMask(0xffffff); -} - -AkPacket ShagadelicElement::iStream(const AkPacket &packet) +AkPacket ShagadelicElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -153,10 +140,24 @@ this->d->m_bx += this->d->m_bvx; this->d->m_by += this->d->m_bvy; - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void ShagadelicElement::setMask(quint32 mask) +{ + if (this->d->m_mask == mask) + return; + + this->d->m_mask = mask; + emit this->maskChanged(mask); +} + +void ShagadelicElement::resetMask() +{ + this->setMask(0xffffff); +} + QImage ShagadelicElementPrivate::makeRipple(const QSize &size) const { QImage ripple(2 * size, QImage::Format_Grayscale8); @@ -200,10 +201,10 @@ this->m_ripple = this->makeRipple(size); this->m_spiral = this->makeSpiral(size); - this->m_rx = qrand() % size.width(); - this->m_ry = qrand() % size.height(); - this->m_bx = qrand() % size.width(); - this->m_by = qrand() % size.height(); + this->m_rx = QRandomGenerator::global()->bounded(size.width()); + this->m_ry = QRandomGenerator::global()->bounded(size.height()); + this->m_bx = QRandomGenerator::global()->bounded(size.width()); + this->m_by = QRandomGenerator::global()->bounded(size.height()); this->m_rvx = -2; this->m_rvy = -2; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Shagadelic/src/shagadelicelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Shagadelic/src/shagadelicelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Shagadelic/src/shagadelicelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Shagadelic/src/shagadelicelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void maskChanged(quint32 mask); @@ -53,7 +54,6 @@ public slots: void setMask(quint32 mask); void resetMask(); - AkPacket iStream(const AkPacket &packet); }; #endif // SHAGADELICELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Swirl/src/swirlelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Swirl/src/swirlelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Swirl/src/swirlelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Swirl/src/swirlelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "swirlelement.h" @@ -61,24 +62,9 @@ context->setContextProperty("controlId", this->objectName()); } -void SwirlElement::setDegrees(qreal degrees) -{ - if (qFuzzyCompare(this->d->m_degrees, degrees)) - return; - - this->d->m_degrees = degrees; - emit this->degreesChanged(degrees); -} - -void SwirlElement::resetDegrees() -{ - this->setDegrees(60); -} - -AkPacket SwirlElement::iStream(const AkPacket &packet) +AkPacket SwirlElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -97,7 +83,7 @@ else if (src.width() < src.height()) xScale = qreal(src.height()) / src.width(); - qreal degrees = M_PI * this->d->m_degrees / 180.0; + auto degrees = qDegreesToRadians(this->d->m_degrees); for (int y = 0; y < src.height(); y++) { auto iLine = reinterpret_cast(src.constScanLine(y)); @@ -127,8 +113,22 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void SwirlElement::setDegrees(qreal degrees) +{ + if (qFuzzyCompare(this->d->m_degrees, degrees)) + return; + + this->d->m_degrees = degrees; + emit this->degreesChanged(degrees); +} + +void SwirlElement::resetDegrees() +{ + this->setDegrees(60); +} + #include "moc_swirlelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Swirl/src/swirlelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Swirl/src/swirlelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Swirl/src/swirlelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Swirl/src/swirlelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void degreesChanged(qreal degrees); @@ -53,7 +54,6 @@ public slots: void setDegrees(qreal degrees); void resetDegrees(); - AkPacket iStream(const AkPacket &packet); }; #endif // SWIRLELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Temperature/src/temperatureelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Temperature/src/temperatureelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Temperature/src/temperatureelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Temperature/src/temperatureelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -15,11 +15,39 @@ * along with Webcamoid. If not, see . * * Web-Site: http://webcamoid.github.io/ + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2012, Tanner Helland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include +#include #include #include "temperatureelement.h" @@ -73,28 +101,9 @@ context->setContextProperty("controlId", this->objectName()); } -void TemperatureElement::setTemperature(qreal temperature) -{ - if (qFuzzyCompare(this->d->m_temperature, temperature)) - return; - - this->d->m_temperature = temperature; - this->d->colorFromTemperature(temperature, - &this->d->m_kr, - &this->d->m_kg, - &this->d->m_kb); - emit this->temperatureChanged(temperature); -} - -void TemperatureElement::resetTemperature() -{ - this->setTemperature(6500); -} - -AkPacket TemperatureElement::iStream(const AkPacket &packet) +AkPacket TemperatureElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -103,8 +112,8 @@ QImage oFrame(src.size(), src.format()); for (int y = 0; y < src.height(); y++) { - const QRgb *srcLine = reinterpret_cast(src.constScanLine(y)); - QRgb *destLine = reinterpret_cast(oFrame.scanLine(y)); + auto srcLine = reinterpret_cast(src.constScanLine(y)); + auto destLine = reinterpret_cast(oFrame.scanLine(y)); for (int x = 0; x < src.width(); x++) { int r = int(this->d->m_kr * qRed(srcLine[x])); @@ -119,10 +128,28 @@ } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void TemperatureElement::setTemperature(qreal temperature) +{ + if (qFuzzyCompare(this->d->m_temperature, temperature)) + return; + + this->d->m_temperature = temperature; + this->d->colorFromTemperature(temperature, + &this->d->m_kr, + &this->d->m_kg, + &this->d->m_kb); + emit this->temperatureChanged(temperature); +} + +void TemperatureElement::resetTemperature() +{ + this->setTemperature(6500); +} + void TemperatureElementPrivate::colorFromTemperature(qreal temperature, qreal *r, qreal *g, diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Temperature/src/temperatureelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Temperature/src/temperatureelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Temperature/src/temperatureelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Temperature/src/temperatureelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -47,6 +47,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void temperatureChanged(qreal temperature); @@ -54,7 +55,6 @@ public slots: void setTemperature(qreal temperature); void resetTemperature(); - AkPacket iStream(const AkPacket &packet); }; #endif // TEMPERATUREELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/share/qml/main.qml webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/share/qml/main.qml --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/share/qml/main.qml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/share/qml/main.qml 2021-02-15 15:25:23.000000000 +0000 @@ -27,23 +27,19 @@ id: recCameraControls columns: 3 - property int lock: 0 - property int lockStreams: 0 - property var caps: [] - - function filterBy(prop, filters) + function filterBy(caps, prop, filters) { var vals = [] - for (var i in recCameraControls.caps) { - var videoCaps = recCameraControls.caps[i] - var caps = {fourcc: videoCaps.fourcc, - size: Qt.size(videoCaps.width, videoCaps.height), - fps: videoCaps.fps} + for (var i in caps) { + var videoCaps = caps[i] + var filterCaps = {fourcc: videoCaps.fourcc, + size: Qt.size(videoCaps.width, videoCaps.height), + fps: videoCaps.fps} var pass = false for (var filterProp in filters) - if (caps[filterProp] != filters[filterProp]) { + if (filterCaps[filterProp] != filters[filterProp]) { pass = true break @@ -52,7 +48,7 @@ if (pass) continue - var val = caps[prop] + var val = filterCaps[prop] if (vals.indexOf(val) < 0) vals.push(val) @@ -61,10 +57,35 @@ return vals } - function indexOf(caps) + function filterCaps(caps, filters) + { + for (var i in caps) { + var videoCaps = caps[i] + var filterCaps = {fourcc: videoCaps.fourcc, + size: Qt.size(videoCaps.width, videoCaps.height), + fps: videoCaps.fps} + var pass = false + + for (var filterProp in filters) + if (filterCaps[filterProp] != filters[filterProp]) { + pass = true + + break + } + + if (pass) + continue + + return i + } + + return -1 + } + + function indexOf(capsList, caps) { - for (var i in recCameraControls.caps) { - var videoCaps = recCameraControls.caps[i] + for (var i in capsList) { + var videoCaps = capsList[i] var size = Qt.size(videoCaps.width, videoCaps.height) if (videoCaps.fourcc == caps.fourcc @@ -103,22 +124,78 @@ return list.map(maps[prop]) } - function updateStreams() + function updateFormatControls(mediaChanged) { - if (lockStreams > 0) - return + cbxFormat.onCurrentIndexChanged.disconnect(cbxFormat.update) + cbxResolution.onCurrentIndexChanged.disconnect(cbxResolution.update) + cbxFps.onCurrentIndexChanged.disconnect(cbxFps.update) + + var ncaps = VideoCapture.listTracks().length + var rawCaps = [] + + for (var i = 0; i < ncaps; i++) + rawCaps.push(Ak.newCaps(VideoCapture.rawCaps(i)).toMap()) + + var index = mediaChanged || VideoCapture.streams.length < 1? + 0: VideoCapture.streams[0] + + if (index >= ncaps) + index = 0; + + var currentCaps = Ak.newCaps(VideoCapture.rawCaps(index)).toMap() + + var filters = {} + cbxFormat.model = createModel(filterBy(rawCaps, "fourcc", filters), + "fourcc") + filters.fourcc = currentCaps.fourcc + cbxResolution.model = createModel(filterBy(rawCaps, "size", filters), + "size") + filters.size = Qt.size(currentCaps.width, currentCaps.height) + cbxFps.model = createModel(filterBy(rawCaps, "fps", filters), "fps") + + cbxFormat.currentIndex = indexBy(cbxFormat.model, currentCaps.fourcc) + cbxResolution.currentIndex = indexBy(cbxResolution.model, + Qt.size(currentCaps.width, + currentCaps.height)) + cbxFps.currentIndex = indexBy(cbxFps.model, currentCaps.fps) + + cbxFormat.onCurrentIndexChanged.connect(cbxFormat.update) + cbxResolution.onCurrentIndexChanged.connect(cbxResolution.update) + cbxFps.onCurrentIndexChanged.connect(cbxFps.update) + } + + function updateStreams(filters) + { + var ncaps = VideoCapture.listTracks().length + var rawCaps = [] + + for (var i = 0; i < ncaps; i++) + rawCaps.push(Ak.newCaps(VideoCapture.rawCaps(i)).toMap()) + + var maps = { + fourcc: cbxFormat.model[cbxFormat.currentIndex]? + cbxFormat.model[cbxFormat.currentIndex].value: + cbxFormat.model[0].value, + size: cbxResolution.model[cbxResolution.currentIndex]? + cbxResolution.model[cbxResolution.currentIndex].value: + cbxResolution.model[0].value, + fps: cbxFps.model[cbxFps.currentIndex]? + cbxFps.model[cbxFps.currentIndex].value: + cbxFps.model[0].value + } + + var capsFilters = {} + + for (var i in filters) + capsFilters[filters[i]] = maps[filters[i]] - var index = indexOf({fourcc: cbxFormat.model[cbxFormat.currentIndex]? - cbxFormat.model[cbxFormat.currentIndex].value: "", - size: cbxResolution.model[cbxResolution.currentIndex]? - cbxResolution.model[cbxResolution.currentIndex].value: Qt.size(-1, -1), - fps: cbxFps.model[cbxFps.currentIndex]? - cbxFps.model[cbxFps.currentIndex].value: Ak.newFrac()}); + var index = filterCaps(rawCaps, capsFilters); if (index < 0) return VideoCapture.streams = [index] + updateFormatControls(false) } function createControls(controls, where) @@ -159,55 +236,46 @@ return [minimumLeftWidth, minimumRightWidth] } - function createInterface() + function createCameraControls() { - var minimumImageWidth = createControls(VideoCapture.imageControls(), clyImageControls) - var minimumCameraWidth = createControls(VideoCapture.cameraControls(), clyCameraControls) - - var minimumLeftWidth = Math.max(minimumImageWidth[0], minimumCameraWidth[0]) - var minimumRightWidth = Math.max(minimumImageWidth[1], minimumCameraWidth[1]) + var minimumImageWidth = + recCameraControls.createControls(VideoCapture.imageControls(), + clyImageControls) + var minimumCameraWidth = + recCameraControls.createControls(VideoCapture.cameraControls(), + clyCameraControls) + + var minimumLeftWidth = Math.max(minimumImageWidth[0], + minimumCameraWidth[0]) + var minimumRightWidth = Math.max(minimumImageWidth[1], + minimumCameraWidth[1]) var controls = [clyImageControls, clyCameraControls] for (var where in controls) for (var child in controls[where].children) { - controls[where].children[child].minimumLeftWidth = minimumLeftWidth - controls[where].children[child].minimumRightWidth = minimumRightWidth + controls[where].children[child].minimumLeftWidth = + minimumLeftWidth + controls[where].children[child].minimumRightWidth = + minimumRightWidth } lblFormat.minimumWidth = minimumLeftWidth btnReset.minimumWidth = minimumRightWidth - - var ncaps = VideoCapture.listTracks().length - var rawCaps = [] - - for (var i = 0; i < ncaps; i++) - rawCaps.push(Ak.newCaps(VideoCapture.rawCaps(i)).toMap()) - - caps = rawCaps - var index = VideoCapture.streams.length < 1? 0: VideoCapture.streams[0] - var currentCaps = Ak.newCaps(VideoCapture.rawCaps(index)).toMap() - - lock++ - lockStreams++; - cbxFormat.update() - cbxFormat.currentIndex = indexBy(cbxFormat.model, currentCaps.fourcc) - cbxResolution.update() - cbxResolution.currentIndex = indexBy(cbxResolution.model, - Qt.size(currentCaps.width, - currentCaps.height)) - cbxFps.update() - cbxFps.currentIndex = indexBy(cbxFps.model, currentCaps.fps) - lockStreams--; - lock--; } - Component.onCompleted: createInterface() + Component.onCompleted: { + createCameraControls() + updateFormatControls(false) + } Connections { target: VideoCapture - onMediaChanged: createInterface() + onMediaChanged: { + recCameraControls.createCameraControls() + recCameraControls.updateFormatControls(true) + } } Label { @@ -226,27 +294,8 @@ function update() { - lock++; - model = [] - model = createModel(filterBy("fourcc"), "fourcc") - currentIndex = -1 - - if (model.length > 0) - currentIndex = 0 - - lock--; + recCameraControls.updateStreams(["fourcc"]) } - - function lockedUpdate() - { - if (lock > 0) - return - - update() - } - - onCurrentIndexChanged: cbxResolution.lockedUpdate() - onModelChanged: cbxResolution.update() } Label { id: lblResolution @@ -264,31 +313,8 @@ function update() { - lock++; - model = [] - model = cbxFormat.model.length < 1? - []: createModel(filterBy("size", - {fourcc: cbxFormat.model[cbxFormat.currentIndex < 0? - 0: cbxFormat.currentIndex].value}), - "size") - currentIndex = -1 - - if (model.length > 0) - currentIndex = 0 - - lock--; - } - - function lockedUpdate() - { - if (lock > 0) - return - - update() + recCameraControls.updateStreams(["fourcc", "size"]) } - - onCurrentIndexChanged: cbxFps.lockedUpdate() - onModelChanged: cbxFps.update() } Label { id: lblFps @@ -306,34 +332,8 @@ function update() { - lock++; - model = [] - model = cbxResolution.model.length < 1? - []: createModel(filterBy("fps", - {fourcc: cbxFormat.model[cbxFormat.currentIndex < 0? - 0: cbxFormat.currentIndex].value, - size: cbxResolution.model[cbxResolution.currentIndex < 0? - 0: cbxResolution.currentIndex].value}), - "fps") - currentIndex = -1 - - if (model.length > 0) - currentIndex = 0 - - lock--; - - updateStreams() + recCameraControls.updateStreams(["fourcc", "size", "fps"]) } - - function lockedUpdate() - { - if (lock > 0) - return - - update() - } - - onCurrentIndexChanged: updateStreams() } Label { Layout.fillWidth: true @@ -349,7 +349,8 @@ onClicked: { VideoCapture.reset() - createInterface() + createCameraControls() + updateFormatControls(false) } } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/androidcamera.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/androidcamera.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/androidcamera.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/androidcamera.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,20 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +TEMPLATE = subdirs +SUBDIRS = jar src diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/jar/jar.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/jar/jar.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/jar/jar.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/jar/jar.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,45 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../../akcommons.pri) { + include(../../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +AK_PLUGIN = VideoCapture +AK_SUBMODULE = androidcamera + +TARGET = Ak$${AK_PLUGIN}_$${AK_SUBMODULE} + +CONFIG += java +DESTDIR = $${PWD}/../../../../../../StandAlone/share/android/libs + +JAVACLASSPATH += \ + src + +JAVASOURCES += \ + src/org/webcamoid/plugins/$${AK_PLUGIN}/submodules/$${AK_SUBMODULE}/AkAndroidCameraCallbacks.java + +# install +target.path = $${JARDIR} +INSTALLS += target diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/jar/src/org/webcamoid/plugins/VideoCapture/submodules/androidcamera/AkAndroidCameraCallbacks.java webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/jar/src/org/webcamoid/plugins/VideoCapture/submodules/androidcamera/AkAndroidCameraCallbacks.java --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/jar/src/org/webcamoid/plugins/VideoCapture/submodules/androidcamera/AkAndroidCameraCallbacks.java 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/jar/src/org/webcamoid/plugins/VideoCapture/submodules/androidcamera/AkAndroidCameraCallbacks.java 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,76 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +package org.webcamoid.plugins.VideoCapture.submodules.androidcamera; + +import android.hardware.Camera; +import android.view.SurfaceHolder; + +public class AkAndroidCameraCallbacks implements Camera.PreviewCallback, + SurfaceHolder.Callback +{ + private long m_userPtr = 0; + private byte[] m_lastPreviewBuffer = null; + + private AkAndroidCameraCallbacks(long userPtr) + { + m_userPtr = userPtr; + } + + // Camera.PreviewCallback + + @Override + public void onPreviewFrame(byte[] data, Camera camera) + { + // Re-enqueue the last buffer + if (m_lastPreviewBuffer != null) + camera.addCallbackBuffer(m_lastPreviewBuffer); + + m_lastPreviewBuffer = data; + + if (data != null) + previewFrameReady(m_userPtr, data); + } + + // SurfaceHolder.Callback + + @Override + public void surfaceChanged(SurfaceHolder holder, + int format, + int width, + int height) + { + } + + @Override + public void surfaceCreated(SurfaceHolder holder) + { + notifySurfaceCreated(m_userPtr); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) + { + notifySurfaceDestroyed(m_userPtr); + } + + private static native void previewFrameReady(long userPtr, byte[] data); + private static native void notifySurfaceCreated(long userPtr); + private static native void notifySurfaceDestroyed(long userPtr); +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/captureandroidcamera.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/captureandroidcamera.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/captureandroidcamera.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/captureandroidcamera.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,1475 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "captureandroidcamera.h" + +#define JNAMESPACE "org/webcamoid/plugins/VideoCapture/submodules/androidcamera" +#define JCLASS(jclass) JNAMESPACE "/" #jclass + +#define CAMERA_FACING_BACK 0 +#define CAMERA_FACING_FRONT 1 + +enum ImageFormat +{ + TRANSLUCENT = -3, + TRANSPARENT = -2, + OPAQUE = -1, + UNKNOWN = AK_FOURCC_NULL, + RGBA_8888 = 1, + RGBX_8888 = 2, + RGB_888 = 3, + RGB_565 = 4, + RGBA_5551 = 6, + RGBA_4444 = 7, + A_8 = 8, + L_8 = 9, + LA_88 = 10, + RGB_332 = 11, + NV16 = 16, + NV21 = 17, + YUY2 = 20, + RGBA_F16 = 22, + RAW_SENSOR = 32, + YUV_420_888 = 35, + PRIVATE = 34, + RAW_PRIVATE = 36, + RAW10 = 37, + RAW12 = 38, + YUV_422_888 = 39, + FLEX_RGB_888 = 41, + FLEX_RGBA_8888 = 42, + RGBA_1010102 = 43, + JPEG = 256, + DEPTH_POINT_CLOUD = 257, + Y8 = AkFourCCR('Y', '8', ' ', ' '), + YV12 = AkFourCCR('Y', 'V', '1', '2'), + DEPTH16 = AkFourCCR('Y', '1', '6', 'D'), + DEPTH_JPEG = AkFourCCR('c', 'i', 'e', 'i'), +}; + +using ImageFormatToStrMap = QMap; + +inline const ImageFormatToStrMap initImageFormatToStrMap() +{ + const ImageFormatToStrMap imgFmtToStrMap = { + {ImageFormat::TRANSLUCENT , "TRANSLUCENT" }, + {ImageFormat::TRANSPARENT , "TRANSPARENT" }, + {ImageFormat::OPAQUE , "OPAQUE" }, + {ImageFormat::UNKNOWN , "UNKNOWN" }, + {ImageFormat::RGBA_8888 , "RGBA" }, + {ImageFormat::RGBX_8888 , "RGBX" }, + {ImageFormat::RGB_888 , "RGB" }, + {ImageFormat::RGB_565 , "RGB565" }, + {ImageFormat::RGBA_5551 , "RGB555" }, + {ImageFormat::RGBA_4444 , "RGBA4444" }, + {ImageFormat::A_8 , "GRAY8" }, + {ImageFormat::L_8 , "GRAY8" }, + {ImageFormat::LA_88 , "GRAYA8" }, + {ImageFormat::RGB_332 , "RGB332" }, + {ImageFormat::NV16 , "NV16" }, + {ImageFormat::NV21 , "NV21" }, + {ImageFormat::YUY2 , "YUY2" }, + {ImageFormat::RGBA_F16 , "RGBAF16" }, + {ImageFormat::RAW_SENSOR , "RAW_SENSOR" }, + {ImageFormat::YUV_420_888 , "YU12" }, + {ImageFormat::PRIVATE , "PRIVATE" }, + {ImageFormat::RAW_PRIVATE , "RAW_PRIVATE" }, + {ImageFormat::RAW10 , "SGRBG10" }, + {ImageFormat::RAW12 , "SGRBG12" }, + {ImageFormat::YUV_422_888 , "YUV422P" }, + {ImageFormat::FLEX_RGB_888 , "FLEX_RGB_888" }, + {ImageFormat::FLEX_RGBA_8888 , "FLEX_RGBA_8888" }, + {ImageFormat::RGBA_1010102 , "RGBA_1010102" }, + {ImageFormat::JPEG , "JPEG" }, + {ImageFormat::DEPTH_POINT_CLOUD, "DEPTH_POINT_CLOUD"}, + {ImageFormat::Y8 , "GRAY8" }, + {ImageFormat::YV12 , "YV12" }, + {ImageFormat::DEPTH16 , "DEPTH16" }, + {ImageFormat::DEPTH_JPEG , "DEPTH_JPEG" }, + }; + + return imgFmtToStrMap; +} + +Q_GLOBAL_STATIC_WITH_ARGS(ImageFormatToStrMap, imgFmtToStrMap, (initImageFormatToStrMap())) + +enum ControlType +{ + Integer, + Boolean, + Menu, + Zoom +}; + +struct Control +{ + ControlType type; + QString name; + QString description; + QVariant defaultValue; +}; + +using ControlVector = QVector; + +inline const ControlVector &initImageControls() +{ + static const ControlVector controls { + {ControlType::Menu , "SceneMode/s", "Scene Mode", "auto"}, + {ControlType::Boolean, "AutoWhiteBalanceLock", "Auto White Balance Lock", true}, + {ControlType::Menu , "WhiteBalance", "White Balance", "auto"}, + {ControlType::Boolean, "AutoExposureLock", "Auto Exposure Lock", true}, + {ControlType::Integer, "ExposureCompensation", "Exposure Compensation", 0}, + {ControlType::Menu , "Antibanding", "Antibanding", "auto"}, + {ControlType::Boolean, "VideoStabilization", "Video Stabilization", true}, + {ControlType::Menu , "ColorEffect/s", "Color Effect", "none"}, + }; + + return controls; +} + +Q_GLOBAL_STATIC_WITH_ARGS(ControlVector, globalImageControls, (initImageControls())) + +inline const ControlVector &initCameraControls() +{ + static const ControlVector controls { + {ControlType::Menu, "FlashMode/s", "Flash Mode", "auto"}, + {ControlType::Menu, "FocusMode/s", "Focus Mode", "auto"}, + {ControlType::Zoom, {}, {}, 0}, + }; + + return controls; +} + +Q_GLOBAL_STATIC_WITH_ARGS(ControlVector, globalCameraControls, (initCameraControls())) + +class CaptureAndroidCameraPrivate +{ + public: + CaptureAndroidCamera *self; + QString m_device; + QList m_streams; + QStringList m_devices; + QMap m_descriptions; + QMap m_devicesCaps; + QMutex m_controlsMutex; + QVariantList m_globalImageControls; + QVariantList m_globalCameraControls; + QVariantMap m_localImageControls; + QVariantMap m_localCameraControls; + QMutex m_mutex; + QByteArray m_curBuffer; + QWaitCondition m_waitCondition; + AkFrac m_fps; + AkFrac m_timeBase; + AkCaps m_caps; + qint64 m_id {-1}; + QAndroidJniObject m_camera; + QAndroidJniObject m_callbacks; + QAndroidJniObject m_surfaceView; + + explicit CaptureAndroidCameraPrivate(CaptureAndroidCamera *self); + void registerNatives(); + QVariantList caps(jint device); + jint deviceId(const QString &device) const; + bool nearestFpsRangue(const QAndroidJniObject ¶meters, + const AkFrac &fps, + jint &min, + jint &max); + QVariantList controlBoolean(const QAndroidJniObject ¶meters, + const QString &name, + const QString &description, + bool defaultValue=false) const; + bool setControlBoolean(QAndroidJniObject ¶meters, + const QString &name, + bool value) const; + QVariantList controlMenu(const QAndroidJniObject ¶meters, + const QString &name, + const QString &description, + const QString &defaultValue={}) const; + bool setControlMenu(QAndroidJniObject ¶meters, + const QString &name, + int index) const; + QVariantList controlInteger(const QAndroidJniObject ¶meters, + const QString &name, + const QString &description, + int defaultValue=0) const; + bool setControlInteger(QAndroidJniObject ¶meters, + const QString &name, + int value) const; + QVariantList controlZoom(const QAndroidJniObject ¶meters, + int defaultValue=0) const; + bool setControlZoom(QAndroidJniObject ¶meters, + int value) const; + QVariantList controls(const QAndroidJniObject ¶meters, + const ControlVector &controls) const; + bool setControls(QAndroidJniObject ¶meters, + const ControlVector &controls, + const QVariantMap &values); + QVariantList imageControls(const QAndroidJniObject ¶meters) const; + bool setImageControls(QAndroidJniObject ¶meters, + const QVariantMap &imageControls); + QVariantList cameraControls(const QAndroidJniObject ¶meters) const; + bool setCameraControls(QAndroidJniObject ¶meters, + const QVariantMap &cameraControls); + QVariantMap controlStatus(const QVariantList &controls) const; + QVariantMap mapDiff(const QVariantMap &map1, + const QVariantMap &map2) const; + static void previewFrameReady(JNIEnv *env, + jobject obj, + jlong userPtr, + jbyteArray data); + static void surfaceCreated(JNIEnv *env, jobject obj, jlong userPtr); + static void surfaceDestroyed(JNIEnv *env, jobject obj, jlong userPtr); + static bool canUseCamera(); + void updateDevices(); +}; + +CaptureAndroidCamera::CaptureAndroidCamera(QObject *parent): + Capture(parent) +{ + this->d = new CaptureAndroidCameraPrivate(this); + this->d->updateDevices(); +} + +CaptureAndroidCamera::~CaptureAndroidCamera() +{ + delete this->d; +} + +QStringList CaptureAndroidCamera::webcams() const +{ + return this->d->m_devices; +} + +QString CaptureAndroidCamera::device() const +{ + return this->d->m_device; +} + +QList CaptureAndroidCamera::streams() +{ + if (!this->d->m_streams.isEmpty()) + return this->d->m_streams; + + auto caps = this->caps(this->d->m_device); + + if (caps.isEmpty()) + return {}; + + return {0}; +} + +QList CaptureAndroidCamera::listTracks(const QString &mimeType) +{ + if (mimeType != "video/x-raw" + && !mimeType.isEmpty()) + return {}; + + auto caps = this->caps(this->d->m_device); + QList streams; + + for (int i = 0; i < caps.count(); i++) + streams << i; + + return streams; +} + +QString CaptureAndroidCamera::ioMethod() const +{ + return {}; +} + +int CaptureAndroidCamera::nBuffers() const +{ + return 0; +} + +QString CaptureAndroidCamera::description(const QString &webcam) const +{ + return this->d->m_descriptions.value(webcam); +} + +QVariantList CaptureAndroidCamera::caps(const QString &webcam) const +{ + return this->d->m_devicesCaps.value(webcam); +} + +QString CaptureAndroidCamera::capsDescription(const AkCaps &caps) const +{ + if (caps.mimeType() != "video/unknown") + return {}; + + AkFrac fps = caps.property("fps").toString(); + + return QString("%1, %2x%3, %4 FPS") + .arg(caps.property("fourcc").toString(), + caps.property("width").toString(), + caps.property("height").toString()) + .arg(qRound(fps.value())); +} + +QVariantList CaptureAndroidCamera::imageControls() const +{ + return this->d->m_globalImageControls; +} + +bool CaptureAndroidCamera::setImageControls(const QVariantMap &imageControls) +{ + this->d->m_controlsMutex.lock(); + auto globalImageControls = this->d->m_globalImageControls; + this->d->m_controlsMutex.unlock(); + + for (int i = 0; i < globalImageControls.count(); i++) { + auto control = globalImageControls[i].toList(); + auto controlName = control[0].toString(); + + if (imageControls.contains(controlName)) { + control[6] = imageControls[controlName]; + globalImageControls[i] = control; + } + } + + this->d->m_controlsMutex.lock(); + + if (this->d->m_globalImageControls == globalImageControls) { + this->d->m_controlsMutex.unlock(); + + return false; + } + + this->d->m_globalImageControls = globalImageControls; + this->d->m_controlsMutex.unlock(); + + emit this->imageControlsChanged(imageControls); + + return true; +} + +bool CaptureAndroidCamera::resetImageControls() +{ + QVariantMap controls; + + for (auto &control: this->imageControls()) { + auto params = control.toList(); + controls[params[0].toString()] = params[5].toInt(); + } + + return this->setImageControls(controls); +} + +QVariantList CaptureAndroidCamera::cameraControls() const +{ + return this->d->m_globalCameraControls; +} + +bool CaptureAndroidCamera::setCameraControls(const QVariantMap &cameraControls) +{ + this->d->m_controlsMutex.lock(); + auto globalCameraControls = this->d->m_globalCameraControls; + this->d->m_controlsMutex.unlock(); + + for (int i = 0; i < globalCameraControls.count(); i++) { + auto control = globalCameraControls[i].toList(); + auto controlName = control[0].toString(); + + if (cameraControls.contains(controlName)) { + control[6] = cameraControls[controlName]; + globalCameraControls[i] = control; + } + } + + this->d->m_controlsMutex.lock(); + + if (this->d->m_globalCameraControls == globalCameraControls) { + this->d->m_controlsMutex.unlock(); + + return false; + } + + this->d->m_globalCameraControls = globalCameraControls; + this->d->m_controlsMutex.unlock(); + emit this->cameraControlsChanged(cameraControls); + + return true; +} + +bool CaptureAndroidCamera::resetCameraControls() +{ + QVariantMap controls; + + for (auto &control: this->cameraControls()) { + auto params = control.toList(); + controls[params[0].toString()] = params[5].toInt(); + } + + return this->setCameraControls(controls); +} + +AkPacket CaptureAndroidCamera::readFrame() +{ + if (this->d->m_camera.isValid()) { + auto parameters = + this->d->m_camera.callObjectMethod("getParameters", + "()Landroid/hardware/Camera$Parameters;"); + + if (parameters.isValid()) { + this->d->m_controlsMutex.lock(); + auto imageControls = this->d->controlStatus(this->d->m_globalImageControls); + this->d->m_controlsMutex.unlock(); + bool apply = false; + + if (this->d->m_localImageControls != imageControls) { + auto controls = this->d->mapDiff(this->d->m_localImageControls, + imageControls); + apply |= this->d->setImageControls(parameters, controls); + this->d->m_localImageControls = imageControls; + } + + this->d->m_controlsMutex.lock(); + auto cameraControls = this->d->controlStatus(this->d->m_globalCameraControls); + this->d->m_controlsMutex.unlock(); + + if (this->d->m_localCameraControls != cameraControls) { + auto controls = this->d->mapDiff(this->d->m_localCameraControls, + cameraControls); + apply |= this->d->setCameraControls(parameters, controls); + this->d->m_localCameraControls = cameraControls; + } + + if (apply) + this->d->m_camera.callMethod("setParameters", + "(Landroid/hardware/Camera$Parameters;)V", + parameters.object()); + } + } + + AkPacket packet; + auto timestamp = QDateTime::currentMSecsSinceEpoch(); + auto pts = + qint64(timestamp + * this->d->m_timeBase.invert().value() + / 1e3); + + this->d->m_mutex.lock(); + + if (this->d->m_curBuffer.isEmpty()) + this->d->m_waitCondition.wait(&this->d->m_mutex, 1000); + + if (!this->d->m_curBuffer.isEmpty()) { + int bufferSize = this->d->m_curBuffer.size(); + QByteArray oBuffer(bufferSize, 0); + memcpy(oBuffer.data(), + this->d->m_curBuffer.constData(), + size_t(bufferSize)); + + packet = AkPacket(this->d->m_caps); + packet.setBuffer(oBuffer); + packet.setPts(pts); + packet.setTimeBase(this->d->m_timeBase); + packet.setIndex(0); + packet.setId(this->d->m_id); + this->d->m_curBuffer.clear(); + } + + this->d->m_mutex.unlock(); + + return packet; +} + +CaptureAndroidCameraPrivate::CaptureAndroidCameraPrivate(CaptureAndroidCamera *self): + self(self) +{ + this->registerNatives(); + this->m_callbacks = + QAndroidJniObject(JCLASS(AkAndroidCameraCallbacks), + "(J)V", + this); +} + +void CaptureAndroidCameraPrivate::registerNatives() +{ + static bool ready = false; + + if (ready) + return; + + QAndroidJniEnvironment jenv; + + if (auto jclass = jenv.findClass(JCLASS(AkAndroidCameraCallbacks))) { + QVector methods { + {"previewFrameReady" , "(J[B)V", reinterpret_cast(CaptureAndroidCameraPrivate::previewFrameReady)}, + {"notifySurfaceCreated" , "(J)V" , reinterpret_cast(CaptureAndroidCameraPrivate::surfaceCreated) }, + {"notifySurfaceDestroyed", "(J)V" , reinterpret_cast(CaptureAndroidCameraPrivate::surfaceDestroyed) }, + }; + + jenv->RegisterNatives(jclass, methods.data(), methods.size()); + } + + ready = true; +} + +QVariantList CaptureAndroidCameraPrivate::caps(jint device) +{ + auto camera = + QAndroidJniObject::callStaticObjectMethod("android/hardware/Camera", + "open", + "(I)Landroid/hardware/Camera;", + device); + + if (!camera.isValid()) + return {}; + + auto parameters = + camera.callObjectMethod("getParameters", + "()Landroid/hardware/Camera$Parameters;"); + + if (!parameters.isValid()) + return {}; + + QSet supportedFormats; + auto formats = parameters.callObjectMethod("getSupportedPreviewFormats", + "()Ljava/util/List;"); + auto numFormats = formats.callMethod("size"); + + for (jint i = 0; i < numFormats; i++) { + auto jformat = formats.callObjectMethod("get", + "(I)Ljava/lang/Object;", + i); + auto format = jformat.callMethod("intValue"); + + if (!imgFmtToStrMap->contains(ImageFormat(format))) + continue; + + supportedFormats << ImageFormat(format); + } + + QList supportedSizes; + auto sizes = parameters.callObjectMethod("getSupportedPreviewSizes", + "()Ljava/util/List;"); + auto numSizes = sizes.callMethod("size"); + + for (jint i = 0; i < numSizes; i++) { + auto jsize = sizes.callObjectMethod("get", + "(I)Ljava/lang/Object;", + i); + auto width = jsize.getField("width"); + auto height = jsize.getField("height"); + + if (width < 1 || height < 1) + continue; + + QSize size(width, height); + + if (!supportedSizes.contains(size)) + supportedSizes << size; + } + + QList supportedFrameRates; + auto frameRates = parameters.callObjectMethod("getSupportedPreviewFpsRange", + "()Ljava/util/List;"); + auto numFps = frameRates.callMethod("size"); + QAndroidJniEnvironment jenv; + + for (jint i = 0; i < numFps; i++) { + auto jfpsRange = frameRates.callObjectMethod("get", + "(I)Ljava/lang/Object;", + i); + auto jrange = static_cast(jfpsRange.object()); + auto range = jenv->GetIntArrayElements(jrange, nullptr); + AkFrac fps(range[0] + range[1], 2000); + + if (!supportedFrameRates.contains(fps)) + supportedFrameRates << fps; + + jenv->ReleaseIntArrayElements(jrange, range, 0); + } + + camera.callMethod("release"); + QVariantList caps; + + for (auto &format: supportedFormats) + for (auto &size: supportedSizes) + for (auto &fps: supportedFrameRates) { + AkCaps videoCaps; + videoCaps.setMimeType("video/unknown"); + videoCaps.setProperty("fourcc", imgFmtToStrMap->value(ImageFormat(format))); + videoCaps.setProperty("width", size.width()); + videoCaps.setProperty("height", size.height()); + videoCaps.setProperty("fps", fps.toString()); + caps << QVariant::fromValue(videoCaps); + } + + return caps; +} + +jint CaptureAndroidCameraPrivate::deviceId(const QString &device) const +{ + auto idStr = device; + bool ok = false; + int id = idStr.remove("/dev/video").toInt(&ok); + + return ok? id: -1; +} + +bool CaptureAndroidCameraPrivate::nearestFpsRangue(const QAndroidJniObject ¶meters, + const AkFrac &fps, + jint &min, + jint &max) +{ + QAndroidJniEnvironment jenv; + auto frameRates = parameters.callObjectMethod("getSupportedPreviewFpsRange", + "()Ljava/util/List;"); + auto numFps = frameRates.callMethod("size"); + auto fpsValue = fps.value(); + bool ok = false; + min = 0; + max = 0; + + for (jint i = 0; i < numFps; i++) { + auto jfpsRange = frameRates.callObjectMethod("get", + "(I)Ljava/lang/Object;", + i); + auto jrange = static_cast(jfpsRange.object()); + auto range = jenv->GetIntArrayElements(jrange, nullptr); + + if (1e3 * fpsValue >= qreal(range[0]) + && 1e3 * fpsValue <= qreal(range[1])) { + min = range[0]; + max = range[1]; + ok = true; + } + + jenv->ReleaseIntArrayElements(jrange, range, 0); + + if (ok) + break; + } + + return ok; +} + +QVariantList CaptureAndroidCameraPrivate::controlBoolean(const QAndroidJniObject ¶meters, + const QString &name, + const QString &description, + bool defaultValue) const +{ + auto supported = + parameters.callMethod(QString("is%1Supported") + .arg(name) + .toStdString() + .c_str()); + + if (!supported) + return {}; + + auto value = parameters.callMethod(QString("get%1") + .arg(name) + .toStdString() + .c_str()); + + return QVariantList { + description, + "boolean", + 0, + 1, + 1, + defaultValue, + value, + QStringList() + }; +} + +bool CaptureAndroidCameraPrivate::setControlBoolean(QAndroidJniObject ¶meters, + const QString &name, + bool value) const +{ + auto supported = + parameters.callMethod(QString("is%1Supported") + .arg(name) + .toStdString() + .c_str()); + + if (!supported) + return false; + + parameters.callMethod(QString("set%1") + .arg(name) + .toStdString() + .c_str(), + "(Z)V", + value); + + return true; +} + +QVariantList CaptureAndroidCameraPrivate::controlMenu(const QAndroidJniObject ¶meters, + const QString &name, + const QString &description, + const QString &defaultValue) const +{ + auto optionName = name; + auto opt = name; + + if (optionName.endsWith("/s")) { + optionName = optionName.left(optionName.size() - 2); + opt = optionName + 's'; + } + + auto options = + parameters.callObjectMethod(QString("getSupported%1") + .arg(opt) + .toStdString() + .c_str(), + "()Ljava/util/List;"); + + if (!options.isValid()) + return {}; + + auto numOptions = options.callMethod("size"); + + if (numOptions < 2) + return {}; + + QStringList menuOptions; + + for (jint i = 0; i < numOptions; i++) { + auto joption = options.callObjectMethod("get", + "(I)Ljava/lang/Object;", + i); + auto option = joption.toString(); + + if (!menuOptions.contains(option)) + menuOptions << option; + } + + auto value = parameters.callObjectMethod(QString("get%1") + .arg(optionName) + .toStdString() + .c_str(), + "()Ljava/lang/String;").toString(); + + return QVariantList { + description, + "menu", + 0, + menuOptions.size() - 1, + 1, + qMax(menuOptions.indexOf(defaultValue), 0), + qMax(menuOptions.indexOf(value), 0), + menuOptions + }; +} + +bool CaptureAndroidCameraPrivate::setControlMenu(QAndroidJniObject ¶meters, + const QString &name, + int index) const +{ + if (index < 0) + return false; + + auto optionName = name; + auto opt = name; + + if (optionName.endsWith("/s")) { + optionName = optionName.left(optionName.size() - 2); + opt = optionName + 's'; + } + + auto options = + parameters.callObjectMethod(QString("getSupported%1") + .arg(opt) + .toStdString() + .c_str(), + "()Ljava/util/List;"); + + if (!options.isValid()) + return false; + + auto numOptions = options.callMethod("size"); + + if (numOptions < 2 || index >= numOptions) + return false; + + auto joption = options.callObjectMethod("get", + "(I)Ljava/lang/Object;", + index); + parameters.callMethod(QString("set%1") + .arg(optionName) + .toStdString() + .c_str(), + "(Ljava/lang/String;)V", + joption.object()); + + return true; +} + +QVariantList CaptureAndroidCameraPrivate::controlInteger(const QAndroidJniObject ¶meters, + const QString &name, + const QString &description, + int defaultValue) const +{ + auto min = parameters.callMethod(QString("getMin%1") + .arg(name) + .toStdString() + .c_str()); + auto max = parameters.callMethod(QString("getMax%1") + .arg(name) + .toStdString() + .c_str()); + + if (min == max) + return {}; + + auto value = parameters.callMethod(QString("get%1") + .arg(name) + .toStdString() + .c_str()); + auto step = parameters.callMethod(QString("get%1Step") + .arg(name) + .toStdString() + .c_str()); + + return QVariantList { + description, + "integer", + int(min / step), + int(max / step), + 1, + int(qBound(min, defaultValue, max) / step), + int(qBound(min, value, max) / step), + QStringList() + }; +} + +bool CaptureAndroidCameraPrivate::setControlInteger(QAndroidJniObject ¶meters, + const QString &name, + int value) const +{ + auto min = parameters.callMethod(QString("getMin%1") + .arg(name) + .toStdString() + .c_str()); + auto max = parameters.callMethod(QString("getMax%1") + .arg(name) + .toStdString() + .c_str()); + + if (min == max) + return false; + + parameters.callMethod(QString("set%1") + .arg(name) + .toStdString() + .c_str(), + "(I)V", + value); + + return true; +} + +QVariantList CaptureAndroidCameraPrivate::controlZoom(const QAndroidJniObject ¶meters, + int defaultValue) const +{ + auto supported = parameters.callMethod("isZoomSupported"); + + if (!supported) + return {}; + + auto smooth = parameters.callMethod("isSmoothZoomSupported"); + auto value = parameters.callMethod("getZoom"); + + if (smooth) { + auto max = parameters.callMethod("getMaxZoom"); + + if (max == 0) + return {}; + + return QVariantList { + "Zoom", + "integer", + 0, + max, + 1, + qBound(0, defaultValue, max), + qBound(0, value, max), + QStringList() + }; + } + + auto options = + parameters.callObjectMethod("getZoomRatios", + "()Ljava/util/List;"); + + if (!options.isValid()) + return {}; + + auto numOptions = options.callMethod("size"); + + if (numOptions < 2) + return {}; + + QStringList menuOptions; + + for (jint i = 0; i < numOptions; i++) { + auto joption = options.callObjectMethod("get", + "(I)Ljava/lang/Object;", + i); + auto option = joption.callMethod("intValue"); + auto optionStr = QString("%1").arg(option); + + if (!menuOptions.contains(optionStr)) + menuOptions << optionStr; + } + + return QVariantList { + "Zoom", + "menu", + 0, + menuOptions.size() - 1, + 1, + qMax(menuOptions.indexOf(QString("%1").arg(defaultValue)), 0), + qMax(menuOptions.indexOf(QString("%1").arg(value)), 0), + menuOptions + }; +} + +bool CaptureAndroidCameraPrivate::setControlZoom(QAndroidJniObject ¶meters, + int value) const +{ + auto supported = parameters.callMethod("isZoomSupported"); + + if (!supported) + return false; + + parameters.callMethod("setZoom", "(I)V", value); + + return true; +} + +QVariantList CaptureAndroidCameraPrivate::controls(const QAndroidJniObject ¶meters, + const ControlVector &controls) const +{ + QVariantList controlsList; + + for (auto &control: controls) { + QVariantList params; + + switch (control.type) { + case ControlType::Integer: + params = this->controlInteger(parameters, + control.name, + control.description, + control.defaultValue.toInt()); + break; + + case ControlType::Boolean: + params = this->controlBoolean(parameters, + control.name, + control.description, + control.defaultValue.toBool()); + break; + + case ControlType::Menu: + params = this->controlMenu(parameters, + control.name, + control.description, + control.defaultValue.toString()); + break; + + case ControlType::Zoom: + params = this->controlZoom(parameters, + control.defaultValue.toInt()); + break; + } + + if (!params.isEmpty()) + controlsList << QVariant(params); + } + + return controlsList; +} + +bool CaptureAndroidCameraPrivate::setControls(QAndroidJniObject ¶meters, + const ControlVector &controls, + const QVariantMap &values) +{ + bool ok = true; + + for (auto &control: controls) { + if (!values.contains(control.description)) + continue; + + int value = values.value(control.description).toInt(); + + switch (control.type) { + case ControlType::Integer: + ok &= this->setControlInteger(parameters, control.name, value); + break; + + case ControlType::Boolean: + ok &= this->setControlBoolean(parameters, control.name, value); + break; + + case ControlType::Menu: + ok &= this->setControlMenu(parameters, control.name, value); + break; + + case ControlType::Zoom: + ok &= this->setControlZoom(parameters, value); + break; + } + } + + return ok; +} + +QVariantList CaptureAndroidCameraPrivate::imageControls(const QAndroidJniObject ¶meters) const +{ + return this->controls(parameters, *globalImageControls); +} + +bool CaptureAndroidCameraPrivate::setImageControls(QAndroidJniObject ¶meters, + const QVariantMap &imageControls) +{ + return this->setControls(parameters, *globalImageControls, imageControls); +} + +QVariantList CaptureAndroidCameraPrivate::cameraControls(const QAndroidJniObject ¶meters) const +{ + return this->controls(parameters, *globalCameraControls); +} + +bool CaptureAndroidCameraPrivate::setCameraControls(QAndroidJniObject ¶meters, + const QVariantMap &cameraControls) +{ + return this->setControls(parameters, *globalCameraControls, cameraControls); +} + +QVariantMap CaptureAndroidCameraPrivate::controlStatus(const QVariantList &controls) const +{ + QVariantMap controlStatus; + + for (auto &control: controls) { + auto params = control.toList(); + auto controlName = params[0].toString(); + controlStatus[controlName] = params[6]; + } + + return controlStatus; +} + +QVariantMap CaptureAndroidCameraPrivate::mapDiff(const QVariantMap &map1, + const QVariantMap &map2) const +{ + QVariantMap map; + + for (auto it = map2.cbegin(); it != map2.cend(); it++) + if (!map1.contains(it.key()) + || map1[it.key()] != it.value()) { + map[it.key()] = it.value(); + } + + return map; +} + +void CaptureAndroidCameraPrivate::previewFrameReady(JNIEnv *env, + jobject obj, + jlong userPtr, + jbyteArray data) +{ + Q_UNUSED(obj) + auto dataSize = env->GetArrayLength(data); + + if (dataSize < 1) + return; + + QByteArray buffer(dataSize, Qt::Uninitialized); + env->GetByteArrayRegion(data, + 0, + dataSize, + reinterpret_cast(buffer.data())); + auto self = reinterpret_cast(userPtr); + + self->m_mutex.lock(); + self->m_curBuffer = buffer; + self->m_waitCondition.wakeAll(); + self->m_mutex.unlock(); +} + +void CaptureAndroidCameraPrivate::surfaceCreated(JNIEnv *env, + jobject obj, + jlong userPtr) +{ + Q_UNUSED(env) + Q_UNUSED(obj) + Q_UNUSED(userPtr) +} + +void CaptureAndroidCameraPrivate::surfaceDestroyed(JNIEnv *env, + jobject obj, + jlong userPtr) +{ + Q_UNUSED(env) + Q_UNUSED(obj) + Q_UNUSED(userPtr) +} + +bool CaptureAndroidCameraPrivate::canUseCamera() +{ + static bool done = false; + static bool result = false; + + if (done) + return result; + + QStringList permissions { + "android.permission.CAMERA" + }; + QStringList neededPermissions; + + for (auto &permission: permissions) + if (QtAndroid::checkPermission(permission) == QtAndroid::PermissionResult::Denied) + neededPermissions << permission; + + if (!neededPermissions.isEmpty()) { + auto results = QtAndroid::requestPermissionsSync(neededPermissions); + + for (auto it = results.constBegin(); it != results.constEnd(); it++) + if (it.value() == QtAndroid::PermissionResult::Denied) { + done = true; + + return false; + } + } + + done = true; + result = true; + + return true; +} + +void CaptureAndroidCameraPrivate::updateDevices() +{ + if (!this->canUseCamera()) + return; + + decltype(this->m_devices) devices; + decltype(this->m_descriptions) descriptions; + decltype(this->m_devicesCaps) devicesCaps; + + auto numCameras = + QAndroidJniObject::callStaticMethod("android/hardware/Camera", + "getNumberOfCameras"); + + for (jint i = 0; i < numCameras; i++) { + auto caps = this->caps(i); + + if (!caps.empty()) { + auto deviceId = QString("/dev/video%1").arg(i); + QAndroidJniObject cameraInfo("android/hardware/Camera$CameraInfo"); + QAndroidJniObject::callStaticMethod("android/hardware/Camera", + "getCameraInfo", + "(ILandroid/hardware/Camera$CameraInfo;)V", + i, + cameraInfo.object()); + auto facing = cameraInfo.getField("facing"); + auto description = QString("%1 Camera %2") + .arg(facing == CAMERA_FACING_BACK? "Back": "Front") + .arg(i); + + devices << deviceId; + descriptions[deviceId] = description; + devicesCaps[deviceId] = caps; + } + } + + if (devicesCaps.isEmpty()) { + devices.clear(); + descriptions.clear(); + } + + this->m_descriptions = descriptions; + this->m_devicesCaps = devicesCaps; + + if (this->m_devices != devices) { + this->m_devices = devices; + emit self->webcamsChanged(this->m_devices); + } +} + +bool CaptureAndroidCamera::init() +{ + this->d->m_localImageControls.clear(); + this->d->m_localCameraControls.clear(); + this->uninit(); + + QAndroidJniObject surfaceHolder; + QList streams; + QVariantList supportedCaps; + AkCaps caps; + QAndroidJniObject parameters; + jint min = 0; + jint max = 0; + AkFrac fps; + + this->d->m_camera = + QAndroidJniObject::callStaticObjectMethod("android/hardware/Camera", + "open", + "(I)Landroid/hardware/Camera;", + this->d->deviceId(this->d->m_device)); + + if (!this->d->m_camera.isValid()) + goto init_failed; + + QtAndroid::runOnAndroidThreadSync([this] { + this->d->m_surfaceView = + QAndroidJniObject("android/view/SurfaceView", + "(Landroid/content/Context;)V", + QtAndroid::androidActivity().object()); + auto window = QWindow::fromWinId(WId(this->d->m_surfaceView.object())); + window->setVisible(true); + window->setGeometry(0, 0, 0, 0); + }); + + if (!this->d->m_surfaceView.isValid()) + goto init_failed; + + surfaceHolder = + this->d->m_surfaceView.callObjectMethod("getHolder", + "()Landroid/view/SurfaceHolder;"); + + if (!surfaceHolder.isValid()) + goto init_failed; + + QThread::sleep(1); + + this->d->m_camera.callMethod("setPreviewDisplay", + "(Landroid/view/SurfaceHolder;)V", + surfaceHolder.object()); + surfaceHolder.callMethod("addCallback", + "(Landroid/view/SurfaceHolder$Callback;)V", + this->d->m_callbacks.object()); + this->d->m_camera.callMethod("setPreviewCallback", + "(Landroid/hardware/Camera$PreviewCallback;)V", + this->d->m_callbacks.object()); + parameters = + this->d->m_camera.callObjectMethod("getParameters", + "()Landroid/hardware/Camera$Parameters;"); + + if (!parameters.isValid()) + goto init_failed; + + streams = this->streams(); + + if (streams.isEmpty()) + goto init_failed; + + supportedCaps = this->caps(this->d->m_device); + caps = supportedCaps[streams[0]].value(); + caps.setProperty("align", 16); + + parameters.callMethod("setPreviewFormat", + "(I)V", + imgFmtToStrMap->key(caps.property("fourcc").toString(), + ImageFormat::UNKNOWN)); + parameters.callMethod("setPreviewSize", + "(II)V", + caps.property("width").toInt(), + caps.property("height").toInt()); + + min = 0; + max = 0; + fps = caps.property("fps").toString(); + + if (!this->d->nearestFpsRangue(parameters, + fps, + min, + max)) { + goto init_failed; + } + + parameters.callMethod("setPreviewFpsRange", + "(II)V", + min, + max); + this->d->m_camera.callMethod("setParameters", + "(Landroid/hardware/Camera$Parameters;)V", + parameters.object()); + this->d->m_camera.callMethod("startPreview"); + + this->d->m_id = Ak::id(); + this->d->m_caps = caps; + this->d->m_fps = fps; + this->d->m_timeBase = this->d->m_fps.invert(); + + return true; + +init_failed: + this->uninit(); + + return false; +} + +void CaptureAndroidCamera::uninit() +{ + if (!this->d->m_camera.isValid()) + return; + + this->d->m_camera.callMethod("stopPreview"); + + if (this->d->m_surfaceView.isValid()) + QtAndroid::runOnAndroidThreadSync([this] { + this->d->m_surfaceView = {}; + }); + + this->d->m_camera.callMethod("release"); + this->d->m_camera = {}; +} + +void CaptureAndroidCamera::setDevice(const QString &device) +{ + if (this->d->m_device == device) + return; + + this->d->m_device = device; + + if (device.isEmpty()) { + this->d->m_controlsMutex.lock(); + this->d->m_globalImageControls.clear(); + this->d->m_globalCameraControls.clear(); + this->d->m_controlsMutex.unlock(); + } else { + this->d->m_controlsMutex.lock(); + + auto camera = + QAndroidJniObject::callStaticObjectMethod("android/hardware/Camera", + "open", + "(I)Landroid/hardware/Camera;", + this->d->deviceId(device)); + + if (camera.isValid()) { + auto parameters = + camera.callObjectMethod("getParameters", + "()Landroid/hardware/Camera$Parameters;"); + + if (parameters.isValid()) { + this->d->m_globalImageControls = this->d->imageControls(parameters); + this->d->m_globalCameraControls = this->d->cameraControls(parameters); + } + + camera.callMethod("release"); + } + + this->d->m_controlsMutex.unlock(); + } + + this->d->m_controlsMutex.lock(); + auto imageStatus = this->d->controlStatus(this->d->m_globalImageControls); + auto cameraStatus = this->d->controlStatus(this->d->m_globalCameraControls); + this->d->m_controlsMutex.unlock(); + + emit this->deviceChanged(device); + emit this->imageControlsChanged(imageStatus); + emit this->cameraControlsChanged(cameraStatus); +} + +void CaptureAndroidCamera::setStreams(const QList &streams) +{ + if (streams.isEmpty()) + return; + + int stream = streams[0]; + + if (stream < 0) + return; + + auto supportedCaps = this->caps(this->d->m_device); + + if (stream >= supportedCaps.length()) + return; + + QList inputStreams {stream}; + + if (this->streams() == inputStreams) + return; + + this->d->m_streams = inputStreams; + emit this->streamsChanged(inputStreams); +} + +void CaptureAndroidCamera::setIoMethod(const QString &ioMethod) +{ + Q_UNUSED(ioMethod) +} + +void CaptureAndroidCamera::setNBuffers(int nBuffers) +{ + Q_UNUSED(nBuffers) +} + +void CaptureAndroidCamera::resetDevice() +{ + this->setDevice(""); +} + +void CaptureAndroidCamera::resetStreams() +{ + auto supportedCaps = this->caps(this->d->m_device); + QList streams; + + if (!supportedCaps.isEmpty()) + streams << 0; + + this->setStreams(streams); +} + +void CaptureAndroidCamera::resetIoMethod() +{ + this->setIoMethod("any"); +} + +void CaptureAndroidCamera::resetNBuffers() +{ + this->setNBuffers(32); +} + +void CaptureAndroidCamera::reset() +{ + this->resetStreams(); + this->resetImageControls(); + this->resetCameraControls(); +} + +#include "moc_captureandroidcamera.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/captureandroidcamera.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/captureandroidcamera.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/captureandroidcamera.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/captureandroidcamera.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,69 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef CAPTUREANDROIDCAMERA_H +#define CAPTUREANDROIDCAMERA_H + +#include "capture.h" + +class CaptureAndroidCameraPrivate; + +class CaptureAndroidCamera: public Capture +{ + Q_OBJECT + + public: + CaptureAndroidCamera(QObject *parent=nullptr); + ~CaptureAndroidCamera(); + + Q_INVOKABLE QStringList webcams() const; + Q_INVOKABLE QString device() const; + Q_INVOKABLE QList streams(); + Q_INVOKABLE QList listTracks(const QString &mimeType); + Q_INVOKABLE QString ioMethod() const; + Q_INVOKABLE int nBuffers() const; + Q_INVOKABLE QString description(const QString &webcam) const; + Q_INVOKABLE QVariantList caps(const QString &webcam) const; + Q_INVOKABLE QString capsDescription(const AkCaps &caps) const; + Q_INVOKABLE QVariantList imageControls() const; + Q_INVOKABLE bool setImageControls(const QVariantMap &imageControls); + Q_INVOKABLE bool resetImageControls(); + Q_INVOKABLE QVariantList cameraControls() const; + Q_INVOKABLE bool setCameraControls(const QVariantMap &cameraControls); + Q_INVOKABLE bool resetCameraControls(); + Q_INVOKABLE AkPacket readFrame(); + + private: + CaptureAndroidCameraPrivate *d; + + public slots: + bool init(); + void uninit(); + void setDevice(const QString &device); + void setStreams(const QList &streams); + void setIoMethod(const QString &ioMethod); + void setNBuffers(int nBuffers); + void resetDevice(); + void resetStreams(); + void resetIoMethod(); + void resetNBuffers(); + void reset(); +}; + +#endif // CAPTUREANDROIDCAMERA_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "captureandroidcamera.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new CaptureAndroidCamera(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return QStringList(); +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,4 @@ +{ + "pluginType": "Ak.SubModule", + "type": "capture" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/src.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/src.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/src.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/androidcamera/src/src.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,66 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../../akcommons.pri) { + include(../../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +TARGET = androidcamera + +CONFIG += plugin + +HEADERS = \ + plugin.h \ + captureandroidcamera.h \ + ../../capture.h + +INCLUDEPATH += \ + ../../../../../Lib/src \ + ../../ + +LIBS += -L$${OUT_PWD}/../../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} + +OTHER_FILES += pspec.json + +QT += qml +android: QT += androidextras + +SOURCES = \ + plugin.cpp \ + captureandroidcamera.cpp \ + ../../capture.cpp + +akModule = VideoCapture +DESTDIR = $${OUT_PWD}/../../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/avfoundation.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/avfoundation.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/avfoundation.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/avfoundation.pro 2021-02-15 15:25:23.000000000 +0000 @@ -29,10 +29,11 @@ CONFIG += plugin HEADERS = \ + ../capture.h \ src/plugin.h \ src/captureavfoundation.h \ src/deviceobserver.h \ - ../capture.h + src/devicecontrols.h INCLUDEPATH += \ ../../../../Lib/src \ @@ -51,8 +52,9 @@ QT += qml SOURCES = \ + ../capture.cpp \ src/plugin.cpp \ - ../capture.cpp + src/devicecontrols.cpp OBJECTIVE_SOURCES = \ src/captureavfoundation.mm \ diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/captureavfoundation.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/captureavfoundation.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/captureavfoundation.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/captureavfoundation.h 2021-02-15 15:25:23.000000000 +0000 @@ -24,20 +24,13 @@ class CaptureAvFoundationPrivate; class QWaitCondition; +class QMutex; class CaptureAvFoundation: public Capture { Q_OBJECT public: - enum IoMethod - { - IoMethodUnknown = -1, - IoMethodReadWrite, - IoMethodMemoryMap, - IoMethodUserPointer - }; - CaptureAvFoundation(QObject *parent=nullptr); ~CaptureAvFoundation(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/captureavfoundation.mm webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/captureavfoundation.mm --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/captureavfoundation.mm 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/captureavfoundation.mm 2021-02-15 15:25:23.000000000 +0000 @@ -17,6 +17,7 @@ * Web-Site: http://webcamoid.github.io/ */ +#include #include #include #include @@ -30,178 +31,60 @@ #include "captureavfoundation.h" #include "deviceobserver.h" +#include "devicecontrols.h" -typedef QMap FourCharCodeToStrMap; +#define ENABLE_CONTROLS 0 -inline FourCharCodeToStrMap initFourCharCodeToStrMap() -{ - FourCharCodeToStrMap fourccToStrMap = { - // Raw formats - {kCMPixelFormat_32ARGB , "BGRA"}, - {kCMPixelFormat_24RGB , "RGB3"}, - {kCMPixelFormat_16BE555 , "RGBQ"}, - {kCMPixelFormat_16BE565 , "RGBR"}, - {kCMPixelFormat_16LE555 , "RGBO"}, - {kCMPixelFormat_16LE565 , "RGBP"}, - {kCMPixelFormat_16LE5551 , "AR15"}, - {kCMPixelFormat_422YpCbCr8 , "UYVY"}, - {kCMPixelFormat_422YpCbCr8_yuvs, "YUY2"}, - - // Compressed formats - {kCMVideoCodecType_422YpCbCr8 , "UYVY"}, - {kCMVideoCodecType_JPEG , "JPEG"}, - {kCMVideoCodecType_JPEG_OpenDML, "MJPG"}, - {kCMVideoCodecType_H263 , "H263"}, - {kCMVideoCodecType_H264 , "H264"}, - {kCMVideoCodecType_HEVC , "HEVC"}, - {kCMVideoCodecType_MPEG4Video , "MPG4"}, - {kCMVideoCodecType_MPEG2Video , "MPG2"}, - {kCMVideoCodecType_MPEG1Video , "MPG1"} - }; - - return fourccToStrMap; -} - -Q_GLOBAL_STATIC_WITH_ARGS(FourCharCodeToStrMap, fourccToStrMap, (initFourCharCodeToStrMap())) +using FourCharCodeToStrMap = QMap; class CaptureAvFoundationPrivate { public: - id m_deviceObserver; - AVCaptureDeviceInput *m_deviceInput; - AVCaptureVideoDataOutput *m_dataOutput; - AVCaptureSession *m_session; - CMSampleBufferRef m_curFrame; + id m_deviceObserver {nil}; + AVCaptureDeviceInput *m_deviceInput {nil}; + AVCaptureVideoDataOutput *m_dataOutput {nil}; + AVCaptureSession *m_session {nil}; + CMSampleBufferRef m_curFrame {nil}; QString m_device; QList m_streams; QStringList m_devices; QMap m_modelId; QMap m_descriptions; QMap m_devicesCaps; - CaptureAvFoundation::IoMethod m_ioMethod; - int m_nBuffers; + DeviceControls m_controls; + int m_nBuffers {32}; QMutex m_mutex; QMutex m_controlsMutex; QWaitCondition m_frameReady; AkFrac m_fps; AkFrac m_timeBase; AkCaps m_caps; - qint64 m_id; + qint64 m_id {-1}; QVariantList m_globalImageControls; QVariantList m_globalCameraControls; QVariantMap m_localImageControls; QVariantMap m_localCameraControls; - CaptureAvFoundationPrivate(): - m_deviceObserver(nil), - m_deviceInput(nil), - m_dataOutput(nil), - m_session(nil), - m_curFrame(nil), - m_ioMethod(CaptureAvFoundation::IoMethodUnknown), - m_nBuffers(32), - m_id(-1) - { - - } - - static inline QString fourccToStr(FourCharCode format) - { - char fourcc[5]; - memcpy(fourcc, &format, sizeof(FourCharCode)); - fourcc[4] = 0; - - return QString(fourcc); - } - - static inline FourCharCode strToFourCC(const QString &format) - { - FourCharCode fourcc; - memcpy(&fourcc, format.toStdString().c_str(), sizeof(FourCharCode)); - - return fourcc; - } - - static inline QVariantList imageControls(AVCaptureDevice *camera) - { - QVariantList controls; - - if ([camera lockForConfiguration: nil] == NO) - return controls; - - // This controls will be not implemented since Apple doesn't - // provides an interface for controlling camera controls - // (ie. UVC controls). - - [camera unlockForConfiguration]; - - return controls; - } - - static inline QVariantList cameraControls(AVCaptureDevice *camera) - { - QVariantList controls; - - if ([camera lockForConfiguration: nil] == NO) - return controls; - - // Same as above. - - [camera unlockForConfiguration]; - - return controls; - } - + CaptureAvFoundationPrivate(); + static bool canUseCamera(); + static inline QString fourccToStr(FourCharCode format); + static inline FourCharCode strToFourCC(const QString &format); static inline AVCaptureDeviceFormat *formatFromCaps(AVCaptureDevice *camera, - const AkCaps &caps) - { - for (AVCaptureDeviceFormat *format in camera.formats) { - if ([format.mediaType isEqualToString: AVMediaTypeVideo] == NO) - continue; - - FourCharCode fourCC = CMFormatDescriptionGetMediaSubType(format.formatDescription); - CMVideoDimensions size = - CMVideoFormatDescriptionGetDimensions(format.formatDescription); - - QString fourccStr = - fourccToStrMap->value(fourCC, - CaptureAvFoundationPrivate::fourccToStr(fourCC)); - - AkCaps videoCaps; - videoCaps.setMimeType("video/unknown"); - videoCaps.setProperty("fourcc", fourccStr); - videoCaps.setProperty("width", size.width); - videoCaps.setProperty("height", size.height); - - for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) { - videoCaps.setProperty("fps", AkFrac(qRound(1e3 * fpsRange.maxFrameRate), 1e3).toString()); - - if (videoCaps == caps) - return format; - } - } - - return nil; - } - + const AkCaps &caps); static inline AVFrameRateRange *frameRateRangeFromFps(AVCaptureDeviceFormat *format, - const AkFrac &fps) - { - for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) - if (AkFrac(qRound(1e3 * fpsRange.maxFrameRate), 1e3) == fps) - return fpsRange; - - return nil; - } - + const AkFrac &fps); + static inline const FourCharCodeToStrMap &fourccToStrMap(); AkCaps capsFromFrameSampleBuffer(const CMSampleBufferRef sampleBuffer) const; + QVariantMap controlStatus(const QVariantList &controls) const; + QVariantMap mapDiff(const QVariantMap &map1, + const QVariantMap &map2) const; }; CaptureAvFoundation::CaptureAvFoundation(QObject *parent): Capture(parent) { this->d = new CaptureAvFoundationPrivate(); - this->d->m_deviceObserver = [[DeviceObserver alloc] + this->d->m_deviceObserver = [[DeviceObserverAVFoundation alloc] initWithCaptureObject: this]; [[NSNotificationCenter defaultCenter] @@ -259,7 +142,7 @@ { if (mimeType != "video/x-raw" && !mimeType.isEmpty()) - return QList(); + return {}; auto caps = this->caps(this->d->m_device); QList streams; @@ -272,7 +155,7 @@ QString CaptureAvFoundation::ioMethod() const { - return QString(); + return {}; } int CaptureAvFoundation::nBuffers() const @@ -316,8 +199,8 @@ this->d->m_controlsMutex.unlock(); for (int i = 0; i < globalImageControls.count(); i++) { - QVariantList control = globalImageControls[i].toList(); - QString controlName = control[0].toString(); + auto control = globalImageControls[i].toList(); + auto controlName = control[0].toString(); if (imageControls.contains(controlName)) { control[6] = imageControls[controlName]; @@ -345,8 +228,8 @@ { QVariantMap controls; - for (const QVariant &control: this->imageControls()) { - QVariantList params = control.toList(); + for (auto &control: this->imageControls()) { + auto params = control.toList(); controls[params[0].toString()] = params[5].toInt(); } @@ -365,8 +248,8 @@ this->d->m_controlsMutex.unlock(); for (int i = 0; i < globalCameraControls.count(); i++) { - QVariantList control = globalCameraControls[i].toList(); - QString controlName = control[0].toString(); + auto control = globalCameraControls[i].toList(); + auto controlName = control[0].toString(); if (cameraControls.contains(controlName)) { control[6] = cameraControls[controlName]; @@ -394,9 +277,8 @@ { QVariantMap controls; - for (const QVariant &control: this->cameraControls()) { - QVariantList params = control.toList(); - + for (auto &control: this->cameraControls()) { + auto params = control.toList(); controls[params[0].toString()] = params[5].toInt(); } @@ -407,18 +289,43 @@ { this->d->m_mutex.lock(); +#if defined(ENABLE_CONTROLS) && ENABLE_CONTROLS != 0 + this->d->m_controlsMutex.lock(); + auto imageControls = this->d->controlStatus(this->d->m_globalImageControls); + this->d->m_controlsMutex.unlock(); + + if (this->d->m_localImageControls != imageControls) { + auto controls = this->d->mapDiff(this->d->m_localImageControls, + imageControls); + this->d->m_controls.setImageControls(controls); + this->d->m_localImageControls = imageControls; + } + + this->d->m_controlsMutex.lock(); + auto cameraControls = this->d->controlStatus(this->d->m_globalCameraControls); + this->d->m_controlsMutex.unlock(); + + if (this->d->m_localCameraControls != cameraControls) { + auto controls = this->d->mapDiff(this->d->m_localCameraControls, + cameraControls); + this->d->m_controls.setCameraControls(controls); + this->d->m_localCameraControls = cameraControls; + } +#endif + if (!this->d->m_curFrame) if (!this->d->m_frameReady.wait(&this->d->m_mutex, 1000)) { this->d->m_mutex.unlock(); - return AkPacket(); + return {}; } // Read frame data. QByteArray oBuffer; - CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(this->d->m_curFrame); - CMBlockBufferRef dataBuffer = CMSampleBufferGetDataBuffer(this->d->m_curFrame); + auto imageBuffer = CMSampleBufferGetImageBuffer(this->d->m_curFrame); + auto dataBuffer = CMSampleBufferGetDataBuffer(this->d->m_curFrame); auto caps = this->d->capsFromFrameSampleBuffer(this->d->m_curFrame); + caps.setProperty("fps", this->d->m_timeBase.invert().toString()); if (imageBuffer) { size_t dataSize = CVPixelBufferGetDataSize(imageBuffer); @@ -461,7 +368,8 @@ } // Create package. - AkPacket packet(caps, oBuffer); + AkPacket packet(caps); + packet.setBuffer(oBuffer); packet.setPts(pts); packet.setTimeBase(this->d->m_timeBase); packet.setIndex(0); @@ -499,9 +407,9 @@ { QVariantMap controlStatus; - for (const QVariant &control: controls) { - QVariantList params = control.toList(); - QString controlName = params[0].toString(); + for (auto &control: controls) { + auto params = control.toList(); + auto controlName = params[0].toString(); controlStatus[controlName] = params[0]; } @@ -510,7 +418,10 @@ bool CaptureAvFoundation::init() { - QString webcam = this->d->m_device; + this->d->m_localImageControls.clear(); + this->d->m_localCameraControls.clear(); + + auto webcam = this->d->m_device; if (webcam.isEmpty()) return false; @@ -531,9 +442,9 @@ supportedCaps.first().value(); // Get camera input. - NSString *uniqueID = [[NSString alloc] - initWithUTF8String: webcam.toStdString().c_str()]; - AVCaptureDevice *camera = [AVCaptureDevice deviceWithUniqueID: uniqueID]; + auto uniqueID = [[NSString alloc] + initWithUTF8String: webcam.toStdString().c_str()]; + auto camera = [AVCaptureDevice deviceWithUniqueID: uniqueID]; [uniqueID release]; if (!camera) @@ -596,6 +507,9 @@ return false; } +#if defined(ENABLE_CONTROLS) && ENABLE_CONTROLS != 0 + this->d->m_controls.open(webcam); +#endif AkFrac fps = caps.property("fps").toString(); auto fpsRange = CaptureAvFoundationPrivate::frameRateRangeFromFps(format, fps); @@ -651,6 +565,10 @@ } this->d->m_mutex.unlock(); + +#if defined(ENABLE_CONTROLS) && ENABLE_CONTROLS != 0 + this->d->m_controls.close(); +#endif } void CaptureAvFoundation::setDevice(const QString &device) @@ -659,7 +577,36 @@ return; this->d->m_device = device; + + if (device.isEmpty()) { + this->d->m_controlsMutex.lock(); + this->d->m_globalImageControls.clear(); + this->d->m_globalCameraControls.clear(); + this->d->m_controlsMutex.unlock(); + } else { + this->d->m_controlsMutex.lock(); + +#if defined(ENABLE_CONTROLS) && ENABLE_CONTROLS != 0 + DeviceControls controls; + + if (controls.open(device)) { + this->d->m_globalImageControls = controls.imageControls(); + this->d->m_globalCameraControls = controls.cameraControls(); + controls.close(); + } +#endif + + this->d->m_controlsMutex.unlock(); + } + + this->d->m_controlsMutex.lock(); + auto imageStatus = this->d->controlStatus(this->d->m_globalImageControls); + auto cameraStatus = this->d->controlStatus(this->d->m_globalCameraControls); + this->d->m_controlsMutex.unlock(); + emit this->deviceChanged(device); + emit this->imageControlsChanged(imageStatus); + emit this->cameraControlsChanged(cameraStatus); } void CaptureAvFoundation::setStreams(const QList &streams) @@ -746,12 +693,15 @@ void CaptureAvFoundation::updateDevices() { + if (!CaptureAvFoundationPrivate::canUseCamera()) + return; + decltype(this->d->m_devices) devices; decltype(this->d->m_modelId) modelId; decltype(this->d->m_descriptions) descriptions; decltype(this->d->m_devicesCaps) devicesCaps; - NSArray *cameras = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]; + auto cameras = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]; for (AVCaptureDevice *camera in cameras) { QString deviceId = camera.uniqueID.UTF8String; @@ -778,13 +728,13 @@ // List supported frame formats. for (AVCaptureDeviceFormat *format in camera.formats) { - FourCharCode fourCC = CMFormatDescriptionGetMediaSubType(format.formatDescription); + auto fourCC = CMFormatDescriptionGetMediaSubType(format.formatDescription); CMVideoDimensions size = CMVideoFormatDescriptionGetDimensions(format.formatDescription); - + auto &map = CaptureAvFoundationPrivate::fourccToStrMap(); QString fourccStr = - fourccToStrMap->value(fourCC, - CaptureAvFoundationPrivate::fourccToStr(fourCC)); + map.value(fourCC, + CaptureAvFoundationPrivate::fourccToStr(fourCC)); AkCaps videoCaps; videoCaps.setMimeType("video/unknown"); @@ -800,15 +750,143 @@ } } - if (this->d->m_devices != devices) { - this->d->m_devices = devices; - emit this->webcamsChanged(devices); + if (devicesCaps.isEmpty()) { + devices.clear(); + modelId.clear(); + descriptions.clear(); } - this->d->m_devices = devices; this->d->m_modelId = modelId; this->d->m_descriptions = descriptions; this->d->m_devicesCaps = devicesCaps; + + if (this->d->m_devices != devices) { + this->d->m_devices = devices; + emit this->webcamsChanged(devices); + } +} + +CaptureAvFoundationPrivate::CaptureAvFoundationPrivate() +{ + +} + +bool CaptureAvFoundationPrivate::canUseCamera() +{ + if (@available(macOS 10.14, *)) { + auto status = [AVCaptureDevice authorizationStatusForMediaType: AVMediaTypeVideo]; + + if (status == AVAuthorizationStatusAuthorized) + return true; + + static bool done; + static bool result = false; + done = false; + + [AVCaptureDevice + requestAccessForMediaType: AVMediaTypeVideo + completionHandler: ^(BOOL granted) { + done = true; + result = granted; + }]; + + while (!done) + qApp->processEvents(); + + return result; + } + + return true; +} + +QString CaptureAvFoundationPrivate::fourccToStr(FourCharCode format) +{ + char fourcc[5]; + memcpy(fourcc, &format, sizeof(FourCharCode)); + fourcc[4] = 0; + + return QString(fourcc); +} + +FourCharCode CaptureAvFoundationPrivate::strToFourCC(const QString &format) +{ + FourCharCode fourcc; + memcpy(&fourcc, format.toStdString().c_str(), sizeof(FourCharCode)); + + return fourcc; +} + +AVCaptureDeviceFormat *CaptureAvFoundationPrivate::formatFromCaps(AVCaptureDevice *camera, + const AkCaps &caps) +{ + for (AVCaptureDeviceFormat *format in camera.formats) { + if ([format.mediaType isEqualToString: AVMediaTypeVideo] == NO) + continue; + + auto fourCC = CMFormatDescriptionGetMediaSubType(format.formatDescription); + CMVideoDimensions size = + CMVideoFormatDescriptionGetDimensions(format.formatDescription); + auto &map = CaptureAvFoundationPrivate::fourccToStrMap(); + QString fourccStr = + map.value(fourCC, + CaptureAvFoundationPrivate::fourccToStr(fourCC)); + + AkCaps videoCaps; + videoCaps.setMimeType("video/unknown"); + videoCaps.setProperty("fourcc", fourccStr); + videoCaps.setProperty("width", size.width); + videoCaps.setProperty("height", size.height); + + for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) { + videoCaps.setProperty("fps", + AkFrac(qRound(1e3 * fpsRange.maxFrameRate), + 1e3).toString()); + + if (videoCaps == caps) + return format; + } + } + + return nil; +} + +AVFrameRateRange *CaptureAvFoundationPrivate::frameRateRangeFromFps(AVCaptureDeviceFormat *format, + const AkFrac &fps) +{ + for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) + if (AkFrac(qRound(1e3 * fpsRange.maxFrameRate), 1e3) == fps) + return fpsRange; + + return nil; +} + +const FourCharCodeToStrMap &CaptureAvFoundationPrivate::fourccToStrMap() +{ + static const FourCharCodeToStrMap fourccToStrMap { + // Raw formats + {kCMPixelFormat_32ARGB , "ARGB" }, + {kCMPixelFormat_24RGB , "RGB" }, + {kCMPixelFormat_16BE555 , "RGB555BE"}, + {kCMPixelFormat_16BE565 , "RGB565BE"}, + {kCMPixelFormat_16LE555 , "RGB555" }, + {kCMPixelFormat_16LE565 , "RGB565" }, + {kCMPixelFormat_16LE5551 , "ARGB555" }, + {kCMPixelFormat_422YpCbCr8 , "UYVY" }, + {kCMPixelFormat_422YpCbCr8_yuvs, "YUY2" }, + + // Compressed formats + {kCMVideoCodecType_422YpCbCr8 , "UYVY"}, + {kCMVideoCodecType_JPEG , "JPEG"}, + {kCMVideoCodecType_JPEG_OpenDML, "MJPG"}, + {kCMVideoCodecType_H263 , "H263"}, + {kCMVideoCodecType_H264 , "H264"}, + {kCMVideoCodecType_HEVC , "HEVC"}, + {kCMVideoCodecType_MPEG4Video , "MPG4"}, + {kCMVideoCodecType_MPEG2Video , "MPG2"}, + {kCMVideoCodecType_MPEG1Video , "MPG1"} + }; + + return fourccToStrMap; } AkCaps CaptureAvFoundationPrivate::capsFromFrameSampleBuffer(const CMSampleBufferRef sampleBuffer) const @@ -819,8 +897,10 @@ videoCaps.setMimeType("video/unknown"); auto fourCC = CMFormatDescriptionGetMediaSubType(formatDesc); - videoCaps.setProperty("fourcc", fourccToStrMap->value(fourCC, - CaptureAvFoundationPrivate::fourccToStr(fourCC))); + auto &map = CaptureAvFoundationPrivate::fourccToStrMap(); + videoCaps.setProperty("fourcc", + map.value(fourCC, + CaptureAvFoundationPrivate::fourccToStr(fourCC))); auto size = CMVideoFormatDescriptionGetDimensions(formatDesc); videoCaps.setProperty("width", size.width); @@ -832,4 +912,31 @@ return videoCaps; } +QVariantMap CaptureAvFoundationPrivate::controlStatus(const QVariantList &controls) const +{ + QVariantMap controlStatus; + + for (auto &control: controls) { + auto params = control.toList(); + auto controlName = params[0].toString(); + controlStatus[controlName] = params[6]; + } + + return controlStatus; +} + +QVariantMap CaptureAvFoundationPrivate::mapDiff(const QVariantMap &map1, + const QVariantMap &map2) const +{ + QVariantMap map; + + for (auto it = map2.cbegin(); it != map2.cend(); it++) + if (!map1.contains(it.key()) + || map1[it.key()] != it.value()) { + map[it.key()] = it.value(); + } + + return map; +} + #include "moc_captureavfoundation.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/devicecontrols.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/devicecontrols.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/devicecontrols.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/devicecontrols.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,738 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include + +#include "devicecontrols.h" + +#define INTERFACE 0x4 + +// Video Interface Class Code +#define CC_VIDEO 0xe + +// Video Class-Specific Descriptor Types +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +// Video Interface Subclass Codes +#define SC_UNDEFINED 0x0 +#define SC_VIDEOCONTROL 0x1 +#define SC_VIDEOSTREAMING 0x2 + +// Video Class-Specific VC Interface Descriptor Subtypes +#define VC_INPUT_TERMINAL 0x2 +#define VC_PROCESSING_UNIT 0x5 + +// Processing Unit Control Selectors +#define PU_CONTROL_UNDEFINED 0x00 +#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 +#define PU_BRIGHTNESS_CONTROL 0x02 +#define PU_CONTRAST_CONTROL 0x03 +#define PU_GAIN_CONTROL 0x04 +#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05 +#define PU_HUE_CONTROL 0x06 +#define PU_SATURATION_CONTROL 0x07 +#define PU_SHARPNESS_CONTROL 0x08 +#define PU_GAMMA_CONTROL 0x09 +#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a +#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b +#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c +#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d +#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e +#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f +#define PU_HUE_AUTO_CONTROL 0x10 +#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 +#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12 +#define PU_CONTRAST_AUTO_CONTROL 0x13 + +// Camera Terminal Control Selectors +#define CT_CONTROL_UNDEFINED 0x00 +#define CT_SCANNING_MODE_CONTROL 0x01 +#define CT_AE_MODE_CONTROL 0x02 +#define CT_AE_PRIORITY_CONTROL 0x03 +#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 +#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 +#define CT_FOCUS_ABSOLUTE_CONTROL 0x06 +#define CT_FOCUS_RELATIVE_CONTROL 0x07 +#define CT_FOCUS_AUTO_CONTROL 0x08 +#define CT_IRIS_ABSOLUTE_CONTROL 0x09 +#define CT_IRIS_RELATIVE_CONTROL 0x0a +#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b +#define CT_ZOOM_RELATIVE_CONTROL 0x0c +#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d +#define CT_PANTILT_RELATIVE_CONTROL 0x0e +#define CT_ROLL_ABSOLUTE_CONTROL 0x0f +#define CT_ROLL_RELATIVE_CONTROL 0x10 +#define CT_PRIVACY_CONTROL 0x11 +#define CT_FOCUS_SIMPLE_CONTROL 0x12 +#define CT_WINDOW_CONTROL 0x13 +#define CT_REGION_OF_INTEREST_CONTROL 0x14 + +// Video Class-Specific Request Codes +#define RC_UNDEFINED 0x00 +#define SET_CUR 0x01 +#define SET_CUR_ALL 0x11 +#define GET_CUR 0x81 +#define GET_MIN 0x82 +#define GET_MAX 0x83 +#define GET_RES 0x84 +#define GET_LEN 0x85 +#define GET_INFO 0x86 +#define GET_DEF 0x87 +#define GET_CUR_ALL 0x91 +#define GET_MIN_ALL 0x92 +#define GET_MAX_ALL 0x93 +#define GET_RES_ALL 0x94 +#define GET_DEF_ALL 0x97 + +#define CAMERA_TERMINAL 0x0 +#define PROCESSING_UNIT 0x1 + +#define EP_INTERRUPT 0x3 + +struct GenericDescriptor +{ + quint8 bLength; + quint8 bDescriptorType; +}; + +struct StandardVCInterfaceDescriptor +{ + quint8 bLength; + quint8 bDescriptorType; + quint8 bInterfaceNumber; + quint8 bAlternateSetting; + quint8 bNumEndpoints; + quint8 bInterfaceClass; + quint8 bInterfaceSubClass; + quint8 bInterfaceProtocol; + qint8 iInterface; +}; + +struct CsInterfaceDescriptor +{ + quint8 bLength; + quint8 bDescriptorType; + quint8 bDescriptorSubtype; +}; + +struct VcProcessingUnit +{ + quint8 bLength; + quint8 bDescriptorType; + quint8 bDescriptorSubtype; + quint8 bUnitID; +}; + +struct VcInputTerminal +{ + quint8 bLength; + quint8 bDescriptorType; + quint8 bDescriptorSubtype; + quint8 bTerminalID; +}; + +class UvcControl +{ + public: + quint16 controlType; + quint16 selector; + QString description; + QString type; + bool signd; + QStringList menu; + + inline static const QVector &controls(); + static inline const UvcControl *bySelector(quint16 controlType, + quint16 selector); + static inline QVector allSelectors(quint16 controlType); +}; + +using USBInterfacePtr = IOUSBInterfaceInterface182 *; + +class DeviceControlsPrivate +{ + public: + USBInterfacePtr *m_interface {nullptr}; + quint8 m_bInterfaceNumber {0}; + quint8 m_bUnitID {0}; + quint8 m_bTerminalID {0}; + + USBInterfacePtr *controlInterface(IOUSBDeviceInterface **deviceInterface); + void readConfigurationDescription(IOUSBDeviceInterface **deviceInterface); + int sendRequest(USBInterfacePtr *interface, + IOUSBDevRequest &request) const; + template + int readData(USBInterfacePtr *interface, + quint8 request, + quint16 controlType, + quint16 selector, + T *data) const; + template + int writeData(USBInterfacePtr *interface, + quint16 controlType, + quint16 selector, + T *data) const; + QVariantList controlsList(USBInterfacePtr *interface, + quint16 controlID, + quint16 request, + quint16 selector) const; + int setControls(USBInterfacePtr *interface, + quint16 controlID, + quint16 request, + quint16 selector, + const QVariantMap &values) const; +}; + +DeviceControls::DeviceControls() +{ + this->d = new DeviceControlsPrivate; +} + +DeviceControls::~DeviceControls() +{ + this->close(); + delete this->d; +} + +bool DeviceControls::open(const QString &deviceId) +{ + bool ok = false; + auto deviceLocationId = quint32(deviceId.toULongLong(&ok, 16) >> 32); + + if (!ok) + return false; + + auto serviceMatching = IOServiceMatching(kIOUSBDeviceClassName); + io_iterator_t serviceIterator; + IOServiceGetMatchingServices(kIOMasterPortDefault, + serviceMatching, + &serviceIterator); + + while (auto device = IOIteratorNext(serviceIterator)) { + IOCFPlugInInterface **pluginInterface = nullptr; + SInt32 score = 0; + auto result = IOCreatePlugInInterfaceForService(device, + kIOUSBDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &pluginInterface, + &score); + + if (result != kIOReturnSuccess || !pluginInterface) + continue; + + IOUSBDeviceInterface **deviceInterface = nullptr; + auto hr = (*pluginInterface)->QueryInterface(pluginInterface, + CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), + reinterpret_cast(&deviceInterface)); + + if (hr != 0 || !deviceInterface) + continue; + + UInt32 locationId = 0; + (*deviceInterface)->GetLocationID(deviceInterface, &locationId); + + if (locationId == deviceLocationId) { + this->d->m_interface = this->d->controlInterface(deviceInterface); + this->d->readConfigurationDescription(deviceInterface); + + return true; + } + } + + return false; +} + +void DeviceControls::close() +{ + if (this->d->m_interface) { + (*this->d->m_interface)->USBInterfaceClose(this->d->m_interface); + (*this->d->m_interface)->Release(this->d->m_interface); + this->d->m_interface = nullptr; + } +} + +QVariantList DeviceControls::imageControls() +{ + if (!this->d->m_interface) + return {}; + + QVariantList deviceControls; + + for (auto &control: UvcControl::allSelectors(PROCESSING_UNIT)) { + if (control == PU_CONTROL_UNDEFINED) + continue; + + auto controls = + this->d->controlsList(this->d->m_interface, + this->d->m_bUnitID, + PROCESSING_UNIT, + control); + + if (!controls.isEmpty()) + deviceControls << QVariant(controls); + } + + return deviceControls; +} + +QVariantList DeviceControls::cameraControls() +{ + if (!this->d->m_interface) + return {}; + + QVariantList deviceControls; + + for (auto &control: UvcControl::allSelectors(CAMERA_TERMINAL)) { + if (control == CT_CONTROL_UNDEFINED) + continue; + + auto controls = + this->d->controlsList(this->d->m_interface, + this->d->m_bTerminalID, + CAMERA_TERMINAL, + control); + + if (!controls.isEmpty()) + deviceControls << QVariant(controls); + } + + return deviceControls; +} + +void DeviceControls::setImageControls(const QVariantMap &imageControls) +{ + if (!this->d->m_interface) + return; + + for (auto &control: UvcControl::allSelectors(PROCESSING_UNIT)) + this->d->setControls(this->d->m_interface, + this->d->m_bUnitID, + PROCESSING_UNIT, + control, + imageControls); +} + +void DeviceControls::setCameraControls(const QVariantMap &cameraControls) +{ + if (!this->d->m_interface) + return; + + for (auto &control: UvcControl::allSelectors(CAMERA_TERMINAL)) + this->d->setControls(this->d->m_interface, + this->d->m_bTerminalID, + CAMERA_TERMINAL, + control, + cameraControls); +} + +USBInterfacePtr *DeviceControlsPrivate::controlInterface(IOUSBDeviceInterface **deviceInterface) +{ + io_iterator_t interfaceIterator; + IOUSBFindInterfaceRequest interfaceRequest; + interfaceRequest.bInterfaceClass = CC_VIDEO; + interfaceRequest.bInterfaceSubClass = SC_VIDEOCONTROL; + interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + auto hr = (*deviceInterface)->CreateInterfaceIterator(deviceInterface, + &interfaceRequest, + &interfaceIterator); + + if (hr != kIOReturnSuccess) + return nullptr; + + auto usbInterface = IOIteratorNext(interfaceIterator); + + if (!usbInterface) + return nullptr; + + IOCFPlugInInterface **pluginInterface = nullptr; + SInt32 score = 0; + auto result = IOCreatePlugInInterfaceForService(usbInterface, + kIOUSBInterfaceUserClientTypeID, + kIOCFPlugInInterfaceID, + &pluginInterface, + &score); + IOObjectRelease(usbInterface); + + if (result != 0 || !pluginInterface) + return nullptr; + + USBInterfacePtr *controlInterface = nullptr; + hr = (*pluginInterface)->QueryInterface(pluginInterface, + CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), + reinterpret_cast(&controlInterface)); + (*pluginInterface)->Release(pluginInterface); + + if (result != 0 || !controlInterface) + return nullptr; + + return controlInterface; +} + +void DeviceControlsPrivate::readConfigurationDescription(IOUSBDeviceInterface **deviceInterface) +{ + IOUSBConfigurationDescriptorPtr configDescriptor = nullptr; + auto result = + (*deviceInterface)->GetConfigurationDescriptorPtr(deviceInterface, + 0, + &configDescriptor); + + if (result != kIOReturnSuccess) + return; + + auto ptr = reinterpret_cast(configDescriptor); + bool endPoint = false; + + for (size_t bytes = configDescriptor->bLength; + bytes < configDescriptor->wTotalLength && !endPoint;) { + auto descriptor = reinterpret_cast(ptr + bytes); + + switch (descriptor->bDescriptorType) { + case INTERFACE: { + auto desc = reinterpret_cast(descriptor); + + if (desc->bInterfaceClass == CC_VIDEO + && desc->bInterfaceSubClass == SC_VIDEOSTREAMING) + this->m_bInterfaceNumber = desc->bInterfaceNumber; + + break; + } + + case CS_INTERFACE: { + auto desc = reinterpret_cast(descriptor); + + switch (desc->bDescriptorSubtype) { + case VC_PROCESSING_UNIT: { + auto puDesc = reinterpret_cast(desc); + this->m_bUnitID = puDesc->bUnitID; + + break; + } + + case VC_INPUT_TERMINAL: { + auto itDesc = reinterpret_cast(desc); + this->m_bTerminalID = itDesc->bTerminalID; + + break; + } + + default: + break; + } + + break; + } + + case CS_ENDPOINT: { + auto desc = reinterpret_cast(descriptor); + + if (desc->bDescriptorSubtype == EP_INTERRUPT) + endPoint = true; + + break; + } + + default: + break; + } + + bytes += descriptor->bLength; + } +} + +int DeviceControlsPrivate::sendRequest(USBInterfacePtr *interface, + IOUSBDevRequest &request) const +{ + if (!interface) + return kIOReturnError; + + auto hr = (*interface)->USBInterfaceOpen(interface); + + if (hr != kIOReturnSuccess) + return hr; + + UInt8 endPoints = 0; + (*interface)->GetNumEndpoints(interface, &endPoints); + + for (UInt8 i = 0; i < endPoints; i++) + (*interface)->ClearPipeStall(interface, i); + + hr = (*interface)->ControlRequest(interface, 0, &request); + (*interface)->USBInterfaceClose(interface); + + return hr; +} + +template +int DeviceControlsPrivate::readData(USBInterfacePtr *interface, + quint8 request, + quint16 controlType, + quint16 selector, + T *data) const +{ + IOUSBDevRequest controlRequest; + controlRequest.bmRequestType = + USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface); + controlRequest.bRequest = request; + controlRequest.wValue = UInt16(selector << 8); + controlRequest.wIndex = UInt16(controlType << 8) | this->m_bInterfaceNumber; + controlRequest.wLength = sizeof(T); + controlRequest.wLenDone = 0; + controlRequest.pData = reinterpret_cast(data); + + return this->sendRequest(interface, controlRequest); +} + +template +int DeviceControlsPrivate::writeData(USBInterfacePtr *interface, + quint16 controlType, + quint16 selector, + T *data) const +{ + IOUSBDevRequest controlRequest; + controlRequest.bmRequestType = + USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface); + controlRequest.bRequest = SET_CUR; + controlRequest.wValue = UInt16(selector << 8); + controlRequest.wIndex = UInt16(controlType << 8) | this->m_bInterfaceNumber; + controlRequest.wLength = sizeof(T); + controlRequest.wLenDone = 0; + controlRequest.pData = reinterpret_cast(data); + + /* FIXME: For some unknown reason 'ControlRequest' always returns + * kIOUSBPipeStalled, so 'writeData' fails and it's not possible to set the + * control value. + */ + + return this->sendRequest(interface, controlRequest); +} + +QVariantList DeviceControlsPrivate::controlsList(USBInterfacePtr *interface, + quint16 controlID, + quint16 request, + quint16 selector) const +{ + auto control = UvcControl::bySelector(request, selector); + int min = 0; + int max = 0; + int step = 0; + int defaultValue = 0; + int value = 0; + + if (control->type == "integer") { + if (control->signd) { + int16_t val = 0; + + if (this->readData(interface, GET_CUR, controlID, selector, &val) != kIOReturnSuccess) + return {}; + + value = val; + this->readData(interface, GET_MIN, controlID, selector, &val); + min = val; + this->readData(interface, GET_MAX, controlID, selector, &val); + max = val; + this->readData(interface, GET_RES, controlID, selector, &val); + step = val; + this->readData(interface, GET_DEF, controlID, selector, &val); + defaultValue = val; + } else { + uint16_t val = 0; + + if (this->readData(interface, GET_CUR, controlID, selector, &val) != kIOReturnSuccess) + return {}; + + value = val; + this->readData(interface, GET_MIN, controlID, selector, &val); + min = val; + this->readData(interface, GET_MAX, controlID, selector, &val); + max = val; + this->readData(interface, GET_RES, controlID, selector, &val); + step = val; + this->readData(interface, GET_DEF, controlID, selector, &val); + defaultValue = val; + } + } else if (control->type == "boolean") { + uint8_t val = false; + + if (this->readData(interface, GET_CUR, controlID, selector, &val) != kIOReturnSuccess) + return {}; + + value = val; + this->readData(interface, GET_MIN, controlID, selector, &val); + min = val; + this->readData(interface, GET_MAX, controlID, selector, &val); + max = val; + this->readData(interface, GET_RES, controlID, selector, &val); + step = val; + this->readData(interface, GET_DEF, controlID, selector, &val); + defaultValue = val; + } else if (control->type == "menu") { + uint8_t val = 0; + + if (this->readData(interface, GET_CUR, controlID, selector, &val) != kIOReturnSuccess) + return {}; + + value = val; + this->readData(interface, GET_MIN, controlID, selector, &val); + min = val; + this->readData(interface, GET_MAX, controlID, selector, &val); + max = val; + this->readData(interface, GET_RES, controlID, selector, &val); + step = val; + this->readData(interface, GET_DEF, controlID, selector, &val); + defaultValue = val; + } + + return QVariantList { + control->description, + control->type, + min, + max, + step, + defaultValue, + value, + control->menu + }; +} + +int DeviceControlsPrivate::setControls(USBInterfacePtr *interface, + quint16 controlID, + quint16 request, + quint16 selector, + const QVariantMap &values) const +{ + auto control = UvcControl::bySelector(request, selector); + + if (!values.contains(control->description)) + return kIOReturnError; + + int result = kIOReturnError; + + if (control->type == "integer") { + if (control->signd) { + auto val = int16_t(values[control->description].toInt()); + result = this->writeData(interface, controlID, selector, &val); + } else { + auto val = uint16_t(values[control->description].toUInt()); + result = this->writeData(interface, controlID, selector, &val); + } + } else if (control->type == "boolean") { + uint8_t val = values[control->description].toBool(); + result = this->writeData(interface, controlID, selector, &val); + } else if (control->type == "menu") { + auto val = uint8_t(values[control->description].toUInt()); + result = this->writeData(interface, controlID, selector, &val); + } + + return result; +} + +const QVector &UvcControl::controls() +{ + static const QVector controls { + // Processing Units + {PROCESSING_UNIT, PU_CONTROL_UNDEFINED , "" , "" , false, {}}, + {PROCESSING_UNIT, PU_BACKLIGHT_COMPENSATION_CONTROL , "Backlight Compensation" , "integer", false, {}}, + {PROCESSING_UNIT, PU_BRIGHTNESS_CONTROL , "Brightness" , "integer", true , {}}, + {PROCESSING_UNIT, PU_CONTRAST_CONTROL , "Contrast" , "integer", false, {}}, + {PROCESSING_UNIT, PU_GAIN_CONTROL , "Gain" , "integer", false, {}}, + {PROCESSING_UNIT, PU_POWER_LINE_FREQUENCY_CONTROL , "Power Line Frequency" , "menu" , false, {"Disabled", + "50 Hz", + "60 Hz", + "Auto"}}, + {PROCESSING_UNIT, PU_HUE_CONTROL , "Hue" , "integer", true , {}}, + {PROCESSING_UNIT, PU_SATURATION_CONTROL , "Saturation" , "integer", false, {}}, + {PROCESSING_UNIT, PU_SHARPNESS_CONTROL , "Sharpness" , "integer", false, {}}, + {PROCESSING_UNIT, PU_GAMMA_CONTROL , "Gamma" , "integer", false, {}}, + {PROCESSING_UNIT, PU_WHITE_BALANCE_TEMPERATURE_CONTROL , "White Balance Temperature" , "integer", false, {}}, + {PROCESSING_UNIT, PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, "White Balance Temperature Auto", "boolean", false, {}}, + //{PROCESSING_UNIT, PU_WHITE_BALANCE_COMPONENT_CONTROL , "White Balance Component" , "integer", false, {}}, + {PROCESSING_UNIT, PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL , "White Balance Component Auto" , "boolean", false, {}}, + {PROCESSING_UNIT, PU_DIGITAL_MULTIPLIER_CONTROL , "Digital Multiplier" , "integer", false, {}}, + {PROCESSING_UNIT, PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL , "Digital Multiplier Limit" , "integer", false, {}}, + {PROCESSING_UNIT, PU_HUE_AUTO_CONTROL , "Hue Auto" , "boolean", false, {}}, + {PROCESSING_UNIT, PU_ANALOG_VIDEO_STANDARD_CONTROL , "Analog Video Standard" , "menu" , false, {"None", + "NTSC - 525/60", + "PAL - 625/50", + "SECAM - 625/50", + "NTSC - 625/50", + "PAL - 525/60"}}, + {PROCESSING_UNIT, PU_ANALOG_LOCK_STATUS_CONTROL , "Analog Lock Status" , "menu" , false, {"Locked", + "Unlocked"}}, + {PROCESSING_UNIT, PU_CONTRAST_AUTO_CONTROL , "Contrast Auto" , "boolean", false, {}}, + + // Camera Terminals + {CAMERA_TERMINAL, CT_CONTROL_UNDEFINED , "" , "" , false, {}}, + {CAMERA_TERMINAL, CT_SCANNING_MODE_CONTROL , "Scanning Mode" , "boolean", false, {}}, + //{CAMERA_TERMINAL, CT_AE_MODE_CONTROL , "AE Mode" , "", false, {}}, + //{CAMERA_TERMINAL, CT_AE_PRIORITY_CONTROL , "AE Priority" , "", false, {}}, + //{CAMERA_TERMINAL, CT_EXPOSURE_TIME_ABSOLUTE_CONTROL , "Exposure Time Absolute" , "", false, {}}, + //{CAMERA_TERMINAL, CT_EXPOSURE_TIME_RELATIVE_CONTROL , "Exposure Time Relative" , "", false, {}}, + {CAMERA_TERMINAL, CT_FOCUS_ABSOLUTE_CONTROL , "Focus Absolute" , "integer", false, {}}, + //{CAMERA_TERMINAL, CT_FOCUS_RELATIVE_CONTROL , "Focus Relative" , "", false, {}}, + {CAMERA_TERMINAL, CT_FOCUS_AUTO_CONTROL , "Focus Auto" , "boolean", false, {}}, + {CAMERA_TERMINAL, CT_IRIS_ABSOLUTE_CONTROL , "Iris Absolute" , "integer", false, {}}, + //{CAMERA_TERMINAL, CT_IRIS_RELATIVE_CONTROL , "Iris Relative" , "", false, {}}, + {CAMERA_TERMINAL, CT_ZOOM_ABSOLUTE_CONTROL , "Zoom Absolute" , "integer", false, {}}, + //{CAMERA_TERMINAL, CT_ZOOM_RELATIVE_CONTROL , "Zoom Relative" , "", false, {}}, + //{CAMERA_TERMINAL, CT_PANTILT_ABSOLUTE_CONTROL , "Pantilt Absolute" , "", false, {}}, + //{CAMERA_TERMINAL, CT_PANTILT_RELATIVE_CONTROL , "Pantilt Relative" , "", false, {}}, + {CAMERA_TERMINAL, CT_ROLL_ABSOLUTE_CONTROL , "Roll Absolute" , "integer", true, {}}, + //{CAMERA_TERMINAL, CT_ROLL_RELATIVE_CONTROL , "Roll Relative" , "", false, {}}, + {CAMERA_TERMINAL, CT_PRIVACY_CONTROL , "Privacy" , "boolean", false, {}}, + {CAMERA_TERMINAL, CT_FOCUS_SIMPLE_CONTROL , "Focus Simple" , "menu" , false, {"Full Range", + "Macro", + "People", + "Scene"}}, + //{CAMERA_TERMINAL, CT_DIGITAL_WINDOW_CONTROL , "Digital Window" , "", false, {}}, + //{CAMERA_TERMINAL, CT_REGION_OF_INTEREST_CONTROL , "Region of Interest" , "", false, {}} + }; + + return controls; +} + +const UvcControl *UvcControl::bySelector(quint16 controlType, quint16 selector) +{ + for (auto &control: controls()) + if (control.controlType == controlType + && control.selector == selector) + return &control; + + // Returns default for control type. + for (auto &control: controls()) + if (control.controlType == controlType) + return &control; + + return &controls().first(); +} + +QVector UvcControl::allSelectors(quint16 controlType) +{ + QVector selectors; + + for (auto &control: controls()) + if (control.controlType == controlType) + selectors << control.selector; + + return selectors; +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/devicecontrols.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/devicecontrols.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/devicecontrols.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/devicecontrols.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,45 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef DEVICECONTROLS_H +#define DEVICECONTROLS_H + +#include +#include + +class DeviceControlsPrivate; + +class DeviceControls +{ + public: + explicit DeviceControls(); + ~DeviceControls(); + + bool open(const QString &deviceId); + void close(); + QVariantList imageControls(); + QVariantList cameraControls(); + void setImageControls(const QVariantMap &imageControls); + void setCameraControls(const QVariantMap &cameraControls); + + private: + DeviceControlsPrivate *d; +}; + +#endif // DEVICECONTROLS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/deviceobserver.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/deviceobserver.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/deviceobserver.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/deviceobserver.h 2021-02-15 15:25:23.000000000 +0000 @@ -24,7 +24,7 @@ #include "captureavfoundation.h" -@interface DeviceObserver: NSObject { +@interface DeviceObserverAVFoundation: NSObject { CaptureAvFoundation *m_capture; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/deviceobserver.mm webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/deviceobserver.mm --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/deviceobserver.mm 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/avfoundation/src/deviceobserver.mm 2021-02-15 15:25:23.000000000 +0000 @@ -21,7 +21,7 @@ #include "deviceobserver.h" -@implementation DeviceObserver +@implementation DeviceObserverAVFoundation - (id) initWithCaptureObject: (CaptureAvFoundation *) object { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/capture.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/capture.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/capture.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/capture.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -45,7 +45,7 @@ QList Capture::listTracks(const QString &mimeType) { - Q_UNUSED(mimeType); + Q_UNUSED(mimeType) return QList(); } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/capture.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/capture.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/capture.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/capture.h 2021-02-15 15:25:23.000000000 +0000 @@ -26,7 +26,7 @@ class AkCaps; class AkPacket; -typedef QSharedPointer CapturePtr; +using CapturePtr = QSharedPointer; class Capture: public QObject { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/convertvideo.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/convertvideo.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/convertvideo.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/convertvideo.h 2021-02-15 15:25:23.000000000 +0000 @@ -26,7 +26,7 @@ class AkCaps; class AkPacket; -typedef QSharedPointer ConvertVideoPtr; +using ConvertVideoPtr = QSharedPointer; class ConvertVideo: public QObject { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/dshow/src/capturedshow.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/dshow/src/capturedshow.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/dshow/src/capturedshow.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/dshow/src/capturedshow.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -49,7 +49,7 @@ return guid1.Data1 < guid2.Data1; } -typedef QMap VideoProcAmpPropertyMap; +using VideoProcAmpPropertyMap = QMap; inline VideoProcAmpPropertyMap initVideoProcAmpPropertyMap() { @@ -71,7 +71,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(VideoProcAmpPropertyMap, vpapToStr, (initVideoProcAmpPropertyMap())) -typedef QMap CameraControlMap; +using CameraControlMap = QMap; inline CameraControlMap initCameraControlMap() { @@ -90,74 +90,74 @@ Q_GLOBAL_STATIC_WITH_ARGS(CameraControlMap, ccToStr, (initCameraControlMap())) -typedef QMap GuidToStrMap; +using GuidToStrMap = QMap; inline GuidToStrMap initGuidToStrMap() { GuidToStrMap guidToStr = { - {MEDIASUBTYPE_CLPL , "CLPL"}, - {MEDIASUBTYPE_YUYV , "YUYV"}, - {MEDIASUBTYPE_IYUV , "IYUV"}, - {MEDIASUBTYPE_YVU9 , "YVU9"}, - {MEDIASUBTYPE_Y411 , "Y411"}, - {MEDIASUBTYPE_Y41P , "Y41P"}, - {MEDIASUBTYPE_YUY2 , "YUY2"}, - {MEDIASUBTYPE_YVYU , "YVYU"}, - {MEDIASUBTYPE_UYVY , "UYVY"}, - {MEDIASUBTYPE_Y211 , "Y211"}, - {MEDIASUBTYPE_CLJR , "CLJR"}, - {MEDIASUBTYPE_IF09 , "IF09"}, - {MEDIASUBTYPE_CPLA , "CPLA"}, - {MEDIASUBTYPE_MJPG , "MJPG"}, - {MEDIASUBTYPE_TVMJ , "TVMJ"}, - {MEDIASUBTYPE_WAKE , "WAKE"}, - {MEDIASUBTYPE_CFCC , "CFCC"}, - {MEDIASUBTYPE_IJPG , "IJPG"}, - {MEDIASUBTYPE_Plum , "Plum"}, - {MEDIASUBTYPE_DVCS , "DVCS"}, - {MEDIASUBTYPE_DVSD , "DVSD"}, - {MEDIASUBTYPE_MDVF , "MDVF"}, - {MEDIASUBTYPE_RGB1 , "RGB1"}, - {MEDIASUBTYPE_RGB4 , "BGR0"}, - {MEDIASUBTYPE_RGB8 , "RGB8"}, - {MEDIASUBTYPE_RGB565 , "RGBP"}, - {MEDIASUBTYPE_RGB555 , "RGBO"}, - {MEDIASUBTYPE_RGB24 , "RGB3"}, - {MEDIASUBTYPE_RGB32 , "BGR0"}, - {MEDIASUBTYPE_ARGB1555 , "AR15"}, - {MEDIASUBTYPE_ARGB4444 , "AR12"}, - {MEDIASUBTYPE_ARGB32 , "BA24"}, - {MEDIASUBTYPE_AYUV , "AYUV"}, - {MEDIASUBTYPE_AI44 , "AI44"}, - {MEDIASUBTYPE_IA44 , "IA44"}, - {MEDIASUBTYPE_RGB32_D3D_DX7_RT , "7R32"}, - {MEDIASUBTYPE_RGB16_D3D_DX7_RT , "7R16"}, - {MEDIASUBTYPE_ARGB32_D3D_DX7_RT , "7A88"}, - {MEDIASUBTYPE_ARGB4444_D3D_DX7_RT, "7A44"}, - {MEDIASUBTYPE_ARGB1555_D3D_DX7_RT, "7A15"}, - {MEDIASUBTYPE_RGB32_D3D_DX9_RT , "9R32"}, - {MEDIASUBTYPE_RGB16_D3D_DX9_RT , "9R16"}, - {MEDIASUBTYPE_ARGB32_D3D_DX9_RT , "9A88"}, - {MEDIASUBTYPE_ARGB4444_D3D_DX9_RT, "9A44"}, - {MEDIASUBTYPE_ARGB1555_D3D_DX9_RT, "9A15"}, - {MEDIASUBTYPE_YV12 , "YV12"}, - {MEDIASUBTYPE_NV12 , "NV12"}, - {MEDIASUBTYPE_IMC1 , "IMC1"}, - {MEDIASUBTYPE_IMC2 , "IMC2"}, - {MEDIASUBTYPE_IMC3 , "IMC3"}, - {MEDIASUBTYPE_IMC4 , "IMC4"}, - {MEDIASUBTYPE_S340 , "S340"}, - {MEDIASUBTYPE_S342 , "S342"}, - {MEDIASUBTYPE_QTRpza , "rpza"}, - {MEDIASUBTYPE_QTSmc , "smc "}, - {MEDIASUBTYPE_QTRle , "rle "}, - {MEDIASUBTYPE_QTJpeg , "jpeg"}, - {MEDIASUBTYPE_dvsd , "dvsd"}, - {MEDIASUBTYPE_dvhd , "dvhd"}, - {MEDIASUBTYPE_dvsl , "dvsl"}, - {MEDIASUBTYPE_dv25 , "dv25"}, - {MEDIASUBTYPE_dv50 , "dv50"}, - {MEDIASUBTYPE_dvh1 , "dvh1"} + {MEDIASUBTYPE_CLPL , "CLPL" }, + {MEDIASUBTYPE_YUYV , "YUYV" }, + {MEDIASUBTYPE_IYUV , "IYUV" }, + {MEDIASUBTYPE_YVU9 , "YVU9" }, + {MEDIASUBTYPE_Y411 , "Y411" }, + {MEDIASUBTYPE_Y41P , "Y41P" }, + {MEDIASUBTYPE_YUY2 , "YUY2" }, + {MEDIASUBTYPE_YVYU , "YVYU" }, + {MEDIASUBTYPE_UYVY , "UYVY" }, + {MEDIASUBTYPE_Y211 , "Y211" }, + {MEDIASUBTYPE_CLJR , "CLJR" }, + {MEDIASUBTYPE_IF09 , "IF09" }, + {MEDIASUBTYPE_CPLA , "CPLA" }, + {MEDIASUBTYPE_MJPG , "MJPG" }, + {MEDIASUBTYPE_TVMJ , "TVMJ" }, + {MEDIASUBTYPE_WAKE , "WAKE" }, + {MEDIASUBTYPE_CFCC , "CFCC" }, + {MEDIASUBTYPE_IJPG , "IJPG" }, + {MEDIASUBTYPE_Plum , "Plum" }, + {MEDIASUBTYPE_DVCS , "DVCS" }, + {MEDIASUBTYPE_DVSD , "DVSD" }, + {MEDIASUBTYPE_MDVF , "MDVF" }, + {MEDIASUBTYPE_RGB1 , "RGB1" }, + {MEDIASUBTYPE_RGB4 , "BGRX" }, + {MEDIASUBTYPE_RGB8 , "RGB8" }, + {MEDIASUBTYPE_RGB565 , "RGB565" }, + {MEDIASUBTYPE_RGB555 , "RGB555" }, + {MEDIASUBTYPE_RGB24 , "RGB" }, + {MEDIASUBTYPE_RGB32 , "BGRX" }, + {MEDIASUBTYPE_ARGB1555 , "ARGB555" }, + {MEDIASUBTYPE_ARGB4444 , "ARGB4444"}, + {MEDIASUBTYPE_ARGB32 , "ARGB" }, + {MEDIASUBTYPE_AYUV , "AYUV" }, + {MEDIASUBTYPE_AI44 , "AI44" }, + {MEDIASUBTYPE_IA44 , "IA44" }, + {MEDIASUBTYPE_RGB32_D3D_DX7_RT , "7R32" }, + {MEDIASUBTYPE_RGB16_D3D_DX7_RT , "7R16" }, + {MEDIASUBTYPE_ARGB32_D3D_DX7_RT , "7A88" }, + {MEDIASUBTYPE_ARGB4444_D3D_DX7_RT, "7A44" }, + {MEDIASUBTYPE_ARGB1555_D3D_DX7_RT, "7A15" }, + {MEDIASUBTYPE_RGB32_D3D_DX9_RT , "9R32" }, + {MEDIASUBTYPE_RGB16_D3D_DX9_RT , "9R16" }, + {MEDIASUBTYPE_ARGB32_D3D_DX9_RT , "9A88" }, + {MEDIASUBTYPE_ARGB4444_D3D_DX9_RT, "9A44" }, + {MEDIASUBTYPE_ARGB1555_D3D_DX9_RT, "9A15" }, + {MEDIASUBTYPE_YV12 , "YV12" }, + {MEDIASUBTYPE_NV12 , "NV12" }, + {MEDIASUBTYPE_IMC1 , "IMC1" }, + {MEDIASUBTYPE_IMC2 , "IMC2" }, + {MEDIASUBTYPE_IMC3 , "IMC3" }, + {MEDIASUBTYPE_IMC4 , "IMC4" }, + {MEDIASUBTYPE_S340 , "S340" }, + {MEDIASUBTYPE_S342 , "S342" }, + {MEDIASUBTYPE_QTRpza , "rpza" }, + {MEDIASUBTYPE_QTSmc , "smc " }, + {MEDIASUBTYPE_QTRle , "rle " }, + {MEDIASUBTYPE_QTJpeg , "jpeg" }, + {MEDIASUBTYPE_dvsd , "dvsd" }, + {MEDIASUBTYPE_dvhd , "dvhd" }, + {MEDIASUBTYPE_dvsl , "dvsl" }, + {MEDIASUBTYPE_dv25 , "dv25" }, + {MEDIASUBTYPE_dv50 , "dv50" }, + {MEDIASUBTYPE_dvh1 , "dvh1" }, }; return guidToStr; @@ -165,7 +165,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(GuidToStrMap, guidToStr, (initGuidToStrMap())) -typedef QMap IoMethodMap; +using IoMethodMap = QMap; inline IoMethodMap initIoMethodMap() { @@ -180,24 +180,24 @@ Q_GLOBAL_STATIC_WITH_ARGS(IoMethodMap, ioMethodToStr, (initIoMethodMap())) -typedef QSharedPointer GraphBuilderPtr; -typedef QSharedPointer BaseFilterPtr; -typedef QSharedPointer SampleGrabberPtr; -typedef QSharedPointer StreamConfigPtr; -typedef QSharedPointer FrameGrabberPtr; -typedef QSharedPointer MonikerPtr; -typedef QMap MonikersMap; -typedef QSharedPointer MediaTypePtr; -typedef QList MediaTypesList; -typedef QSharedPointer PinPtr; -typedef QList PinList; +using BaseFilterPtr = QSharedPointer; +using SampleGrabberPtr = QSharedPointer; +using MonikerPtr = QSharedPointer; +using MonikersMap = QMap; +using MediaTypePtr = QSharedPointer; +using MediaTypesList = QList; +using PinPtr = QSharedPointer; +using PinList = QList; class CaptureDShowPrivate { public: - QStringList m_webcams; + CaptureDShow *self; QString m_device; QList m_streams; + QStringList m_devices; + QMap m_descriptions; + QMap m_devicesCaps; qint64 m_id {-1}; AkFrac m_timeBase; CaptureDShow::IoMethod m_ioMethod {CaptureDShow::IoMethodGrabSample}; @@ -215,14 +215,18 @@ QVariantMap m_localImageControls; QVariantMap m_localCameraControls; + explicit CaptureDShowPrivate(CaptureDShow *self); + QString devicePath(IPropertyBag *propertyBag) const; + QString deviceDescription(IPropertyBag *propertyBag) const; + QVariantList caps(IBaseFilter *baseFilter) const; AkCaps capsFromMediaType(const AM_MEDIA_TYPE *mediaType) const; AkCaps capsFromMediaType(const MediaTypePtr &mediaType) const; HRESULT enumerateCameras(IEnumMoniker **ppEnum) const; MonikersMap listMonikers() const; MonikerPtr findMoniker(const QString &webcam) const; + QString monikerDisplayName(IMoniker *moniker) const; IBaseFilter *findFilterP(const QString &webcam) const; BaseFilterPtr findFilter(const QString &webcam) const; - MediaTypesList listMediaTypes(const QString &webcam) const; MediaTypesList listMediaTypes(IBaseFilter *filter) const; bool isPinConnected(IPin *pPin, bool *ok=nullptr) const; PinPtr findUnconnectedPin(IBaseFilter *pFilter, @@ -232,10 +236,8 @@ IBaseFilter *pDest) const; PinList enumPins(IBaseFilter *filter, PIN_DIRECTION direction) const; - static void deleteUnknown(IUnknown *unknown); static void freeMediaType(AM_MEDIA_TYPE &mediaType); static void deleteMediaType(AM_MEDIA_TYPE *mediaType); - static void deletePin(IPin *pin); QVariantList imageControls(IBaseFilter *filter) const; bool setImageControls(IBaseFilter *filter, const QVariantMap &imageControls) const; @@ -245,21 +247,22 @@ QVariantMap controlStatus(const QVariantList &controls) const; QVariantMap mapDiff(const QVariantMap &map1, const QVariantMap &map2) const; + void frameReceived(qreal time, const QByteArray &buffer); + void updateDevices(); }; CaptureDShow::CaptureDShow(QObject *parent): Capture(parent), QAbstractNativeEventFilter() { - this->d = new CaptureDShowPrivate; - + this->d = new CaptureDShowPrivate(this); QObject::connect(&this->d->m_frameGrabber, &FrameGrabber::frameReady, - this, - &CaptureDShow::frameReceived, - Qt::DirectConnection); - + [this] (qreal time, const QByteArray &packet) { + this->d->frameReceived(time, packet); + }); qApp->installNativeEventFilter(this); + this->d->updateDevices(); } CaptureDShow::~CaptureDShow() @@ -270,7 +273,7 @@ QStringList CaptureDShow::webcams() const { - return this->d->listMonikers().keys(); + return this->d->m_devices; } QString CaptureDShow::device() const @@ -283,21 +286,21 @@ if (!this->d->m_streams.isEmpty()) return this->d->m_streams; - QVariantList caps = this->caps(this->d->m_device); + auto caps = this->caps(this->d->m_device); if (caps.isEmpty()) - return QList(); + return {}; - return QList() << 0; + return {0}; } QList CaptureDShow::listTracks(const QString &mimeType) { if (mimeType != "video/x-raw" && !mimeType.isEmpty()) - return QList(); + return {}; - QVariantList caps = this->caps(this->d->m_device); + auto caps = this->caps(this->d->m_device); QList streams; for (int i = 0; i < caps.count(); i++) @@ -318,63 +321,18 @@ QString CaptureDShow::description(const QString &webcam) const { - if (webcam.isEmpty()) - return QString(); - - MonikerPtr moniker = this->d->findMoniker(webcam); - - if (!moniker) - return QString(); - - IPropertyBag *pPropBag = nullptr; - HRESULT hr = moniker->BindToStorage(nullptr, - nullptr, - IID_IPropertyBag, - reinterpret_cast(&pPropBag)); - - if (FAILED(hr)) - return QString(); - - VARIANT var; - VariantInit(&var); - - // Get description or friendly name. - hr = pPropBag->Read(L"Description", &var, nullptr); - - if (FAILED(hr)) - hr = pPropBag->Read(L"FriendlyName", &var, nullptr); - - QString description; - - if (SUCCEEDED(hr)) - description = QString::fromWCharArray(var.bstrVal); - - pPropBag->Release(); - - return description; + return this->d->m_descriptions.value(webcam); } QVariantList CaptureDShow::caps(const QString &webcam) const { - QVariantList caps; - MediaTypesList mediaTypes = this->d->listMediaTypes(webcam); - - for (const MediaTypePtr &mediaType: mediaTypes) { - AkCaps videoCaps = this->d->capsFromMediaType(mediaType); - - if (!videoCaps) - continue; - - caps << QVariant::fromValue(videoCaps); - } - - return caps; + return this->d->m_devicesCaps.value(webcam); } QString CaptureDShow::capsDescription(const AkCaps &caps) const { if (caps.mimeType() != "video/unknown") - return QString(); + return {}; AkFrac fps = caps.property("fps").toString(); @@ -397,8 +355,8 @@ this->d->m_controlsMutex.unlock(); for (int i = 0; i < globalImageControls.count(); i++) { - QVariantList control = globalImageControls[i].toList(); - QString controlName = control[0].toString(); + auto control = globalImageControls[i].toList(); + auto controlName = control[0].toString(); if (imageControls.contains(controlName)) { control[6] = imageControls[controlName]; @@ -426,8 +384,8 @@ { QVariantMap controls; - for (const QVariant &control: this->imageControls()) { - QVariantList params = control.toList(); + for (auto &control: this->imageControls()) { + auto params = control.toList(); controls[params[0].toString()] = params[5].toInt(); } @@ -446,8 +404,8 @@ this->d->m_controlsMutex.unlock(); for (int i = 0; i < globalCameraControls.count(); i++) { - QVariantList control = globalCameraControls[i].toList(); - QString controlName = control[0].toString(); + auto control = globalCameraControls[i].toList(); + auto controlName = control[0].toString(); if (cameraControls.contains(controlName)) { control[6] = cameraControls[controlName]; @@ -474,9 +432,8 @@ { QVariantMap controls; - for (const QVariant &control: this->cameraControls()) { - QVariantList params = control.toList(); - + for (auto &control: this->cameraControls()) { + auto params = control.toList(); controls[params[0].toString()] = params[5].toInt(); } @@ -521,9 +478,7 @@ this->d->freeMediaType(mediaType); AkPacket packet; - auto timestamp = QDateTime::currentMSecsSinceEpoch(); - auto pts = qint64(timestamp * this->d->m_timeBase.invert().value() @@ -542,7 +497,8 @@ this->d->m_curBuffer.constData(), size_t(bufferSize)); - packet = AkPacket(caps, oBuffer); + packet = AkPacket(caps); + packet.setBuffer(oBuffer); packet.setPts(pts); packet.setTimeBase(this->d->m_timeBase); packet.setIndex(0); @@ -557,16 +513,17 @@ HRESULT hr = this->d->m_grabber->GetCurrentBuffer(&bufferSize, nullptr); if (FAILED(hr)) - return AkPacket(); + return {}; QByteArray oBuffer(bufferSize, 0); hr = this->d->m_grabber->GetCurrentBuffer(&bufferSize, reinterpret_cast(oBuffer.data())); if (FAILED(hr)) - return AkPacket(); + return {}; - packet = AkPacket(caps, oBuffer); + packet = AkPacket(caps); + packet.setBuffer(oBuffer); packet.setPts(pts); packet.setTimeBase(this->d->m_timeBase); packet.setIndex(0); @@ -580,7 +537,7 @@ void *message, long *result) { - Q_UNUSED(eventType); + Q_UNUSED(eventType) if (!message) return false; @@ -592,13 +549,7 @@ case DBT_DEVICEARRIVAL: case DBT_DEVICEREMOVECOMPLETE: case DBT_DEVNODES_CHANGED: { - auto webcams = this->webcams(); - - if (webcams != this->d->m_webcams) { - emit this->webcamsChanged(webcams); - - this->d->m_webcams = webcams; - } + this->d->updateDevices(); if (result) *result = TRUE; @@ -613,17 +564,92 @@ return false; } +CaptureDShowPrivate::CaptureDShowPrivate(CaptureDShow *self): + self(self) +{ + +} + +QString CaptureDShowPrivate::devicePath(IPropertyBag *propertyBag) const +{ + VARIANT var; + VariantInit(&var); + auto hr = propertyBag->Read(L"DevicePath", &var, nullptr); + QString devicePath; + + if (SUCCEEDED(hr)) + devicePath = QString::fromWCharArray(var.bstrVal); + + VariantClear(&var); + + return devicePath; +} + +QString CaptureDShowPrivate::deviceDescription(IPropertyBag *propertyBag) const +{ + + VARIANT var; + VariantInit(&var); + auto hr = propertyBag->Read(L"Description", &var, nullptr); + + if (FAILED(hr)) + hr = propertyBag->Read(L"FriendlyName", &var, nullptr); + + QString description; + + if (SUCCEEDED(hr)) + description = QString::fromWCharArray(var.bstrVal); + + VariantClear(&var); + + return description; +} + +QVariantList CaptureDShowPrivate::caps(IBaseFilter *baseFilter) const +{ + auto pins = this->enumPins(baseFilter, PINDIR_OUTPUT); + QVariantList caps; + + for (auto &pin: pins) { + IEnumMediaTypes *pEnum = nullptr; + + if (FAILED(pin->EnumMediaTypes(&pEnum))) + continue; + + pEnum->Reset(); + AM_MEDIA_TYPE *mediaType = nullptr; + + while (pEnum->Next(1, &mediaType, nullptr) == S_OK) { + if (mediaType->formattype == FORMAT_VideoInfo + && mediaType->cbFormat >= sizeof(VIDEOINFOHEADER) + && mediaType->pbFormat != nullptr + && guidToStr->contains(mediaType->subtype)) { + auto videoCaps = this->capsFromMediaType(mediaType); + + if (videoCaps) + caps << QVariant::fromValue(videoCaps); + } + + this->deleteMediaType(mediaType); + } + + pEnum->Release(); + } + + return caps; +} + AkCaps CaptureDShowPrivate::capsFromMediaType(const AM_MEDIA_TYPE *mediaType) const { if (!mediaType) - return AkCaps(); + return {}; VIDEOINFOHEADER *videoInfoHeader = reinterpret_cast(mediaType->pbFormat); QString fourcc = guidToStr->value(mediaType->subtype); if (fourcc.isEmpty()) - return AkCaps(); + return {}; AkCaps videoCaps; videoCaps.setMimeType("video/unknown"); @@ -689,20 +715,15 @@ continue; } - VARIANT var; - VariantInit(&var); - hr = pPropBag->Read(L"DevicePath", &var, nullptr); - - QString devicePath; + auto devicePath = this->devicePath(pPropBag); - if (SUCCEEDED(hr)) - devicePath = QString::fromWCharArray(var.bstrVal); - else - devicePath = QString("/dev/video%1").arg(i); + if (devicePath.isEmpty()) + devicePath = this->monikerDisplayName(pMoniker); - monikers[devicePath] = MonikerPtr(pMoniker, this->deleteUnknown); - - VariantClear(&var); + monikers[devicePath] = + MonikerPtr(pMoniker, [] (IMoniker *moniker) { + moniker->Release(); + }); pPropBag->Release(); } @@ -722,15 +743,28 @@ return {}; } +QString CaptureDShowPrivate::monikerDisplayName(IMoniker *moniker) const +{ + IBindCtx *bind_ctx = nullptr; + + if (FAILED(CreateBindCtx(0, &bind_ctx))) + return {}; + + LPOLESTR olestr = nullptr; + moniker->GetDisplayName(bind_ctx, nullptr, &olestr); + bind_ctx->Release(); + + return QString::fromWCharArray(olestr); +} + IBaseFilter *CaptureDShowPrivate::findFilterP(const QString &webcam) const { - MonikerPtr moniker = this->findMoniker(webcam); + auto moniker = this->findMoniker(webcam); if (!moniker) return nullptr; IBaseFilter *filter = nullptr; - HRESULT hr = moniker->BindToObject(nullptr, nullptr, IID_IBaseFilter, @@ -744,27 +778,22 @@ BaseFilterPtr CaptureDShowPrivate::findFilter(const QString &webcam) const { - IBaseFilter *filter = this->findFilterP(webcam); + auto filter = this->findFilterP(webcam); if (!filter) - return BaseFilterPtr(); + return {}; - return BaseFilterPtr(filter, this->deleteUnknown); -} - -MediaTypesList CaptureDShowPrivate::listMediaTypes(const QString &webcam) const -{ - BaseFilterPtr filter = this->findFilter(webcam); - - return this->listMediaTypes(filter.data()); + return BaseFilterPtr(filter, [] (IBaseFilter *filter) { + filter->Release(); + }); } MediaTypesList CaptureDShowPrivate::listMediaTypes(IBaseFilter *filter) const { - PinList pins = this->enumPins(filter, PINDIR_OUTPUT); + auto pins = this->enumPins(filter, PINDIR_OUTPUT); MediaTypesList mediaTypes; - for (const PinPtr &pin: pins) { + for (auto &pin: pins) { IEnumMediaTypes *pEnum = nullptr; if (FAILED(pin->EnumMediaTypes(&pEnum))) @@ -821,7 +850,7 @@ IEnumPins *pEnum = nullptr; if (FAILED(pFilter->EnumPins(&pEnum))) - return PinPtr(); + return {}; pEnum->Reset(); PinPtr matchedPin; @@ -840,7 +869,9 @@ if (!ok || connected) continue; - matchedPin = PinPtr(pPin, this->deletePin); + matchedPin = PinPtr(pPin, [] (IPin *pin) { + pin->Release(); + }); pPin->AddRef(); break; @@ -891,7 +922,9 @@ if (SUCCEEDED(pin->QueryDirection(&pinDir)) && pinDir == direction) { - pinList << PinPtr(pin, this->deleteUnknown); + pinList << PinPtr(pin, [] (IPin *pin) { + pin->Release(); + }); continue; } @@ -905,11 +938,6 @@ return pinList; } -void CaptureDShowPrivate::deleteUnknown(IUnknown *unknown) -{ - unknown->Release(); -} - void CaptureDShowPrivate::freeMediaType(AM_MEDIA_TYPE &mediaType) { if (mediaType.cbFormat) { @@ -934,59 +962,74 @@ CoTaskMemFree(mediaType); } -void CaptureDShowPrivate::deletePin(IPin *pin) -{ - pin->Release(); -} - QVariantList CaptureDShowPrivate::imageControls(IBaseFilter *filter) const { if (!filter) return QVariantList(); - qint32 min; - qint32 max; - qint32 step; - qint32 defaultValue; - qint32 flags; - qint32 value; + qint32 min = 0; + qint32 max = 0; + qint32 step = 0; + qint32 defaultValue = 0; + qint32 value = 0; + qint32 flags = 0; QVariantList controls; IAMVideoProcAmp *pProcAmp = nullptr; if (SUCCEEDED(filter->QueryInterface(IID_IAMVideoProcAmp, reinterpret_cast(&pProcAmp)))) { - for (const VideoProcAmpProperty &property: vpapToStr->keys()) { - if (SUCCEEDED(pProcAmp->GetRange(property, + for (auto it = vpapToStr->begin(); it != vpapToStr->end(); it++) { + if (SUCCEEDED(pProcAmp->GetRange(it.key(), reinterpret_cast(&min), reinterpret_cast(&max), reinterpret_cast(&step), reinterpret_cast(&defaultValue), - reinterpret_cast(&flags)))) - if (SUCCEEDED(pProcAmp->Get(property, + reinterpret_cast(&flags)))) { + bool autoSupport = flags & VideoProcAmp_Flags_Auto; + bool manualSupport = flags & VideoProcAmp_Flags_Manual; + + if (SUCCEEDED(pProcAmp->Get(it.key(), reinterpret_cast(&value), reinterpret_cast(&flags)))) { - QVariantList control; - - QString type; + if (autoSupport) { + QVariantList control { + it.value() + " (Auto)", + QString("boolean"), + 0, + 1, + 1, + 1, + flags & VideoProcAmp_Flags_Auto, + QStringList() + }; + + controls << QVariant(control); + } + + if (manualSupport) { + QString type; + + if (min == 0 && max == 1) + type = "boolean"; + else + type = "integer"; + + QVariantList control { + it.value(), + type, + min, + max, + step, + defaultValue, + value, + QStringList() + }; - if (property == VideoProcAmp_ColorEnable - || property == VideoProcAmp_BacklightCompensation) - type = "boolean"; - else - type = "integer"; - - control << vpapToStr->value(property) - << type - << min - << max - << step - << defaultValue - << value - << QStringList(); - - controls << QVariant(control); + controls << QVariant(control); + } } + } } pProcAmp->Release(); @@ -1005,13 +1048,33 @@ if (SUCCEEDED(filter->QueryInterface(IID_IAMVideoProcAmp, reinterpret_cast(&pProcAmp)))) { - for (const VideoProcAmpProperty &property: vpapToStr->keys()) { - QString propertyStr = vpapToStr->value(property); + for (auto it = vpapToStr->begin(); it != vpapToStr->end(); it++) { + auto key = it.value(); - if (imageControls.contains(propertyStr)) - pProcAmp->Set(property, - imageControls[propertyStr].toInt(), - VideoProcAmp_Flags_Manual); + if (imageControls.contains(key)) { + LONG value = 0; + LONG flags = 0; + pProcAmp->Get(it.key(), + reinterpret_cast(&value), + reinterpret_cast(&flags)); + value = imageControls[key].toInt(); + pProcAmp->Set(it.key(), value, flags); + } + + if (imageControls.contains(key + " (Auto)")) { + LONG value = 0; + LONG flags = 0; + pProcAmp->Get(it.key(), + reinterpret_cast(&value), + reinterpret_cast(&flags)); + + if (imageControls[key + " (Auto)"].toBool()) + flags |= VideoProcAmp_Flags_Auto; + else + flags &= ~VideoProcAmp_Flags_Auto; + + pProcAmp->Set(it.key(), value, flags); + } } pProcAmp->Release(); @@ -1025,41 +1088,69 @@ if (!filter) return QVariantList(); - qint32 min; - qint32 max; - qint32 step; - qint32 defaultValue; - qint32 flags; - qint32 value; + qint32 min = 0; + qint32 max = 0; + qint32 step = 0; + qint32 defaultValue = 0; + qint32 value = 0; + qint32 flags = 0; QVariantList controls; IAMCameraControl *pCameraControl = nullptr; if (SUCCEEDED(filter->QueryInterface(IID_IAMCameraControl, reinterpret_cast(&pCameraControl)))) { - for (const CameraControlProperty &cameraControl: ccToStr->keys()) { - if (SUCCEEDED(pCameraControl->GetRange(cameraControl, + for (auto it = ccToStr->begin(); it != ccToStr->end(); it++) { + if (SUCCEEDED(pCameraControl->GetRange(it.key(), reinterpret_cast(&min), reinterpret_cast(&max), reinterpret_cast(&step), reinterpret_cast(&defaultValue), - reinterpret_cast(&flags)))) - if (SUCCEEDED(pCameraControl->Get(cameraControl, + reinterpret_cast(&flags)))) { + bool autoSupport = flags & CameraControl_Flags_Auto; + bool manualSupport = flags & CameraControl_Flags_Manual; + + if (SUCCEEDED(pCameraControl->Get(it.key(), reinterpret_cast(&value), reinterpret_cast(&flags)))) { - QVariantList control; - - control << ccToStr->value(cameraControl) - << QString("integer") - << min - << max - << step - << defaultValue - << value - << QStringList(); + if (autoSupport) { + QVariantList control { + it.value() + " (Auto)", + QString("boolean"), + 0, + 1, + 1, + 1, + flags & CameraControl_Flags_Auto, + QStringList() + }; + + controls << QVariant(control); + } + + if (manualSupport) { + QString type; + + if (min == 0 && max == 1) + type = "boolean"; + else + type = "integer"; + + QVariantList control { + it.value(), + type, + min, + max, + step, + defaultValue, + value, + QStringList() + }; - controls << QVariant(control); + controls << QVariant(control); + } } + } } pCameraControl->Release(); @@ -1078,13 +1169,33 @@ if (SUCCEEDED(filter->QueryInterface(IID_IAMCameraControl, reinterpret_cast(&pCameraControl)))) { - for (const CameraControlProperty &cameraControl: ccToStr->keys()) { - QString cameraControlStr = ccToStr->value(cameraControl); + for (auto it = ccToStr->begin(); it != ccToStr->end(); it++) { + auto key = it.value(); + + if (cameraControls.contains(key)) { + LONG value = 0; + LONG flags = 0; + pCameraControl->Get(it.key(), + reinterpret_cast(&value), + reinterpret_cast(&flags)); + value = cameraControls[key].toInt(); + pCameraControl->Set(it.key(), value, flags); + } - if (cameraControls.contains(cameraControlStr)) - pCameraControl->Set(cameraControl, - cameraControls[cameraControlStr].toInt(), - CameraControl_Flags_Manual); + if (cameraControls.contains(key + " (Auto)")) { + LONG value = 0; + LONG flags = 0; + pCameraControl->Get(it.key(), + reinterpret_cast(&value), + reinterpret_cast(&flags)); + + if (cameraControls[key + " (Auto)"].toBool()) + flags |= CameraControl_Flags_Auto; + else + flags &= ~CameraControl_Flags_Auto; + + pCameraControl->Set(it.key(), value, flags); + } } pCameraControl->Release(); @@ -1098,8 +1209,8 @@ QVariantMap controlStatus; for (auto &control: controls) { - QVariantList params = control.toList(); - QString controlName = params[0].toString(); + auto params = control.toList(); + auto controlName = params[0].toString(); controlStatus[controlName] = params[6]; } @@ -1120,6 +1231,92 @@ return map; } +void CaptureDShowPrivate::frameReceived(qreal time, const QByteArray &buffer) +{ + Q_UNUSED(time) + + this->m_mutex.lock(); + this->m_curBuffer = buffer; + this->m_waitCondition.wakeAll(); + this->m_mutex.unlock(); +} + +void CaptureDShowPrivate::updateDevices() +{ + decltype(this->m_devices) devices; + decltype(this->m_descriptions) descriptions; + decltype(this->m_devicesCaps) devicesCaps; + + MonikersMap monikers; + IEnumMoniker *pEnum = nullptr; + HRESULT hr = this->enumerateCameras(&pEnum); + + if (SUCCEEDED(hr)) { + pEnum->Reset(); + IMoniker *moniker = nullptr; + + for (int i = 0; pEnum->Next(1, &moniker, nullptr) == S_OK; i++) { + IPropertyBag *propertyBag = nullptr; + HRESULT hr = moniker->BindToStorage(nullptr, + nullptr, + IID_IPropertyBag, + reinterpret_cast(&propertyBag)); + + if (FAILED(hr)) { + moniker->Release(); + + continue; + } + + auto devicePath = this->devicePath(propertyBag); + + if (devicePath.isEmpty()) + devicePath = this->monikerDisplayName(moniker); + + auto description = this->deviceDescription(propertyBag); + propertyBag->Release(); + + IBaseFilter *baseFilter = nullptr; + hr = moniker->BindToObject(nullptr, + nullptr, + IID_IBaseFilter, + reinterpret_cast(&baseFilter)); + + if (FAILED(hr)) { + moniker->Release(); + + continue; + } + + auto caps = this->caps(baseFilter); + baseFilter->Release(); + + if (!caps.isEmpty()) { + devices << devicePath; + descriptions[devicePath] = description; + devicesCaps[devicePath] = caps; + } + + moniker->Release(); + } + + pEnum->Release(); + } + + if (devicesCaps.isEmpty()) { + devices.clear(); + descriptions.clear(); + } + + this->m_descriptions = descriptions; + this->m_devicesCaps = devicesCaps; + + if (this->m_devices != devices) { + this->m_devices = devices; + emit self->webcamsChanged(this->m_devices); + } +} + bool CaptureDShow::init() { this->d->m_localImageControls.clear(); @@ -1209,7 +1406,10 @@ hr = grabberPtr->SetCallback(&this->d->m_frameGrabber, type); } - this->d->m_grabber = SampleGrabberPtr(grabberPtr, this->d->deleteUnknown); + this->d->m_grabber = + SampleGrabberPtr(grabberPtr, [] (ISampleGrabber *sampleGrabber) { + sampleGrabber->Release(); + }); if (!this->d->connectFilters(this->d->m_graph, this->d->m_webcamFilter.data(), @@ -1292,7 +1492,7 @@ for (const PinPtr &pin: pins) { IAMStreamConfig *pStreamConfig = nullptr; - HRESULT hr = + auto hr = pin->QueryInterface(IID_IAMStreamConfig, reinterpret_cast(&pStreamConfig)); @@ -1421,7 +1621,7 @@ void CaptureDShow::setNBuffers(int nBuffers) { - Q_UNUSED(nBuffers); + Q_UNUSED(nBuffers) } void CaptureDShow::resetDevice() @@ -1456,14 +1656,4 @@ this->resetCameraControls(); } -void CaptureDShow::frameReceived(qreal time, const QByteArray &buffer) -{ - Q_UNUSED(time) - - this->d->m_mutex.lock(); - this->d->m_curBuffer = buffer; - this->d->m_waitCondition.wakeAll(); - this->d->m_mutex.unlock(); -} - #include "moc_capturedshow.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/dshow/src/capturedshow.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/dshow/src/capturedshow.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/dshow/src/capturedshow.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/dshow/src/capturedshow.h 2021-02-15 15:25:23.000000000 +0000 @@ -78,9 +78,6 @@ void resetIoMethod(); void resetNBuffers(); void reset(); - - private slots: - void frameReceived(qreal time, const QByteArray &buffer); }; #endif // CAPTUREDSHOW_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ffmpeg/src/convertvideoffmpeg.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ffmpeg/src/convertvideoffmpeg.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ffmpeg/src/convertvideoffmpeg.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ffmpeg/src/convertvideoffmpeg.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -62,32 +62,32 @@ // no AV correction is done if too big error #define AV_NOSYNC_THRESHOLD 10.0 -using V4l2PixFmtMap = QMap; +using ImgFmtMap = QMap; -inline V4l2PixFmtMap initV4l2PixFmtMap() +inline ImgFmtMap initImgFmtMap() { - V4l2PixFmtMap rawToFF = { + ImgFmtMap rawToFF = { // RGB formats - {"RGB1", AV_PIX_FMT_RGB8 }, - {"R444", AV_PIX_FMT_RGB444LE}, - {"RGBO", AV_PIX_FMT_RGB555LE}, - {"RGBP", AV_PIX_FMT_RGB565LE}, - {"RGBQ", AV_PIX_FMT_RGB555BE}, - {"RGBR", AV_PIX_FMT_RGB565BE}, - {"BGR3", AV_PIX_FMT_BGR24 }, - {"RGB3", AV_PIX_FMT_RGB24 }, - {"BGR0", AV_PIX_FMT_BGR0 }, - {"BGR4", AV_PIX_FMT_RGB0 }, - {"RGB4", AV_PIX_FMT_0RGB }, - {"ARGB", AV_PIX_FMT_ARGB }, - {"RGBA", AV_PIX_FMT_RGBA }, + {"RGB332" , AV_PIX_FMT_RGB8 }, + {"RGB444" , AV_PIX_FMT_RGB444LE}, + {"RGB555" , AV_PIX_FMT_RGB555LE}, + {"RGB565" , AV_PIX_FMT_RGB565LE}, + {"RGB555BE", AV_PIX_FMT_RGB555BE}, + {"RGB565BE", AV_PIX_FMT_RGB565BE}, + {"BGR" , AV_PIX_FMT_BGR24 }, + {"RGB" , AV_PIX_FMT_RGB24 }, + {"BGR0" , AV_PIX_FMT_BGR0 }, + {"BGRX" , AV_PIX_FMT_RGB0 }, + {"RGBX" , AV_PIX_FMT_0RGB }, + {"ARGB" , AV_PIX_FMT_ARGB }, + {"RGBA" , AV_PIX_FMT_RGBA }, // Grey formats - {"Y800", AV_PIX_FMT_GRAY8 }, - {"GREY", AV_PIX_FMT_GRAY8 }, - {"Y16 ", AV_PIX_FMT_GRAY16LE }, - {"B1W0", AV_PIX_FMT_MONOWHITE}, - {"B0W1", AV_PIX_FMT_MONOBLACK}, + {"Y800" , AV_PIX_FMT_GRAY8 }, + {"GRAY8" , AV_PIX_FMT_GRAY8 }, + {"GRAY16", AV_PIX_FMT_GRAY16LE }, + {"B1W0" , AV_PIX_FMT_MONOWHITE}, + {"B0W1" , AV_PIX_FMT_MONOBLACK}, // Palette formats {"PAL8", AV_PIX_FMT_PAL8}, @@ -116,19 +116,19 @@ {"NV16", AV_PIX_FMT_NV16}, // Bayer formats - {"BA81", AV_PIX_FMT_BAYER_BGGR8}, - {"GBRG", AV_PIX_FMT_BAYER_GBRG8}, - {"GRBG", AV_PIX_FMT_BAYER_GRBG8}, - {"RGGB", AV_PIX_FMT_BAYER_RGGB8}, + {"SBGGR8", AV_PIX_FMT_BAYER_BGGR8}, + {"SGBRG8", AV_PIX_FMT_BAYER_GBRG8}, + {"SGRBG8", AV_PIX_FMT_BAYER_GRBG8}, + {"SRGGB8", AV_PIX_FMT_BAYER_RGGB8}, // 10bit raw bayer, expanded to 16 bits - {"BYR2", AV_PIX_FMT_BAYER_BGGR16LE} + {"SBGGR16", AV_PIX_FMT_BAYER_BGGR16LE} }; return rawToFF; } -Q_GLOBAL_STATIC_WITH_ARGS(V4l2PixFmtMap, rawToFF, (initV4l2PixFmtMap())) +Q_GLOBAL_STATIC_WITH_ARGS(ImgFmtMap, rawToFF, (initImgFmtMap())) using V4l2CodecMap = QMap; @@ -537,7 +537,7 @@ nullptr, oFrame.linesize); - QByteArray oBuffer(frameSize, 0); + QByteArray oBuffer(frameSize, Qt::Uninitialized); if (av_image_fill_pointers(reinterpret_cast(oFrame.data), outPixFormat, @@ -556,24 +556,19 @@ oFrame.data, oFrame.linesize); - AkVideoCaps caps; - caps.isValid() = true; - caps.format() = AkVideoCaps::Format_rgb24; - caps.bpp() = AkVideoCaps::bitsPerPixel(caps.format()); - caps.width() = frame->width; - caps.height() = frame->height; - caps.fps() = this->m_fps; - // Create packet AkVideoPacket oPacket; - oPacket.caps() = caps; + oPacket.caps() = {AkVideoCaps::Format_rgb24, + frame->width, + frame->height, + this->m_fps}; oPacket.buffer() = oBuffer; oPacket.id() = this->m_id; oPacket.pts() = frame->pts; - oPacket.timeBase() = caps.fps().invert(); + oPacket.timeBase() = this->m_fps.invert(); oPacket.index() = 0; - emit self->frameReady(oPacket.toPacket()); + emit self->frameReady(oPacket); } void ConvertVideoFFmpegPrivate::log(qreal diff) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/generic.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/generic.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/generic.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/generic.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,61 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../akcommons.pri) { + include(../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +CONFIG += plugin + +HEADERS = \ + src/plugin.h \ + src/convertvideogeneric.h \ + ../convertvideo.h + +INCLUDEPATH += \ + ../../../../Lib/src \ + ../ + +LIBS += -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} + +OTHER_FILES += pspec.json + +SOURCES = \ + src/plugin.cpp \ + src/convertvideogeneric.cpp \ + ../convertvideo.cpp + +akModule = VideoCapture +DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,4 @@ +{ + "pluginType": "Ak.SubModule", + "type": "convert" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/convertvideogeneric.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/convertvideogeneric.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/convertvideogeneric.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/convertvideogeneric.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,113 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "convertvideogeneric.h" + +using ImgFmtMap = QMap; + +inline ImgFmtMap initImgFmtMap() +{ + ImgFmtMap rawToFF = { + {"B0W1" , AkVideoCaps::Format_monob }, + {"XRGB" , AkVideoCaps::Format_0rgb }, + {"ARGB" , AkVideoCaps::Format_argb }, + {"RGBA" , AkVideoCaps::Format_rgba }, + {"RGBX" , AkVideoCaps::Format_rgb0 }, + {"RGB565" , AkVideoCaps::Format_rgb565le}, + {"RGB555" , AkVideoCaps::Format_rgb555le}, + {"RGB" , AkVideoCaps::Format_rgb24 }, + {"RGB444" , AkVideoCaps::Format_rgb444le}, + {"BGR" , AkVideoCaps::Format_bgr24 }, + {"GRAY8" , AkVideoCaps::Format_gray }, + {"NV16" , AkVideoCaps::Format_nv16 }, + {"NV21" , AkVideoCaps::Format_nv21 }, + {"YUY2" , AkVideoCaps::Format_yuyv422 }, + {"YUYV" , AkVideoCaps::Format_yuyv422 }, + {"YV12" , AkVideoCaps::Format_yuv420p }, + {"Y422" , AkVideoCaps::Format_yuv422p }, + {"YU12" , AkVideoCaps::Format_yuv420p }, + {"I420" , AkVideoCaps::Format_yuv420p }, + {"YUV420P_888", AkVideoCaps::Format_yuv420p } + }; + + return rawToFF; +} + +Q_GLOBAL_STATIC_WITH_ARGS(ImgFmtMap, fourccToFormat, (initImgFmtMap())) + +ConvertVideoGeneric::ConvertVideoGeneric(QObject *parent): + ConvertVideo(parent) +{ +} + +ConvertVideoGeneric::~ConvertVideoGeneric() +{ +} + +void ConvertVideoGeneric::packetEnqueue(const AkPacket &packet) +{ + auto fourcc = packet.caps().property("fourcc").toString(); + AkVideoPacket videoPacket(packet); + + if (fourcc == "JPEG") { + videoPacket = + AkVideoPacket::fromImage(QImage::fromData(packet.buffer()), + packet); + } else { + AkVideoCaps caps(fourccToFormat->value(fourcc, + AkVideoCaps::Format_none), + packet.caps().property("width").toInt(), + packet.caps().property("height").toInt(), + packet.caps().property("fps").toString()); + + if (packet.caps().contains("align")) + caps.setAlign(packet.caps().property("align").toInt()); + + videoPacket.caps() = caps; + videoPacket.buffer() = packet.buffer(); + videoPacket.copyMetadata(packet); + videoPacket = videoPacket.convert(AkVideoCaps::Format_rgb24); + } + + if (videoPacket) + emit this->frameReady(videoPacket); +} + +bool ConvertVideoGeneric::init(const AkCaps &caps) +{ + Q_UNUSED(caps) + + return true; +} + +void ConvertVideoGeneric::uninit() +{ +} + +#include "moc_convertvideogeneric.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/convertvideogeneric.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/convertvideogeneric.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/convertvideogeneric.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/convertvideogeneric.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef CONVERTVIDEOGENERIC_H +#define CONVERTVIDEOGENERIC_H + +#include "convertvideo.h" + +class ConvertVideoGeneric: public ConvertVideo +{ + Q_OBJECT + + public: + ConvertVideoGeneric(QObject *parent=nullptr); + ~ConvertVideoGeneric(); + + Q_INVOKABLE void packetEnqueue(const AkPacket &packet); + Q_INVOKABLE bool init(const AkCaps &caps); + Q_INVOKABLE void uninit(); +}; + +#endif // CONVERTVIDEOGENERIC_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "convertvideogeneric.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new ConvertVideoGeneric(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return QStringList(); +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/generic/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/gstreamer/src/convertvideogstreamer.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/gstreamer/src/convertvideogstreamer.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/gstreamer/src/convertvideogstreamer.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/gstreamer/src/convertvideogstreamer.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,20 +33,19 @@ using StringStringMap = QMap; -inline StringStringMap initFourCCToGst() +inline const StringStringMap &initFourCCToGst() { - StringStringMap fourCCToGst = { + static const StringStringMap fourCCToGst = { // RGB formats - {"RGBO", "video/x-raw,format=RGB15"}, - {"RGBP", "video/x-raw,format=RGB16"}, - {"BGR3", "video/x-raw,format=BGR" }, - {"RGB3", "video/x-raw,format=RGB" }, - {"BGR4", "video/x-raw,format=BGRx" }, - {"RGB4", "video/x-raw,format=xRGB" }, + {"RGB555", "video/x-raw,format=RGB15"}, + {"RGB565", "video/x-raw,format=RGB16"}, + {"BGR" , "video/x-raw,format=BGR" }, + {"RGB" , "video/x-raw,format=RGB" }, + {"BGRX" , "video/x-raw,format=BGRx" }, + {"XRGB" , "video/x-raw,format=xRGB" }, // Grey formats - {"GREY", "video/x-raw,format=GRAY8"}, - {"Y04 ", "video/x-raw,format=Y41P" }, + {"GRAY8", "video/x-raw,format=GRAY8"}, // Luminance+Chrominance formats {"YVU9", "video/x-raw,format=YVU9"}, @@ -68,10 +69,10 @@ {"TM12", "video/x-raw,format=NV12_64Z32"}, // Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm - {"BA81", "video/x-bayer,format=bggr"}, - {"GBRG", "video/x-bayer,format=gbrg"}, - {"GRBG", "video/x-bayer,format=grbg"}, - {"RGGB", "video/x-bayer,format=rggb"}, + {"SBGGR8", "video/x-bayer,format=bggr"}, + {"SGBRG8", "video/x-bayer,format=gbrg"}, + {"SGRBG8", "video/x-bayer,format=grbg"}, + {"SRGGB8", "video/x-bayer,format=rggb"}, // compressed formats {"MJPG", "image/jpeg" }, @@ -164,23 +165,25 @@ int height = caps.property("height").toInt(); AkFrac fps = caps.property("fps").toString(); - AkCaps gstCaps = fourCCToGst->value(fourcc); - GstCaps *inCaps = nullptr; + auto gstCaps = fourCCToGst->value(fourcc); - if (gstCaps.mimeType() == "video/x-raw" - || gstCaps.mimeType() == "video/x-bayer" - || gstCaps.mimeType() == "video/x-pwc1" - || gstCaps.mimeType() == "video/x-pwc2" - || gstCaps.mimeType() == "video/x-sonix") { - gstCaps.setProperty("width", width); - gstCaps.setProperty("height", height); - gstCaps.setProperty("framerate", fps.toString()); - inCaps = gst_caps_from_string(gstCaps.toString().toStdString().c_str()); - } else if (!gstCaps.mimeType().isEmpty()) { - inCaps = gst_caps_from_string(gstCaps.toString().toStdString().c_str()); - } else + if (gstCaps.isEmpty()) return false; + auto inCaps = gst_caps_from_string(gstCaps.toStdString().c_str()); + + if (gstCaps.startsWith("video/x-raw") + || gstCaps.startsWith("video/x-bayer") + || gstCaps.startsWith("video/x-pwc1") + || gstCaps.startsWith("video/x-pwc2") + || gstCaps.startsWith("video/x-sonix")) { + gst_caps_set_simple(inCaps, + "width", width, + "height", height, + "framerate", fps.toString().toStdString().c_str(), + nullptr); + } + inCaps = gst_caps_fixate(inCaps); this->d->m_source = gst_element_factory_make("appsrc", nullptr); @@ -501,25 +504,22 @@ GstVideoInfo *videoInfo = gst_video_info_new(); gst_video_info_from_caps(videoInfo, caps); - // Create a package and return it. - AkVideoPacket oVideoPacket; - oVideoPacket.caps().isValid() = true; - oVideoPacket.caps().format() = AkVideoCaps::Format_rgb24; - oVideoPacket.caps().bpp() = AkVideoCaps::bitsPerPixel(oVideoPacket.caps().format()); - oVideoPacket.caps().width() = videoInfo->width; - oVideoPacket.caps().height() = videoInfo->height; - oVideoPacket.caps().fps() = AkFrac(videoInfo->fps_n, videoInfo->fps_d); - gst_video_info_free(videoInfo); GstBuffer *buffer = gst_sample_get_buffer(sample); GstMapInfo info; gst_buffer_map(buffer, &info, GST_MAP_READ); - - QByteArray oBuffer(int(info.size), 0); + QByteArray oBuffer(int(info.size), Qt::Uninitialized); memcpy(oBuffer.data(), info.data, info.size); + // Create a package and return it. + AkVideoPacket oVideoPacket; + oVideoPacket.caps() = {AkVideoCaps::Format_rgb24, + videoInfo->width, + videoInfo->height, + AkFrac(videoInfo->fps_n, videoInfo->fps_d)}; oVideoPacket.buffer() = oBuffer; + oVideoPacket.pts() = qint64(GST_BUFFER_PTS(buffer)); oVideoPacket.timeBase() = AkFrac(1, GST_SECOND); oVideoPacket.index() = 0; @@ -528,7 +528,7 @@ gst_buffer_unmap(buffer, &info); gst_sample_unref(sample); - emit self->frameReady(oVideoPacket.toPacket()); + emit self->frameReady(oVideoPacket); return GST_FLOW_OK; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/capturelibuvc.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/capturelibuvc.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/capturelibuvc.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/capturelibuvc.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -45,124 +45,21 @@ bool signd; QStringList menu; - inline static const QVector &controls() - { - static const QVector controls { - // Processing Units - {PROCESSING_UNIT, UVC_PU_CONTROL_UNDEFINED , "" , "" , false, {}}, - {PROCESSING_UNIT, UVC_PU_BACKLIGHT_COMPENSATION_CONTROL , "Backlight Compensation" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_BRIGHTNESS_CONTROL , "Brightness" , "integer", true , {}}, - {PROCESSING_UNIT, UVC_PU_CONTRAST_CONTROL , "Contrast" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_GAIN_CONTROL , "Gain" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_POWER_LINE_FREQUENCY_CONTROL , "Power Line Frequency" , "menu" , false, {"Disabled", - "50 Hz", - "60 Hz", - "Auto"}}, - {PROCESSING_UNIT, UVC_PU_HUE_CONTROL , "Hue" , "integer", true , {}}, - {PROCESSING_UNIT, UVC_PU_SATURATION_CONTROL , "Saturation" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_SHARPNESS_CONTROL , "Sharpness" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_GAMMA_CONTROL , "Gamma" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL , "White Balance Temperature" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, "White Balance Temperature Auto", "boolean", false, {}}, - {PROCESSING_UNIT, UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL , "White Balance Component" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL , "White Balance Component Auto" , "boolean", false, {}}, - {PROCESSING_UNIT, UVC_PU_DIGITAL_MULTIPLIER_CONTROL , "Digital Multiplier" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL , "Digital Multiplier Limit" , "integer", false, {}}, - {PROCESSING_UNIT, UVC_PU_HUE_AUTO_CONTROL , "Hue Auto" , "boolean", false, {}}, - {PROCESSING_UNIT, UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL , "Analog Video Standard" , "menu" , false, {"None", - "NTSC - 525/60", - "PAL - 625/50", - "SECAM - 625/50", - "NTSC - 625/50", - "PAL - 525/60"}}, - {PROCESSING_UNIT, UVC_PU_ANALOG_LOCK_STATUS_CONTROL , "Analog Lock Status" , "menu" , false, {"Locked", - "Unlocked"}}, - {PROCESSING_UNIT, UVC_PU_CONTRAST_AUTO_CONTROL , "Contrast Auto" , "boolean", false, {}}, - - // Camera Terminals - {CAMERA_TERMINAL, UVC_CT_CONTROL_UNDEFINED , "" , "" , false, {}}, - {CAMERA_TERMINAL, UVC_CT_SCANNING_MODE_CONTROL , "Scanning Mode" , "boolean", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_AE_MODE_CONTROL , "AE Mode" , "", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_AE_PRIORITY_CONTROL , "AE Priority" , "", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL , "Exposure Time Absolute" , "", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL , "Exposure Time Relative" , "", false, {}}, - {CAMERA_TERMINAL, UVC_CT_FOCUS_ABSOLUTE_CONTROL , "Focus Absolute" , "integer", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_FOCUS_RELATIVE_CONTROL , "Focus Relative" , "", false, {}}, - {CAMERA_TERMINAL, UVC_CT_FOCUS_AUTO_CONTROL , "Focus Auto" , "boolean", false, {}}, - {CAMERA_TERMINAL, UVC_CT_IRIS_ABSOLUTE_CONTROL , "Iris Absolute" , "integer", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_IRIS_RELATIVE_CONTROL , "Iris Relative" , "", false, {}}, - {CAMERA_TERMINAL, UVC_CT_ZOOM_ABSOLUTE_CONTROL , "Zoom Absolute" , "integer", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_ZOOM_RELATIVE_CONTROL , "Zoom Relative" , "", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_PANTILT_ABSOLUTE_CONTROL , "Pantilt Absolute" , "", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_PANTILT_RELATIVE_CONTROL , "Pantilt Relative" , "", false, {}}, - {CAMERA_TERMINAL, UVC_CT_ROLL_ABSOLUTE_CONTROL , "Roll Absolute" , "integer", true, {}}, - //{CAMERA_TERMINAL, UVC_CT_ROLL_RELATIVE_CONTROL , "Roll Relative" , "", false, {}}, - {CAMERA_TERMINAL, UVC_CT_PRIVACY_CONTROL , "Privacy" , "boolean", false, {}}, - {CAMERA_TERMINAL, UVC_CT_FOCUS_SIMPLE_CONTROL , "Focus Simple" , "menu" , false, {"Full Range", - "Macro", - "People", - "Scene"}}, - //{CAMERA_TERMINAL, UVC_CT_DIGITAL_WINDOW_CONTROL , "Digital Window" , "", false, {}}, - //{CAMERA_TERMINAL, UVC_CT_REGION_OF_INTEREST_CONTROL , "Region of Interest" , "", false, {}} - }; - - return controls; - } - - static inline const UvcControl *bySelector(int controlType, - uint8_t selector) - { - for (auto &control: controls()) - if (control.controlType == controlType - && control.selector == selector) - return &control; - - // Returns default for control type. - for (auto &control: controls()) - if (control.controlType == controlType) - return &control; - - return &controls().first(); - } - - static inline QVector allSelectors(int controlType) - { - QVector selectors; - - for (int i = 1; i < controls().size(); i++) - if (controls()[i].controlType == controlType) - selectors << controls()[i].selector; - - return selectors; - } + inline static const QVector &controls(); + inline static const UvcControl *bySelector(int controlType, + uint8_t selector); + inline static QVector allSelectors(int controlType); }; Q_GLOBAL_STATIC(UsbGlobals, usbGlobals) -using PixFmtToUvcMap = QMap; - -inline PixFmtToUvcMap initPixFmtToUvcMap() -{ - PixFmtToUvcMap fourccToUvc = { - {"YUY2", UVC_FRAME_FORMAT_YUYV }, - {"UYVY", UVC_FRAME_FORMAT_UYVY }, - {"RGB3", UVC_FRAME_FORMAT_RGB }, - {"BGR3", UVC_FRAME_FORMAT_BGR }, - {"MJPG", UVC_FRAME_FORMAT_MJPEG}, - {"Y800", UVC_FRAME_FORMAT_GRAY8}, -#ifdef UVC_FRAME_FORMAT_BY8 - {"BY8 ", UVC_FRAME_FORMAT_BY8 }, -#endif - }; - - return fourccToUvc; -} - -Q_GLOBAL_STATIC_WITH_ARGS(PixFmtToUvcMap, fourccToUvc, (initPixFmtToUvcMap())) +using PixFmtToStrMap = QMap; +using FourccToStrMap = QMap; class CaptureLibUVCPrivate { public: + CaptureLibUVC *self; QString m_device; QList m_streams; QMap m_devices; @@ -180,23 +77,27 @@ qint64 m_id {-1}; AkFrac m_fps; + explicit CaptureLibUVCPrivate(CaptureLibUVC *self); QVariantList controlsList(uvc_device_handle_t *deviceHnd, uint8_t unit, uint8_t control, int controlType) const; - void setControls(uvc_device_handle_t *deviceHnd, - uint8_t unit, - uint8_t control, - int controlType, - const QVariantMap &values); + int setControls(uvc_device_handle_t *deviceHnd, + uint8_t unit, + uint8_t control, + int controlType, + const QVariantMap &values); static void frameCallback(struct uvc_frame *frame, void *userData); QString fourccToStr(const uint8_t *format) const; + void updateDevices(); + inline static const PixFmtToStrMap &pixFmtToStr(); + inline static const FourccToStrMap &v4l2FourccToStr(); }; CaptureLibUVC::CaptureLibUVC(QObject *parent): Capture(parent) { - this->d = new CaptureLibUVCPrivate; + this->d = new CaptureLibUVCPrivate(this); auto uvcError = uvc_init(&this->d->m_uvcContext, usbGlobals->context()); if (uvcError != UVC_SUCCESS) { @@ -207,10 +108,10 @@ QObject::connect(usbGlobals, &UsbGlobals::devicesUpdated, - this, - &CaptureLibUVC::updateDevices); - - this->updateDevices(); + [this] () { + this->d->updateDevices(); + }); + this->d->updateDevices(); } CaptureLibUVC::~CaptureLibUVC() @@ -378,8 +279,7 @@ QVariantMap controls; for (auto &control: this->imageControls()) { - QVariantList params = control.toList(); - + auto params = control.toList(); controls[params[0].toString()] = params[5].toInt(); } @@ -471,8 +371,7 @@ QVariantMap controls; for (auto &control: this->cameraControls()) { - QVariantList params = control.toList(); - + auto params = control.toList(); controls[params[0].toString()] = params[5].toInt(); } @@ -487,11 +386,11 @@ if (!this->d->m_packetNotReady.wait(&this->d->m_mutex, TIME_OUT)) { this->d->m_mutex.unlock(); - return AkPacket(); + return {}; } auto packet = this->d->m_curPacket; - this->d->m_curPacket = AkPacket(); + this->d->m_curPacket = {}; this->d->m_mutex.unlock(); @@ -505,6 +404,12 @@ .arg(productId, 4, 16, QChar('0')); } +CaptureLibUVCPrivate::CaptureLibUVCPrivate(CaptureLibUVC *self): + self(self) +{ + +} + QVariantList CaptureLibUVCPrivate::controlsList(uvc_device_handle_t *deviceHnd, uint8_t unit, uint8_t control, @@ -522,7 +427,7 @@ int16_t val = 0; if (uvc_get_ctrl(deviceHnd, unit, control, &val, sizeof(int16_t), UVC_GET_CUR) < 0) - return QVariantList(); + return {}; value = val; uvc_get_ctrl(deviceHnd, unit, control, &val, sizeof(int16_t), UVC_GET_MIN); @@ -537,7 +442,7 @@ uint16_t val = 0; if (uvc_get_ctrl(deviceHnd, unit, control, &val, sizeof(int16_t), UVC_GET_CUR) < 0) - return QVariantList(); + return {}; value = val; uvc_get_ctrl(deviceHnd, unit, control, &val, sizeof(uint16_t), UVC_GET_MIN); @@ -553,7 +458,7 @@ uint8_t val = false; if (uvc_get_ctrl(deviceHnd, unit, control, &val, sizeof(int16_t), UVC_GET_CUR) < 0) - return QVariantList(); + return {}; value = val; uvc_get_ctrl(deviceHnd, unit, control, &val, sizeof(uint8_t), UVC_GET_MIN); @@ -568,7 +473,7 @@ uint8_t val = 0; if (uvc_get_ctrl(deviceHnd, unit, control, &val, sizeof(int16_t), UVC_GET_CUR) < 0) - return QVariantList(); + return {}; value = val; uvc_get_ctrl(deviceHnd, unit, control, &val, sizeof(uint8_t), UVC_GET_MIN); @@ -593,53 +498,53 @@ }; } -void CaptureLibUVCPrivate::setControls(uvc_device_handle_t *deviceHnd, - uint8_t unit, - uint8_t control, - int controlType, - const QVariantMap &values) +int CaptureLibUVCPrivate::setControls(uvc_device_handle_t *deviceHnd, + uint8_t unit, + uint8_t control, + int controlType, + const QVariantMap &values) { auto selector = UvcControl::bySelector(controlType, control); if (!values.contains(selector->description)) - return; + return -1; + + int result = -1; if (selector->type == "integer") { if (selector->signd) { auto val = int16_t(values[selector->description].toInt()); - - uvc_set_ctrl(deviceHnd, - unit, - control, - &val, - sizeof(int16_t)); + result = uvc_set_ctrl(deviceHnd, + unit, + control, + &val, + sizeof(int16_t)); } else { auto val = uint16_t(values[selector->description].toUInt()); - - uvc_set_ctrl(deviceHnd, - unit, - control, - &val, - sizeof(uint16_t)); + result = uvc_set_ctrl(deviceHnd, + unit, + control, + &val, + sizeof(uint16_t)); } } else if (selector->type == "boolean") { uint8_t val = values[selector->description].toBool(); - - uvc_set_ctrl(deviceHnd, - unit, - control, - &val, - sizeof(uint8_t)); + result = uvc_set_ctrl(deviceHnd, + unit, + control, + &val, + sizeof(uint8_t)); } else if (selector->type == "menu") { auto val = uint8_t(values[selector->description].toUInt()); - - uvc_set_ctrl(deviceHnd, - unit, - control, - &val, - sizeof(uint8_t)); + result = uvc_set_ctrl(deviceHnd, + unit, + control, + &val, + sizeof(uint8_t)); } + + return result; } void CaptureLibUVCPrivate::frameCallback(uvc_frame *frame, void *userData) @@ -647,32 +552,32 @@ if (!frame || !userData) return; - auto self = reinterpret_cast(userData); + auto self = reinterpret_cast(userData); - self->d->m_mutex.lock(); + self->m_mutex.lock(); - AkCaps caps; - caps.setMimeType("video/unknown"); - caps.setProperty("fourcc", fourccToUvc->key(frame->frame_format)); + AkCaps caps("video/unknown"); + caps.setProperty("fourcc", CaptureLibUVCPrivate::pixFmtToStr().value(frame->frame_format)); caps.setProperty("width", frame->width); caps.setProperty("height", frame->height); - caps.setProperty("fps", self->d->m_fps.toString()); + caps.setProperty("fps", self->m_fps.toString()); QByteArray buffer(reinterpret_cast(frame->data), int(frame->data_bytes)); auto pts = qint64(QTime::currentTime().msecsSinceStartOfDay() - * self->d->m_fps.value() / 1e3); + * self->m_fps.value() / 1e3); - AkPacket packet(caps, buffer); + AkPacket packet(caps); + packet.setBuffer(buffer); packet.setPts(pts); - packet.setTimeBase(self->d->m_fps.invert()); + packet.setTimeBase(self->m_fps.invert()); packet.setIndex(0); - packet.setId(self->d->m_id); + packet.setId(self->m_id); - self->d->m_curPacket = packet; - self->d->m_packetNotReady.wakeAll(); - self->d->m_mutex.unlock(); + self->m_curPacket = packet; + self->m_packetNotReady.wakeAll(); + self->m_mutex.unlock(); } QString CaptureLibUVCPrivate::fourccToStr(const uint8_t *format) const @@ -684,6 +589,250 @@ return QString(fourcc); } +void CaptureLibUVCPrivate::updateDevices() +{ + if (!this->m_uvcContext) + return; + + decltype(this->m_devices) devicesList; + decltype(this->m_descriptions) descriptions; + decltype(this->m_devicesCaps) devicesCaps; + decltype(this->m_imageControls) imageControls; + decltype(this->m_cameraControls) cameraControls; + + uvc_device_t **devices = nullptr; + auto error = uvc_get_device_list(this->m_uvcContext, &devices); + + if (error != UVC_SUCCESS) { + qDebug() << "CaptureLibUVC:" << uvc_strerror(error); + + goto updateDevices_failed; + } + + for (int i = 0; devices[i] != nullptr; i++) { + uvc_device_descriptor_t *descriptor = nullptr; + error = uvc_get_device_descriptor(devices[i], &descriptor); + + if (error != UVC_SUCCESS) { + qDebug() << "CaptureLibUVC:" << uvc_strerror(error); + + continue; + } + + auto deviceId = self->uvcId(descriptor->idVendor, + descriptor->idProduct); + uvc_device_handle_t *deviceHnd = nullptr; + + if (this->m_deviceHnd && this->m_curDevice == deviceId) + deviceHnd = this->m_deviceHnd; + else { + error = uvc_open(devices[i], &deviceHnd); + + if (error != UVC_SUCCESS) { + qDebug() << "CaptureLibUVC:" << uvc_strerror(error); + uvc_free_device_descriptor(descriptor); + + continue; + } + } + + auto formatDescription = uvc_get_format_descs(deviceHnd); + + if (!formatDescription) { + qDebug() << "CaptureLibUVC: Can't read format description"; + + if (!this->m_deviceHnd || this->m_curDevice != deviceId) + uvc_close(deviceHnd); + + uvc_free_device_descriptor(descriptor); + + continue; + } + + auto description = + usbIds->description(descriptor->idVendor, descriptor->idProduct); + + if (description.isEmpty()) { + if (QString(descriptor->manufacturer).isEmpty()) + description += QString("Vendor 0x%1") + .arg(descriptor->idVendor, 4, 16, QChar('0')); + else + description += QString(descriptor->manufacturer); + + description += ", "; + + if (QString(descriptor->product).isEmpty()) + description += QString("Product 0x%1") + .arg(descriptor->idProduct, 4, 16, QChar('0')); + else + description += QString(descriptor->product); + } + + devicesList[quint32((descriptor->idVendor << 16) + | descriptor->idProduct)] = deviceId; + descriptions[deviceId] = description; + devicesCaps[deviceId] = QVariantList(); + AkCaps videoCaps; + videoCaps.setMimeType("video/unknown"); + + for (; formatDescription; formatDescription = formatDescription->next) { + auto fourCC = this->fourccToStr(formatDescription->fourccFormat); + fourCC = CaptureLibUVCPrivate::v4l2FourccToStr().value(fourCC, + fourCC); + + if (std::find(CaptureLibUVCPrivate::pixFmtToStr().cbegin(), + CaptureLibUVCPrivate::pixFmtToStr().cend(), + fourCC) == CaptureLibUVCPrivate::pixFmtToStr().cend()) + continue; + + videoCaps.setProperty("fourcc", fourCC); + + for (auto description = formatDescription->frame_descs; + description; + description = description->next) { + videoCaps.setProperty("width", description->wWidth); + videoCaps.setProperty("height", description->wHeight); + + if (description->intervals) { + int prevInterval = 0; + + for (auto interval = description->intervals; interval && *interval; interval++) { + auto fps = AkFrac(100e5, *interval); + auto fpsValue = qRound(fps.value()); + + if (prevInterval != fpsValue) { + videoCaps.setProperty("fps", fps.toString()); + devicesCaps[deviceId] << QVariant::fromValue(videoCaps); + } + + prevInterval = fpsValue; + } + } else if (description->dwFrameIntervalStep > 0 + && description->dwMinFrameInterval != description->dwMaxFrameInterval) { + int prevInterval = 0; + + for (auto interval = description->dwMinFrameInterval; + interval <= description->dwMaxFrameInterval; + interval += description->dwFrameIntervalStep) { + auto fps = AkFrac(100e5, interval); + auto fpsValue = qRound(fps.value()); + + if (prevInterval != fpsValue) { + videoCaps.setProperty("fps", fps.toString()); + devicesCaps[deviceId] << QVariant::fromValue(videoCaps); + } + + prevInterval = fpsValue; + } + } else { + auto fps = AkFrac(100e5, description->dwDefaultFrameInterval); + videoCaps.setProperty("fps", fps.toString()); + devicesCaps[deviceId] << QVariant::fromValue(videoCaps); + } + } + } + + QVariantList deviceControls; + + for (auto pu = uvc_get_processing_units(deviceHnd); pu; pu = pu->next) { + for (auto &control: UvcControl::allSelectors(PROCESSING_UNIT)) + if (pu->bmControls & control) { + auto controls = + this->controlsList(deviceHnd, + pu->bUnitID, + control, + PROCESSING_UNIT); + + if (!controls.isEmpty()) + deviceControls << QVariant(controls); + } + } + + imageControls[deviceId] = deviceControls; + deviceControls.clear(); + + for (auto ca = uvc_get_input_terminals(deviceHnd); ca; ca = ca->next) { + for (auto &control: UvcControl::allSelectors(CAMERA_TERMINAL)) + if (ca->bmControls & control) { + auto controls = + this->controlsList(deviceHnd, + ca->bTerminalID, + control, + CAMERA_TERMINAL); + + if (!controls.isEmpty()) + deviceControls << QVariant(controls); + } + } + + cameraControls[deviceId] = deviceControls; + + if (!this->m_deviceHnd || this->m_curDevice != deviceId) + uvc_close(deviceHnd); + + uvc_free_device_descriptor(descriptor); + } + +updateDevices_failed: + if (devices) + uvc_free_device_list(devices, 1); + + if (devicesCaps.isEmpty()) { + devicesList.clear(); + descriptions.clear(); + imageControls.clear(); + cameraControls.clear(); + } + + this->m_descriptions = descriptions; + this->m_devicesCaps = devicesCaps; + this->m_imageControls = imageControls; + this->m_cameraControls = cameraControls; + + if (this->m_devices != devicesList) { + this->m_devices = devicesList; + emit self->webcamsChanged(this->m_devices.values()); + } +} + +const PixFmtToStrMap &CaptureLibUVCPrivate::pixFmtToStr() +{ + static const PixFmtToStrMap &pixFmtToStr { + {UVC_FRAME_FORMAT_YUYV , "YUY2" }, + {UVC_FRAME_FORMAT_UYVY , "UYVY" }, + {UVC_FRAME_FORMAT_RGB , "RGB" }, + {UVC_FRAME_FORMAT_BGR , "BGR" }, + {UVC_FRAME_FORMAT_MJPEG , "MJPG" }, + {UVC_FRAME_FORMAT_GRAY8 , "GRAY8" }, + {UVC_FRAME_FORMAT_GRAY16, "GRAY16"}, + {UVC_FRAME_FORMAT_BY8 , "BY8" }, + {UVC_FRAME_FORMAT_BA81 , "SBGGR8"}, + {UVC_FRAME_FORMAT_SGRBG8, "SGRBG8"}, + {UVC_FRAME_FORMAT_SGBRG8, "SGBRG8"}, + {UVC_FRAME_FORMAT_SRGGB8, "SRGGB8"}, + {UVC_FRAME_FORMAT_SBGGR8, "SBGGR8"}, + }; + + return pixFmtToStr; +} + +const FourccToStrMap &CaptureLibUVCPrivate::v4l2FourccToStr() +{ + static const FourccToStrMap fourccToStr { + {"RGB3", "RGB24" }, + {"BGR3", "BGR24" }, + {"Y800", "GRAY8" }, + {"Y16 ", "GRAY16"}, + {"BA81", "SBGGR8"}, + {"GRBG", "SGRBG8"}, + {"GBRG", "SGBRG8"}, + {"RGGB", "SRGGB8"}, + {"BGGR", "SBGGR8"}, + }; + + return fourccToStr; +} + bool CaptureLibUVC::init() { if (this->d->m_devices.isEmpty() || this->d->m_device.isEmpty()) @@ -730,7 +879,7 @@ uvc_stream_ctrl_t streamCtrl; error = uvc_get_stream_ctrl_format_size(this->d->m_deviceHnd, &streamCtrl, - fourccToUvc->value(caps.property("fourcc").toString()), + CaptureLibUVCPrivate::pixFmtToStr().key(caps.property("fourcc").toString()), caps.property("width").toInt(), caps.property("height").toInt(), fps); @@ -744,7 +893,7 @@ error = uvc_start_streaming(this->d->m_deviceHnd, &streamCtrl, this->d->frameCallback, - this, + this->d, 0); if (error != UVC_SUCCESS) { @@ -802,7 +951,7 @@ if (stream < 0) return; - QVariantList supportedCaps = this->caps(this->d->m_device); + auto supportedCaps = this->caps(this->d->m_device); if (stream >= supportedCaps.length()) return; @@ -833,7 +982,7 @@ void CaptureLibUVC::resetStreams() { - QVariantList supportedCaps = this->caps(this->d->m_device); + auto supportedCaps = this->caps(this->d->m_device); QList streams; if (!supportedCaps.isEmpty()) @@ -857,199 +1006,94 @@ this->resetCameraControls(); } -void CaptureLibUVC::updateDevices() +const QVector &UvcControl::controls() { - if (!this->d->m_uvcContext) - return; - - decltype(this->d->m_devices) devicesList; - decltype(this->d->m_descriptions) descriptions; - decltype(this->d->m_devicesCaps) devicesCaps; - decltype(this->d->m_imageControls) imageControls; - decltype(this->d->m_cameraControls) cameraControls; - - uvc_device_t **devices = nullptr; - auto error = uvc_get_device_list(this->d->m_uvcContext, &devices); - - if (error != UVC_SUCCESS) { - qDebug() << "CaptureLibUVC:" << uvc_strerror(error); - - goto updateDevices_failed; - } - - for (int i = 0; devices[i] != nullptr; i++) { - uvc_device_descriptor_t *descriptor = nullptr; - error = uvc_get_device_descriptor(devices[i], &descriptor); - - if (error != UVC_SUCCESS) { - qDebug() << "CaptureLibUVC:" << uvc_strerror(error); - - continue; - } - - auto deviceId = this->uvcId(descriptor->idVendor, - descriptor->idProduct); - uvc_device_handle_t *deviceHnd = nullptr; - - if (this->d->m_deviceHnd && this->d->m_curDevice == deviceId) - deviceHnd = this->d->m_deviceHnd; - else { - error = uvc_open(devices[i], &deviceHnd); - - if (error != UVC_SUCCESS) { - qDebug() << "CaptureLibUVC:" << uvc_strerror(error); - uvc_free_device_descriptor(descriptor); - - continue; - } - } - - auto formatDescription = uvc_get_format_descs(deviceHnd); - - if (!formatDescription) { - qDebug() << "CaptureLibUVC: Can't read format description"; - - if (!this->d->m_deviceHnd || this->d->m_curDevice != deviceId) - uvc_close(deviceHnd); - - uvc_free_device_descriptor(descriptor); - - continue; - } - - auto description = - usbIds->description(descriptor->idVendor, descriptor->idProduct); - - if (description.isEmpty()) { - if (QString(descriptor->manufacturer).isEmpty()) - description += QString("Vendor 0x%1") - .arg(descriptor->idVendor, 4, 16, QChar('0')); - else - description += QString(descriptor->manufacturer); - - description += ", "; - - if (QString(descriptor->product).isEmpty()) - description += QString("Product 0x%1") - .arg(descriptor->idProduct, 4, 16, QChar('0')); - else - description += QString(descriptor->product); - } - - devicesList[quint32((descriptor->idVendor << 16) - | descriptor->idProduct)] = deviceId; - descriptions[deviceId] = description; - devicesCaps[deviceId] = QVariantList(); - AkCaps videoCaps; - videoCaps.setMimeType("video/unknown"); - - for (; formatDescription; formatDescription = formatDescription->next) { - auto fourCC = this->d->fourccToStr(formatDescription->fourccFormat); - - if (!fourccToUvc->contains(fourCC)) - continue; - - videoCaps.setProperty("fourcc", fourCC); - - for (auto description = formatDescription->frame_descs; - description; - description = description->next) { - videoCaps.setProperty("width", description->wWidth); - videoCaps.setProperty("height", description->wHeight); - - if (description->intervals) { - int prevInterval = 0; - - for (auto interval = description->intervals; interval && *interval; interval++) { - auto fps = AkFrac(100e5, *interval); - auto fpsValue = qRound(fps.value()); - - if (prevInterval != fpsValue) { - videoCaps.setProperty("fps", fps.toString()); - devicesCaps[deviceId] << QVariant::fromValue(videoCaps); - } - - prevInterval = fpsValue; - } - } else if (description->dwFrameIntervalStep > 0 - && description->dwMinFrameInterval != description->dwMaxFrameInterval) { - int prevInterval = 0; - - for (auto interval = description->dwMinFrameInterval; - interval <= description->dwMaxFrameInterval; - interval += description->dwFrameIntervalStep) { - auto fps = AkFrac(100e5, interval); - auto fpsValue = qRound(fps.value()); - - if (prevInterval != fpsValue) { - videoCaps.setProperty("fps", fps.toString()); - devicesCaps[deviceId] << QVariant::fromValue(videoCaps); - } - - prevInterval = fpsValue; - } - } else { - auto fps = AkFrac(100e5, description->dwDefaultFrameInterval); - videoCaps.setProperty("fps", fps.toString()); - devicesCaps[deviceId] << QVariant::fromValue(videoCaps); - } - } - } - - QVariantList deviceControls; - - for (auto pu = uvc_get_processing_units(deviceHnd); pu; pu = pu->next) { - for (auto &control: UvcControl::allSelectors(PROCESSING_UNIT)) - if (pu->bmControls & control) { - auto controls = - this->d->controlsList(deviceHnd, - pu->bUnitID, - control, - PROCESSING_UNIT); - - if (!controls.isEmpty()) - deviceControls << QVariant(controls); - } - } - - imageControls[deviceId] = deviceControls; - deviceControls.clear(); + static const QVector controls { + // Processing Units + {PROCESSING_UNIT, UVC_PU_CONTROL_UNDEFINED , "" , "" , false, {}}, + {PROCESSING_UNIT, UVC_PU_BACKLIGHT_COMPENSATION_CONTROL , "Backlight Compensation" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_BRIGHTNESS_CONTROL , "Brightness" , "integer", true , {}}, + {PROCESSING_UNIT, UVC_PU_CONTRAST_CONTROL , "Contrast" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_GAIN_CONTROL , "Gain" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_POWER_LINE_FREQUENCY_CONTROL , "Power Line Frequency" , "menu" , false, {"Disabled", + "50 Hz", + "60 Hz", + "Auto"}}, + {PROCESSING_UNIT, UVC_PU_HUE_CONTROL , "Hue" , "integer", true , {}}, + {PROCESSING_UNIT, UVC_PU_SATURATION_CONTROL , "Saturation" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_SHARPNESS_CONTROL , "Sharpness" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_GAMMA_CONTROL , "Gamma" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL , "White Balance Temperature" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, "White Balance Temperature Auto", "boolean", false, {}}, + //{PROCESSING_UNIT, UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL , "White Balance Component" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL , "White Balance Component Auto" , "boolean", false, {}}, + {PROCESSING_UNIT, UVC_PU_DIGITAL_MULTIPLIER_CONTROL , "Digital Multiplier" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL , "Digital Multiplier Limit" , "integer", false, {}}, + {PROCESSING_UNIT, UVC_PU_HUE_AUTO_CONTROL , "Hue Auto" , "boolean", false, {}}, + {PROCESSING_UNIT, UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL , "Analog Video Standard" , "menu" , false, {"None", + "NTSC - 525/60", + "PAL - 625/50", + "SECAM - 625/50", + "NTSC - 625/50", + "PAL - 525/60"}}, + {PROCESSING_UNIT, UVC_PU_ANALOG_LOCK_STATUS_CONTROL , "Analog Lock Status" , "menu" , false, {"Locked", + "Unlocked"}}, + {PROCESSING_UNIT, UVC_PU_CONTRAST_AUTO_CONTROL , "Contrast Auto" , "boolean", false, {}}, + + // Camera Terminals + {CAMERA_TERMINAL, UVC_CT_CONTROL_UNDEFINED , "" , "" , false, {}}, + {CAMERA_TERMINAL, UVC_CT_SCANNING_MODE_CONTROL , "Scanning Mode" , "boolean", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_AE_MODE_CONTROL , "AE Mode" , "", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_AE_PRIORITY_CONTROL , "AE Priority" , "", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL , "Exposure Time Absolute" , "", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL , "Exposure Time Relative" , "", false, {}}, + {CAMERA_TERMINAL, UVC_CT_FOCUS_ABSOLUTE_CONTROL , "Focus Absolute" , "integer", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_FOCUS_RELATIVE_CONTROL , "Focus Relative" , "", false, {}}, + {CAMERA_TERMINAL, UVC_CT_FOCUS_AUTO_CONTROL , "Focus Auto" , "boolean", false, {}}, + {CAMERA_TERMINAL, UVC_CT_IRIS_ABSOLUTE_CONTROL , "Iris Absolute" , "integer", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_IRIS_RELATIVE_CONTROL , "Iris Relative" , "", false, {}}, + {CAMERA_TERMINAL, UVC_CT_ZOOM_ABSOLUTE_CONTROL , "Zoom Absolute" , "integer", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_ZOOM_RELATIVE_CONTROL , "Zoom Relative" , "", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_PANTILT_ABSOLUTE_CONTROL , "Pantilt Absolute" , "", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_PANTILT_RELATIVE_CONTROL , "Pantilt Relative" , "", false, {}}, + {CAMERA_TERMINAL, UVC_CT_ROLL_ABSOLUTE_CONTROL , "Roll Absolute" , "integer", true, {}}, + //{CAMERA_TERMINAL, UVC_CT_ROLL_RELATIVE_CONTROL , "Roll Relative" , "", false, {}}, + {CAMERA_TERMINAL, UVC_CT_PRIVACY_CONTROL , "Privacy" , "boolean", false, {}}, + {CAMERA_TERMINAL, UVC_CT_FOCUS_SIMPLE_CONTROL , "Focus Simple" , "menu" , false, {"Full Range", + "Macro", + "People", + "Scene"}}, + //{CAMERA_TERMINAL, UVC_CT_DIGITAL_WINDOW_CONTROL , "Digital Window" , "", false, {}}, + //{CAMERA_TERMINAL, UVC_CT_REGION_OF_INTEREST_CONTROL , "Region of Interest" , "", false, {}} + }; - for (auto ca = uvc_get_input_terminals(deviceHnd); ca; ca = ca->next) { - for (auto &control: UvcControl::allSelectors(CAMERA_TERMINAL)) - if (ca->bmControls & control) { - auto controls = - this->d->controlsList(deviceHnd, - ca->bTerminalID, - control, - CAMERA_TERMINAL); + return controls; +} - if (!controls.isEmpty()) - deviceControls << QVariant(controls); - } - } +const UvcControl *UvcControl::bySelector(int controlType, uint8_t selector) +{ + for (auto &control: controls()) + if (control.controlType == controlType + && control.selector == selector) + return &control; - cameraControls[deviceId] = deviceControls; + // Returns default for control type. + for (auto &control: controls()) + if (control.controlType == controlType) + return &control; - if (!this->d->m_deviceHnd || this->d->m_curDevice != deviceId) - uvc_close(deviceHnd); + return &controls().first(); +} - uvc_free_device_descriptor(descriptor); - } +QVector UvcControl::allSelectors(int controlType) +{ + QVector selectors; -updateDevices_failed: - if (devices) - uvc_free_device_list(devices, 1); + for (int i = 1; i < controls().size(); i++) + if (controls()[i].controlType == controlType) + selectors << controls()[i].selector; - this->d->m_descriptions = descriptions; - this->d->m_devicesCaps = devicesCaps; - this->d->m_imageControls = imageControls; - this->d->m_cameraControls = cameraControls; - - if (this->d->m_devices != devicesList) { - this->d->m_devices = devicesList; - emit this->webcamsChanged(this->d->m_devices.values()); - } + return selectors; } #include "moc_capturelibuvc.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/capturelibuvc.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/capturelibuvc.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/capturelibuvc.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/capturelibuvc.h 2021-02-15 15:25:23.000000000 +0000 @@ -88,11 +88,6 @@ void resetIoMethod(); void resetNBuffers(); void reset(); - - private slots: - void updateDevices(); - - friend class CaptureLibUVCPrivate; }; #endif // CAPTURELIBUVC_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/usbids.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/usbids.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/usbids.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/libuvc/src/usbids.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -70,7 +70,7 @@ const UsbIdsElement *UsbIds::operator [](quint16 vendorId) const { - for (const auto &id: this->m_ids) + for (auto &id: this->m_ids) if (id.vendorId == vendorId) return &id; @@ -82,7 +82,7 @@ auto element = this->operator[](vendorId); if (!element) - return QString(); + return {}; if (element->products.contains(productId)) return element->products[productId]; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/mediafoundation/src/capturemmf.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/mediafoundation/src/capturemmf.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/mediafoundation/src/capturemmf.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/mediafoundation/src/capturemmf.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -48,11 +48,11 @@ return guid1.Data1 < guid2.Data1; } -typedef QMap VideoProcAmpPropertyMap; +using VideoProcAmpPropertyMap = QMap; inline VideoProcAmpPropertyMap initVideoProcAmpPropertyMap() { - VideoProcAmpPropertyMap vpapToStr = { + VideoProcAmpPropertyMap vpapToStr { {VideoProcAmp_Brightness , "Brightness" }, {VideoProcAmp_Contrast , "Contrast" }, {VideoProcAmp_Hue , "Hue" }, @@ -70,11 +70,11 @@ Q_GLOBAL_STATIC_WITH_ARGS(VideoProcAmpPropertyMap, vpapToStr, (initVideoProcAmpPropertyMap())) -typedef QMap CameraControlMap; +using CameraControlMap = QMap; inline CameraControlMap initCameraControlMap() { - CameraControlMap ccToStr = { + CameraControlMap ccToStr { {CameraControl_Pan , "Pan" }, {CameraControl_Tilt , "Tilt" }, {CameraControl_Roll , "Roll" }, @@ -89,11 +89,11 @@ Q_GLOBAL_STATIC_WITH_ARGS(CameraControlMap, ccToStr, (initCameraControlMap())) -typedef QMap GuidToStrMap; +using GuidToStrMap = QMap; inline GuidToStrMap initGuidToStrMap() { - GuidToStrMap guidToStr = { + GuidToStrMap guidToStr { {MEDIASUBTYPE_CLPL , "CLPL"}, {MEDIASUBTYPE_YUYV , "YUYV"}, {MEDIASUBTYPE_IYUV , "IYUV"}, @@ -164,11 +164,11 @@ Q_GLOBAL_STATIC_WITH_ARGS(GuidToStrMap, guidToStr, (initGuidToStrMap())) -typedef QMap IoMethodMap; +using IoMethodMap = QMap; inline IoMethodMap initIoMethodMap() { - IoMethodMap ioMethodToStr = { + IoMethodMap ioMethodToStr { {CaptureMMF::IoMethodSync , "sync" }, {CaptureMMF::IoMethodASync, "async"} }; @@ -178,18 +178,21 @@ Q_GLOBAL_STATIC_WITH_ARGS(IoMethodMap, ioMethodToStr, (initIoMethodMap())) -typedef QSharedPointer ActivatePtr; -typedef QSharedPointer MediaSourcePtr; -typedef QSharedPointer SourceReaderPtr; -typedef QSharedPointer MediaTypeHandlerPtr; -typedef QSharedPointer MediaTypePtr; +using ActivatePtr = QSharedPointer; +using MediaSourcePtr = QSharedPointer; +using SourceReaderPtr = QSharedPointer; +using MediaTypeHandlerPtr = QSharedPointer; +using MediaTypePtr = QSharedPointer; class CaptureMMFPrivate { public: - QStringList m_webcams; + CaptureMMF *self; QString m_device; QList m_streams; + QStringList m_devices; + QMap m_descriptions; + QMap m_devicesCaps; qint64 m_id {-1}; DWORD m_streamIndex {DWORD(MF_SOURCE_READER_FIRST_VIDEO_STREAM)}; CaptureMMF::IoMethod m_ioMethod {CaptureMMF::IoMethodSync}; @@ -201,10 +204,13 @@ QVariantMap m_localImageControls; QVariantMap m_localCameraControls; + explicit CaptureMMFPrivate(CaptureMMF *self); QVector sources() const; ActivatePtr source(const QString &sourceId) const; MediaSourcePtr mediaSource(const QString &sourceId) const; + MediaSourcePtr mediaSource(const ActivatePtr &activate) const; QVector streams(const QString &webcam) const; + QVector streams(const ActivatePtr &activate) const; QVector streams(IMFMediaSource *mediaSource) const; MediaTypeHandlerPtr stream(IMFMediaSource *mediaSource, DWORD streamIndex) const; @@ -228,14 +234,16 @@ QVariantMap controlStatus(const QVariantList &controls) const; QVariantMap mapDiff(const QVariantMap &map1, const QVariantMap &map2) const; + void updateDevices(); }; CaptureMMF::CaptureMMF(QObject *parent): Capture(parent), QAbstractNativeEventFilter() { - this->d = new CaptureMMFPrivate; + this->d = new CaptureMMFPrivate(this); qApp->installNativeEventFilter(this); + this->d->updateDevices(); } CaptureMMF::~CaptureMMF() @@ -246,23 +254,7 @@ QStringList CaptureMMF::webcams() const { - QStringList webcams; - auto sources = this->d->sources(); - - for (auto &source: sources) { - WCHAR *deviceId = nullptr; - - if (FAILED(source->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, - &deviceId, - nullptr))) { - continue; - } - - webcams << QString::fromWCharArray(deviceId); - CoTaskMemFree(deviceId); - } - - return webcams; + return this->d->m_devices; } QString CaptureMMF::device() const @@ -278,9 +270,9 @@ auto caps = this->caps(this->d->m_device); if (caps.isEmpty()) - return QList(); + return {}; - return QList() << 0; + return {0}; } QList CaptureMMF::listTracks(const QString &mimeType) @@ -310,37 +302,12 @@ QString CaptureMMF::description(const QString &webcam) const { - auto source = this->d->source(webcam); - - if (!source) - return QString(); - - QString description; - WCHAR *friendlyName = nullptr; - - if (SUCCEEDED(source->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, - &friendlyName, - nullptr))) { - description = QString::fromWCharArray(friendlyName); - CoTaskMemFree(friendlyName); - } - - return description; + return this->d->m_descriptions.value(webcam); } QVariantList CaptureMMF::caps(const QString &webcam) const { - QVariantList caps; - - for (auto &stream: this->d->streams(webcam)) - for (auto &mediaType: this->d->mediaTypes(stream.data())) { - auto videoCaps = this->d->capsFromMediaType(mediaType.data()); - - if (videoCaps) - caps << QVariant::fromValue(videoCaps); - } - - return caps; + return this->d->m_devicesCaps.value(webcam); } QString CaptureMMF::capsDescription(const AkCaps &caps) const @@ -540,7 +507,8 @@ sample->Release(); // Send packet. - AkPacket packet(caps, oBuffer); + AkPacket packet(caps); + packet.setBuffer(oBuffer); packet.setPts(sampleTime); packet.setTimeBase(AkFrac(1, TIME_BASE)); packet.setIndex(0); @@ -553,7 +521,7 @@ void *message, long *result) { - Q_UNUSED(eventType); + Q_UNUSED(eventType) if (!message) return false; @@ -565,13 +533,7 @@ case DBT_DEVICEARRIVAL: case DBT_DEVICEREMOVECOMPLETE: case DBT_DEVNODES_CHANGED: { - auto webcams = this->webcams(); - - if (webcams != this->d->m_webcams) { - emit this->webcamsChanged(webcams); - - this->d->m_webcams = webcams; - } + this->d->updateDevices(); if (result) *result = TRUE; @@ -691,8 +653,10 @@ auto mediaSource = this->d->mediaSource(device); if (mediaSource) { - this->d->m_globalImageControls = this->d->imageControls(mediaSource.data()); - this->d->m_globalCameraControls = this->d->cameraControls(mediaSource.data()); + this->d->m_globalImageControls = + this->d->imageControls(mediaSource.data()); + this->d->m_globalCameraControls = + this->d->cameraControls(mediaSource.data()); } this->d->m_controlsMutex.unlock(); @@ -745,7 +709,7 @@ void CaptureMMF::setNBuffers(int nBuffers) { - Q_UNUSED(nBuffers); + Q_UNUSED(nBuffers) } void CaptureMMF::resetDevice() @@ -780,7 +744,11 @@ this->resetCameraControls(); } +CaptureMMFPrivate::CaptureMMFPrivate(CaptureMMF *self): + self(self) +{ +} QVector CaptureMMFPrivate::sources() const { @@ -847,10 +815,15 @@ if (!source) return {}; + return this->mediaSource(source); +} + +MediaSourcePtr CaptureMMFPrivate::mediaSource(const ActivatePtr &activate) const +{ IMFMediaSource *mediaSource = nullptr; - if (FAILED(source->ActivateObject(IID_IMFMediaSource, - reinterpret_cast(&mediaSource)))) + if (FAILED(activate->ActivateObject(IID_IMFMediaSource, + reinterpret_cast(&mediaSource)))) return MediaSourcePtr(); return MediaSourcePtr(mediaSource, CaptureMMFPrivate::deleteMediaSource); @@ -863,6 +836,13 @@ return this->streams(mediaSource.data()); } +QVector CaptureMMFPrivate::streams(const ActivatePtr &activate) const +{ + auto mediaSource = this->mediaSource(activate); + + return this->streams(mediaSource.data()); +} + QVector CaptureMMFPrivate::streams(IMFMediaSource *mediaSource) const { QVector streams; @@ -1095,49 +1075,69 @@ if (!device) return QVariantList(); - qint32 min; - qint32 max; - qint32 step; - qint32 defaultValue; - qint32 flags; - qint32 value; + qint32 min = 0; + qint32 max = 0; + qint32 step = 0; + qint32 defaultValue = 0; + qint32 value = 0; + qint32 flags = 0; QVariantList controls; IAMVideoProcAmp *pProcAmp = nullptr; if (SUCCEEDED(device->QueryInterface(IID_IAMVideoProcAmp, reinterpret_cast(&pProcAmp)))) { - for (auto &property: vpapToStr->keys()) { - if (SUCCEEDED(pProcAmp->GetRange(property, + for (auto it = vpapToStr->begin(); it != vpapToStr->end(); it++) { + if (SUCCEEDED(pProcAmp->GetRange(it.key(), reinterpret_cast(&min), reinterpret_cast(&max), reinterpret_cast(&step), reinterpret_cast(&defaultValue), - reinterpret_cast(&flags)))) - if (SUCCEEDED(pProcAmp->Get(property, + reinterpret_cast(&flags)))) { + bool autoSupport = flags & VideoProcAmp_Flags_Auto; + bool manualSupport = flags & VideoProcAmp_Flags_Manual; + + if (SUCCEEDED(pProcAmp->Get(it.key(), reinterpret_cast(&value), reinterpret_cast(&flags)))) { - QVariantList control; - - QString type; + if (autoSupport) { + QVariantList control { + it.value() + " (Auto)", + QString("boolean"), + 0, + 1, + 1, + 1, + flags & VideoProcAmp_Flags_Auto, + QStringList() + }; + + controls << QVariant(control); + } + + if (manualSupport) { + QString type; + + if (min == 0 && max == 1) + type = "boolean"; + else + type = "integer"; + + QVariantList control { + it.value(), + type, + min, + max, + step, + defaultValue, + value, + QStringList() + }; - if (property == VideoProcAmp_ColorEnable - || property == VideoProcAmp_BacklightCompensation) - type = "boolean"; - else - type = "integer"; - - control << vpapToStr->value(property) - << type - << min - << max - << step - << defaultValue - << value - << QStringList(); - - controls << QVariant(control); + controls << QVariant(control); + } } + } } pProcAmp->Release(); @@ -1156,13 +1156,33 @@ if (SUCCEEDED(device->QueryInterface(IID_IAMVideoProcAmp, reinterpret_cast(&pProcAmp)))) { - for (auto &property: vpapToStr->keys()) { - QString propertyStr = vpapToStr->value(property); + for (auto it = vpapToStr->begin(); it != vpapToStr->end(); it++) { + auto key = it.value(); + + if (imageControls.contains(key)) { + LONG value = 0; + LONG flags = 0; + pProcAmp->Get(it.key(), + reinterpret_cast(&value), + reinterpret_cast(&flags)); + value = imageControls[key].toInt(); + pProcAmp->Set(it.key(), value, flags); + } + + if (imageControls.contains(key + " (Auto)")) { + LONG value = 0; + LONG flags = 0; + pProcAmp->Get(it.key(), + reinterpret_cast(&value), + reinterpret_cast(&flags)); + + if (imageControls[key + " (Auto)"].toBool()) + flags |= VideoProcAmp_Flags_Auto; + else + flags &= ~VideoProcAmp_Flags_Auto; - if (imageControls.contains(propertyStr)) - pProcAmp->Set(property, - imageControls[propertyStr].toInt(), - VideoProcAmp_Flags_Manual); + pProcAmp->Set(it.key(), value, flags); + } } pProcAmp->Release(); @@ -1176,41 +1196,69 @@ if (!device) return QVariantList(); - qint32 min; - qint32 max; - qint32 step; - qint32 defaultValue; - qint32 flags; - qint32 value; + qint32 min = 0; + qint32 max = 0; + qint32 step = 0; + qint32 defaultValue = 0; + qint32 value = 0; + qint32 flags = 0; QVariantList controls; IAMCameraControl *pCameraControl = nullptr; if (SUCCEEDED(device->QueryInterface(IID_IAMCameraControl, reinterpret_cast(&pCameraControl)))) { - for (auto &cameraControl: ccToStr->keys()) { - if (SUCCEEDED(pCameraControl->GetRange(cameraControl, + for (auto it = ccToStr->begin(); it != ccToStr->end(); it++) { + if (SUCCEEDED(pCameraControl->GetRange(it.key(), reinterpret_cast(&min), reinterpret_cast(&max), reinterpret_cast(&step), reinterpret_cast(&defaultValue), - reinterpret_cast(&flags)))) - if (SUCCEEDED(pCameraControl->Get(cameraControl, + reinterpret_cast(&flags)))) { + bool autoSupport = flags & CameraControl_Flags_Auto; + bool manualSupport = flags & CameraControl_Flags_Manual; + + if (SUCCEEDED(pCameraControl->Get(it.key(), reinterpret_cast(&value), reinterpret_cast(&flags)))) { - QVariantList control; - - control << ccToStr->value(cameraControl) - << QString("integer") - << min - << max - << step - << defaultValue - << value - << QStringList(); + if (autoSupport) { + QVariantList control { + it.value() + " (Auto)", + QString("boolean"), + 0, + 1, + 1, + 1, + flags & CameraControl_Flags_Auto, + QStringList() + }; + + controls << QVariant(control); + } + + if (manualSupport) { + QString type; + + if (min == 0 && max == 1) + type = "boolean"; + else + type = "integer"; + + QVariantList control { + it.value(), + type, + min, + max, + step, + defaultValue, + value, + QStringList() + }; - controls << QVariant(control); + controls << QVariant(control); + } } + } } pCameraControl->Release(); @@ -1229,13 +1277,33 @@ if (SUCCEEDED(device->QueryInterface(IID_IAMCameraControl, reinterpret_cast(&pCameraControl)))) { - for (auto &cameraControl: ccToStr->keys()) { - QString cameraControlStr = ccToStr->value(cameraControl); + for (auto it = ccToStr->begin(); it != ccToStr->end(); it++) { + auto key = it.value(); + + if (cameraControls.contains(key)) { + LONG value = 0; + LONG flags = 0; + pCameraControl->Get(it.key(), + reinterpret_cast(&value), + reinterpret_cast(&flags)); + value = cameraControls[key].toInt(); + pCameraControl->Set(it.key(), value, flags); + } + + if (cameraControls.contains(key + " (Auto)")) { + LONG value = 0; + LONG flags = 0; + pCameraControl->Get(it.key(), + reinterpret_cast(&value), + reinterpret_cast(&flags)); + + if (cameraControls[key + " (Auto)"].toBool()) + flags |= CameraControl_Flags_Auto; + else + flags &= ~CameraControl_Flags_Auto; - if (cameraControls.contains(cameraControlStr)) - pCameraControl->Set(cameraControl, - cameraControls[cameraControlStr].toInt(), - CameraControl_Flags_Manual); + pCameraControl->Set(it.key(), value, flags); + } } pCameraControl->Release(); @@ -1271,4 +1339,64 @@ return map; } +void CaptureMMFPrivate::updateDevices() +{ + decltype(this->m_devices) devices; + decltype(this->m_descriptions) descriptions; + decltype(this->m_devicesCaps) devicesCaps; + auto sources = this->sources(); + + for (auto &source: sources) { + WCHAR *sourceLink = nullptr; + + if (FAILED(source->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, + &sourceLink, + nullptr))) { + continue; + } + + auto deviceId = QString::fromWCharArray(sourceLink); + CoTaskMemFree(sourceLink); + + QString description; + WCHAR *friendlyName = nullptr; + + if (SUCCEEDED(source->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, + &friendlyName, + nullptr))) { + description = QString::fromWCharArray(friendlyName); + CoTaskMemFree(friendlyName); + } + + QVariantList caps; + + for (auto &stream: this->streams(source)) + for (auto &mediaType: this->mediaTypes(stream.data())) { + auto videoCaps = this->capsFromMediaType(mediaType.data()); + + if (videoCaps) + caps << QVariant::fromValue(videoCaps); + } + + if (!caps.isEmpty()) { + devices << deviceId; + descriptions[deviceId] = description; + devicesCaps[deviceId] = caps; + } + } + + if (devicesCaps.isEmpty()) { + devices.clear(); + descriptions.clear(); + } + + this->m_descriptions = descriptions; + this->m_devicesCaps = devicesCaps; + + if (this->m_devices != devices) { + this->m_devices = devices; + emit self->webcamsChanged(this->m_devices); + } +} + #include "moc_capturemmf.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/ndkcamera.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/ndkcamera.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/ndkcamera.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/ndkcamera.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,68 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +exists(akcommons.pri) { + include(akcommons.pri) +} else { + exists(../../../../akcommons.pri) { + include(../../../../akcommons.pri) + } else { + error("akcommons.pri file not found.") + } +} + +CONFIG += plugin + +HEADERS = \ + src/plugin.h \ + src/capturendkcamera.h \ + ../capture.h + +INCLUDEPATH += \ + ../../../../Lib/src \ + ../ + +LIBS += \ + -L$${OUT_PWD}/../../../../Lib/$${BIN_DIR} -l$${COMMONS_TARGET} \ + -landroid \ + -lcamera2ndk \ + -lmediandk + +OTHER_FILES += pspec.json + +QT += qml +android: QT += androidextras + +SOURCES = \ + src/plugin.cpp \ + src/capturendkcamera.cpp \ + ../capture.cpp + +akModule = VideoCapture +DESTDIR = $${OUT_PWD}/../../$${BIN_DIR}/submodules/$${akModule} + +TEMPLATE = lib + +INSTALLS += target + +android { + TARGET = $${COMMONS_TARGET}_submodules_$${akModule}_lib$${TARGET} + target.path = $${LIBDIR} +} else { + target.path = $${INSTALLPLUGINSDIR}/submodules/$${akModule} +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/pspec.json webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/pspec.json --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/pspec.json 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/pspec.json 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,4 @@ +{ + "pluginType": "Ak.SubModule", + "type": "capture" +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/capturendkcamera.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/capturendkcamera.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/capturendkcamera.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/capturendkcamera.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,994 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "capturendkcamera.h" + +using ImageFormatToStrMap = QMap; + +inline const ImageFormatToStrMap initImageFormatToStrMap() +{ + const ImageFormatToStrMap imgFmtToStrMap = { + {AIMAGE_FORMAT_RGBA_8888 , "RGBA" }, + {AIMAGE_FORMAT_RGBX_8888 , "RGBX" }, + {AIMAGE_FORMAT_RGB_888 , "RGB" }, + {AIMAGE_FORMAT_RGB_565 , "RGB565" }, + {AIMAGE_FORMAT_RGBA_FP16 , "RGBA_FP16" }, + {AIMAGE_FORMAT_YUV_420_888 , "YU12" }, + {AIMAGE_FORMAT_JPEG , "JPEG" }, + {AIMAGE_FORMAT_RAW16 , "SGRBG16" }, + {AIMAGE_FORMAT_RAW_PRIVATE , "RAW_PRIVATE" }, + {AIMAGE_FORMAT_RAW10 , "SGRBG10" }, + {AIMAGE_FORMAT_RAW12 , "SGRBG12" }, + {AIMAGE_FORMAT_DEPTH16 , "DEPTH16" }, + {AIMAGE_FORMAT_DEPTH_POINT_CLOUD, "DEPTH_POINT_CLOUD"}, + {AIMAGE_FORMAT_PRIVATE , "PRIVATE" }, + }; + + return imgFmtToStrMap; +} + +Q_GLOBAL_STATIC_WITH_ARGS(ImageFormatToStrMap, imgFmtToStrMap, (initImageFormatToStrMap())) + +using CameraManagerPtr = QSharedPointer; + +class CaptureNdkCameraPrivate +{ + public: + CaptureNdkCamera *self; + QString m_device; + QList m_streams; + QStringList m_devices; + QMap m_descriptions; + QMap m_devicesCaps; + QMutex m_controlsMutex; + QVariantList m_globalImageControls; + QVariantList m_globalCameraControls; + QVariantMap m_localImageControls; + QVariantMap m_localCameraControls; + QMutex m_mutex; + AkPacket m_curPacket; + QWaitCondition m_waitCondition; + AkFrac m_fps; + AkCaps m_caps; + qint64 m_id {-1}; + CameraManagerPtr m_manager; + ACameraDevice *m_camera {nullptr}; + AImageReader *m_imageReader {nullptr}; + ANativeWindow *m_imageReaderWindow {nullptr}; + ACaptureSessionOutputContainer *m_outputContainer {nullptr}; + ACaptureSessionOutput *m_sessionOutput {nullptr}; + ACameraOutputTarget *m_outputTarget {nullptr}; + ACaptureRequest *m_captureRequest {nullptr}; + ACameraCaptureSession *m_captureSession {nullptr}; + int m_nBuffers {4}; + + explicit CaptureNdkCameraPrivate(CaptureNdkCamera *self); + bool nearestFpsRangue(const QString &cameraId, + const AkFrac &fps, + int32_t &min, + int32_t &max) const; + static void onCamerasChanged(void *context, const char *cameraId); + static void deviceDisconnected(void *context, ACameraDevice *device); + static void deviceError(void *context, + ACameraDevice *device, + int error); + static void imageAvailable(void *context, AImageReader *reader); + static void sessionClosed(void *context, + ACameraCaptureSession *session); + static void sessionReady(void *context, + ACameraCaptureSession *session); + static void sessionActive(void *context, + ACameraCaptureSession *session); + static bool canUseCamera(); + static QByteArray readBuffer(AImage *image); + void updateDevices(); +}; + +CaptureNdkCamera::CaptureNdkCamera(QObject *parent): + Capture(parent) +{ + this->d = new CaptureNdkCameraPrivate(this); + ACameraManager_AvailabilityCallbacks availabilityCb = { + this->d, + CaptureNdkCameraPrivate::onCamerasChanged, + CaptureNdkCameraPrivate::onCamerasChanged, + }; + ACameraManager_registerAvailabilityCallback(this->d->m_manager.data(), + &availabilityCb); + this->d->updateDevices(); +} + +CaptureNdkCamera::~CaptureNdkCamera() +{ + this->uninit(); + + delete this->d; +} + +QStringList CaptureNdkCamera::webcams() const +{ + return this->d->m_devices; +} + +QString CaptureNdkCamera::device() const +{ + return this->d->m_device; +} + +QList CaptureNdkCamera::streams() +{ + if (!this->d->m_streams.isEmpty()) + return this->d->m_streams; + + QVariantList caps = this->caps(this->d->m_device); + + if (caps.isEmpty()) + return QList(); + + return QList {0}; +} + +QList CaptureNdkCamera::listTracks(const QString &mimeType) +{ + if (mimeType != "video/x-raw" + && !mimeType.isEmpty()) + return QList(); + + QVariantList caps = this->caps(this->d->m_device); + QList streams; + + for (int i = 0; i < caps.count(); i++) + streams << i; + + return streams; +} + +QString CaptureNdkCamera::ioMethod() const +{ + return {}; +} + +int CaptureNdkCamera::nBuffers() const +{ + return this->d->m_nBuffers; +} + +QString CaptureNdkCamera::description(const QString &webcam) const +{ + return this->d->m_descriptions.value(webcam); +} + +QVariantList CaptureNdkCamera::caps(const QString &webcam) const +{ + return this->d->m_devicesCaps.value(webcam); +} + +QString CaptureNdkCamera::capsDescription(const AkCaps &caps) const +{ + if (caps.mimeType() != "video/unknown") + return QString(); + + AkFrac fps = caps.property("fps").toString(); + + return QString("%1, %2x%3, %4 FPS") + .arg(caps.property("fourcc").toString(), + caps.property("width").toString(), + caps.property("height").toString()) + .arg(qRound(fps.value())); +} + +QVariantList CaptureNdkCamera::imageControls() const +{ + return this->d->m_globalImageControls; +} + +bool CaptureNdkCamera::setImageControls(const QVariantMap &imageControls) +{ + this->d->m_controlsMutex.lock(); + auto globalImageControls = this->d->m_globalImageControls; + this->d->m_controlsMutex.unlock(); + + for (int i = 0; i < globalImageControls.count(); i++) { + QVariantList control = globalImageControls[i].toList(); + QString controlName = control[0].toString(); + + if (imageControls.contains(controlName)) { + control[6] = imageControls[controlName]; + globalImageControls[i] = control; + } + } + + this->d->m_controlsMutex.lock(); + + if (this->d->m_globalImageControls == globalImageControls) { + this->d->m_controlsMutex.unlock(); + + return false; + } + + this->d->m_globalImageControls = globalImageControls; + this->d->m_controlsMutex.unlock(); + + emit this->imageControlsChanged(imageControls); + + return true; +} + +bool CaptureNdkCamera::resetImageControls() +{ + QVariantMap controls; + + for (auto &control: this->imageControls()) { + QVariantList params = control.toList(); + + controls[params[0].toString()] = params[5].toInt(); + } + + return this->setImageControls(controls); +} + +QVariantList CaptureNdkCamera::cameraControls() const +{ + return this->d->m_globalCameraControls; +} + +bool CaptureNdkCamera::setCameraControls(const QVariantMap &cameraControls) +{ + this->d->m_controlsMutex.lock(); + auto globalCameraControls = this->d->m_globalCameraControls; + this->d->m_controlsMutex.unlock(); + + for (int i = 0; i < globalCameraControls.count(); i++) { + QVariantList control = globalCameraControls[i].toList(); + QString controlName = control[0].toString(); + + if (cameraControls.contains(controlName)) { + control[6] = cameraControls[controlName]; + globalCameraControls[i] = control; + } + } + + this->d->m_controlsMutex.lock(); + + if (this->d->m_globalCameraControls == globalCameraControls) { + this->d->m_controlsMutex.unlock(); + + return false; + } + + this->d->m_globalCameraControls = globalCameraControls; + this->d->m_controlsMutex.unlock(); + emit this->cameraControlsChanged(cameraControls); + + return true; +} + +bool CaptureNdkCamera::resetCameraControls() +{ + QVariantMap controls; + + for (auto &control: this->cameraControls()) { + auto params = control.toList(); + controls[params[0].toString()] = params[5].toInt(); + } + + return this->setCameraControls(controls); +} + +AkPacket CaptureNdkCamera::readFrame() +{ + AkPacket packet; + + this->d->m_mutex.lock(); + + if (!this->d->m_curPacket) + this->d->m_waitCondition.wait(&this->d->m_mutex, 1000); + + if (this->d->m_curPacket) { + packet = this->d->m_curPacket; + this->d->m_curPacket = {}; + } + + this->d->m_mutex.unlock(); + + return packet; +} + +CaptureNdkCameraPrivate::CaptureNdkCameraPrivate(CaptureNdkCamera *self): + self(self) +{ + this->m_manager = CameraManagerPtr(ACameraManager_create(), + [] (ACameraManager *manager) { + ACameraManager_delete(manager); + }); +} + +bool CaptureNdkCameraPrivate::nearestFpsRangue(const QString &cameraId, + const AkFrac &fps, + int32_t &min, + int32_t &max) const +{ + ACameraMetadata *metaData {nullptr}; + + if (ACameraManager_getCameraCharacteristics(this->m_manager.data(), + cameraId.toStdString().c_str(), + &metaData) != ACAMERA_OK) { + return false; + } + + ACameraMetadata_const_entry frameRates; + + if (ACameraMetadata_getConstEntry(metaData, + ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, + &frameRates) != ACAMERA_OK) { + ACameraMetadata_free(metaData); + + return false; + } + + auto fpsValue = fps.value(); + bool ok = false; + min = 0; + max = 0; + + for (uint32_t i = 0; i < frameRates.count; i += 2) { + auto fpsMin = frameRates.data.i32[i + 0]; + auto fpsMax = frameRates.data.i32[i + 1]; + + if (fpsValue >= qreal(fpsMin) + && fpsValue <= qreal(fpsMax)) { + min = fpsMin; + max = fpsMax; + ok = true; + + break; + } + } + + ACameraMetadata_free(metaData); + + return ok; +} + +void CaptureNdkCameraPrivate::onCamerasChanged(void *context, + const char *cameraId) +{ + Q_UNUSED(cameraId) + auto self = reinterpret_cast(context); + self->updateDevices(); +} + +void CaptureNdkCameraPrivate::deviceDisconnected(void *context, + ACameraDevice *device) +{ + Q_UNUSED(context) + Q_UNUSED(device) +} + +void CaptureNdkCameraPrivate::deviceError(void *context, + ACameraDevice *device, + int error) +{ + Q_UNUSED(context) + Q_UNUSED(device) + Q_UNUSED(error) +} + +void CaptureNdkCameraPrivate::imageAvailable(void *context, + AImageReader *reader) +{ + auto self = reinterpret_cast(context); + AImage *image {nullptr}; + int32_t format = 0; + int32_t width = 0; + int32_t height = 0; + int64_t timestampNs = 0; + QByteArray oBuffer; + AkCaps caps; + AkPacket packet; + + if (AImageReader_acquireLatestImage(reader, &image) != AMEDIA_OK) + return; + + if (AImage_getFormat(image, &format) != AMEDIA_OK) + goto imageAvailable_error; + + if (AImage_getWidth(image, &width) != AMEDIA_OK) + goto imageAvailable_error; + + if (AImage_getHeight(image, &height) != AMEDIA_OK) + goto imageAvailable_error; + + if (AImage_getTimestamp(image, ×tampNs) != AMEDIA_OK) + goto imageAvailable_error; + + oBuffer = CaptureNdkCameraPrivate::readBuffer(image); + + if (oBuffer.isEmpty()) + goto imageAvailable_error; + + caps.setMimeType("video/unknown"); + caps.setProperty("fourcc", imgFmtToStrMap->value(AIMAGE_FORMATS(format))); + caps.setProperty("width", width); + caps.setProperty("height", height); + caps.setProperty("fps", self->m_fps.toString()); + + packet = AkPacket(caps); + packet.setBuffer(oBuffer); + packet.setPts(timestampNs); + packet.setTimeBase({1, qint64(1e9)}); + packet.setIndex(0); + packet.setId(self->m_id); + + self->m_mutex.lock(); + self->m_curPacket = packet; + self->m_waitCondition.wakeAll(); + self->m_mutex.unlock(); + +imageAvailable_error: + AImage_delete(image); +} + +void CaptureNdkCameraPrivate::sessionClosed(void *context, + ACameraCaptureSession *session) +{ + Q_UNUSED(context) + Q_UNUSED(session) +} + +void CaptureNdkCameraPrivate::sessionReady(void *context, + ACameraCaptureSession *session) +{ + Q_UNUSED(context) + Q_UNUSED(session) +} + +void CaptureNdkCameraPrivate::sessionActive(void *context, + ACameraCaptureSession *session) +{ + Q_UNUSED(context) + Q_UNUSED(session) +} + +bool CaptureNdkCameraPrivate::canUseCamera() +{ + static bool done = false; + static bool result = false; + + if (done) + return result; + + QStringList permissions { + "android.permission.CAMERA" + }; + QStringList neededPermissions; + + for (auto &permission: permissions) + if (QtAndroid::checkPermission(permission) == QtAndroid::PermissionResult::Denied) + neededPermissions << permission; + + if (!neededPermissions.isEmpty()) { + auto results = QtAndroid::requestPermissionsSync(neededPermissions); + + for (auto it = results.constBegin(); it != results.constEnd(); it++) + if (it.value() == QtAndroid::PermissionResult::Denied) { + done = true; + + return false; + } + } + + done = true; + result = true; + + return true; +} + +QByteArray CaptureNdkCameraPrivate::readBuffer(AImage *image) +{ + int32_t format = 0; + AImage_getFormat(image, &format); + int32_t width = 0; + AImage_getWidth(image, &width); + int32_t height = 0; + AImage_getHeight(image, &height); + int32_t numPlanes = 0; + AImage_getNumberOfPlanes(image, &numPlanes); + QByteArray oBuffer; + + if (format == AIMAGE_FORMAT_YUV_420_888) { + for (int32_t i = 0; i < numPlanes; i++) { + uint8_t *data = nullptr; + int dataLength = 0; + + if (AImage_getPlaneData(image, i, &data, &dataLength) != AMEDIA_OK) + continue; + + int32_t pixelStride = 0; + int32_t rowStride = 0; + AImage_getPlanePixelStride(image, i, &pixelStride); + AImage_getPlaneRowStride(image, i, &rowStride); + auto _width = width / (i > 0? 2: 1); + auto _height = height / (i > 0? 2: 1); + QByteArray buffer(_width * _height, Qt::Uninitialized); + + for (int y = 0; y < _height; y++) { + auto srcLine = data + y * rowStride; + auto dstLine = reinterpret_cast(buffer.data()) + + y * _width; + + for (int x = 0; x < _width; x++) + dstLine[x] = srcLine[pixelStride * x]; + } + + oBuffer += buffer; + } + } else { + for (int32_t i = 0; i < numPlanes; i++) { + uint8_t *data = nullptr; + int dataLength = 0; + + if (AImage_getPlaneData(image, i, &data, &dataLength) != AMEDIA_OK) + continue; + + oBuffer += QByteArray(reinterpret_cast(data), dataLength); + } + } + + return oBuffer; +} + +void CaptureNdkCameraPrivate::updateDevices() +{ + if (!this->canUseCamera()) + return; + + decltype(this->m_devices) devices; + decltype(this->m_descriptions) descriptions; + decltype(this->m_devicesCaps) devicesCaps; + + ACameraIdList *cameras = nullptr; + + if (ACameraManager_getCameraIdList(this->m_manager.data(), + &cameras) == ACAMERA_OK) { + QVector unsupportedFormats { + AIMAGE_FORMAT_RAW_PRIVATE, + AIMAGE_FORMAT_DEPTH16, + AIMAGE_FORMAT_DEPTH_POINT_CLOUD, + AIMAGE_FORMAT_PRIVATE, + }; + + QMap facingToStr { + {ACAMERA_LENS_FACING_FRONT , "Front"}, + {ACAMERA_LENS_FACING_BACK , "Back"}, + {ACAMERA_LENS_FACING_EXTERNAL, "External"}, + }; + + for (int i = 0; i < cameras->numCameras; i++) { + QString cameraId = cameras->cameraIds[i]; + ACameraMetadata *metaData = nullptr; + + if (ACameraManager_getCameraCharacteristics(this->m_manager.data(), + cameras->cameraIds[i], + &metaData) != ACAMERA_OK) { + continue; + } + + ACameraMetadata_const_entry frameRates; + + if (ACameraMetadata_getConstEntry(metaData, + ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, + &frameRates) != ACAMERA_OK) { + continue; + } + + QList supportedFrameRates; + + for (uint32_t i = 0; i < frameRates.count; i += 2) { + AkFrac fps(frameRates.data.i32[i + 0] + + frameRates.data.i32[i + 1], + 2); + + if (!supportedFrameRates.contains(fps)) + supportedFrameRates << fps; + } + + ACameraMetadata_const_entry formats; + + if (ACameraMetadata_getConstEntry(metaData, + ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &formats) != ACAMERA_OK) { + continue; + } + + QList supportedFormats; + + for (uint32_t i = 0; i < formats.count; i += 4) { + if (formats.data.i32[i + 3]) + continue; + + auto width = formats.data.i32[i + 1]; + auto height = formats.data.i32[i + 2]; + + if (width < 1 || height < 1) + continue; + + auto format = AIMAGE_FORMATS(formats.data.i32[i + 0]); + + if (unsupportedFormats.contains(format)) + continue; + + AkCaps videoCaps; + videoCaps.setMimeType("video/unknown"); + videoCaps.setProperty("fourcc", imgFmtToStrMap->value(format)); + videoCaps.setProperty("width", width); + videoCaps.setProperty("height", height); + + if (!supportedFormats.contains(videoCaps)) + supportedFormats << videoCaps; + } + + QVariantList caps; + + for (auto &format: supportedFormats) + for (auto &fps: supportedFrameRates) { + auto videoCaps = format; + videoCaps.setProperty("fps", fps.toString()); + caps << QVariant::fromValue(videoCaps); + } + + if (!caps.isEmpty()) { + auto deviceId = "NdkCamera:" + cameraId; + ACameraMetadata_const_entry lensFacing; + ACameraMetadata_getConstEntry(metaData, + ACAMERA_LENS_FACING, + &lensFacing); + auto facing = + acamera_metadata_enum_android_lens_facing_t(lensFacing.data.u8[0]); + auto description = QString("%1 Camera %2") + .arg(facingToStr[facing]) + .arg(cameraId); + devices << deviceId; + descriptions[deviceId] = description; + devicesCaps[deviceId] = caps; + } + + ACameraMetadata_free(metaData); + } + + ACameraManager_deleteCameraIdList(cameras); + } + + if (devicesCaps.isEmpty()) { + devices.clear(); + descriptions.clear(); + } + + this->m_descriptions = descriptions; + this->m_devicesCaps = devicesCaps; + + if (this->m_devices != devices) { + this->m_devices = devices; + emit self->webcamsChanged(this->m_devices); + } +} + +bool CaptureNdkCamera::init() +{ + this->d->m_localImageControls.clear(); + this->d->m_localCameraControls.clear(); + this->uninit(); + + QList streams; + QVariantList supportedCaps; + AIMAGE_FORMATS format; + AkCaps caps; + int32_t fpsRange[2]; + AkFrac fps; + + auto cameraId = this->d->m_device; + cameraId.remove(QRegExp("^NdkCamera:")); + ACameraDevice_StateCallbacks deviceStateCb { + this->d, + CaptureNdkCameraPrivate::deviceDisconnected, + CaptureNdkCameraPrivate::deviceError, + }; + AImageReader_ImageListener imageListenerCb { + this->d, + CaptureNdkCameraPrivate::imageAvailable + }; + ACameraCaptureSession_stateCallbacks sessionStateCb { + this->d, + CaptureNdkCameraPrivate::sessionClosed, + CaptureNdkCameraPrivate::sessionReady, + CaptureNdkCameraPrivate::sessionActive, + }; + + if (ACameraManager_openCamera(this->d->m_manager.data(), + cameraId.toStdString().c_str(), + &deviceStateCb, + &this->d->m_camera) != ACAMERA_OK) { + goto init_failed; + } + + if (ACameraDevice_createCaptureRequest(this->d->m_camera, + TEMPLATE_PREVIEW, + &this->d->m_captureRequest) != ACAMERA_OK) { + goto init_failed; + } + + streams = this->streams(); + + if (streams.isEmpty()) + goto init_failed; + + supportedCaps = this->caps(this->d->m_device); + caps = supportedCaps[streams[0]].value(); + caps.setProperty("align", 32); + fps = caps.property("fps").toString(); + + if (!this->d->nearestFpsRangue(cameraId, fps, fpsRange[0], fpsRange[1])) + goto init_failed; + + if (ACaptureRequest_setEntry_i32(this->d->m_captureRequest, + ACAMERA_CONTROL_AE_TARGET_FPS_RANGE, + 2, + fpsRange) != ACAMERA_OK) { + goto init_failed; + } + + format = imgFmtToStrMap->key(caps.property("fourcc").toString(), + AIMAGE_FORMAT_PRIVATE); + + if (AImageReader_new(caps.property("width").toInt(), + caps.property("height").toInt(), + format, + this->d->m_nBuffers, + &this->d->m_imageReader) != AMEDIA_OK) { + goto init_failed; + } + + if (AImageReader_setImageListener(this->d->m_imageReader, + &imageListenerCb) != AMEDIA_OK) { + goto init_failed; + } + + if (AImageReader_getWindow(this->d->m_imageReader, + &this->d->m_imageReaderWindow) != AMEDIA_OK) { + goto init_failed; + } + + ANativeWindow_acquire(this->d->m_imageReaderWindow); + + if (ACaptureSessionOutput_create(this->d->m_imageReaderWindow, + &this->d->m_sessionOutput) != ACAMERA_OK) { + goto init_failed; + } + + if (ACaptureSessionOutputContainer_create(&this->d->m_outputContainer) != ACAMERA_OK) { + goto init_failed; + } + + if (ACaptureSessionOutputContainer_add(this->d->m_outputContainer, + this->d->m_sessionOutput) != ACAMERA_OK) { + goto init_failed; + } + + if (ACameraOutputTarget_create(this->d->m_imageReaderWindow, + &this->d->m_outputTarget) != ACAMERA_OK) { + goto init_failed; + } + + if (ACaptureRequest_addTarget(this->d->m_captureRequest, + this->d->m_outputTarget) != ACAMERA_OK) { + goto init_failed; + } + + if (ACameraDevice_createCaptureSession(this->d->m_camera, + this->d->m_outputContainer, + &sessionStateCb, + &this->d->m_captureSession) != ACAMERA_OK) { + goto init_failed; + } + + if (ACameraCaptureSession_setRepeatingRequest(this->d->m_captureSession, + nullptr, + 1, + &this->d->m_captureRequest, + nullptr) != ACAMERA_OK) { + goto init_failed; + } + + this->d->m_id = Ak::id(); + this->d->m_caps = caps; + this->d->m_fps = fps; + + return true; + +init_failed: + this->uninit(); + + return false; +} + +void CaptureNdkCamera::uninit() +{ + if (this->d->m_captureSession) { + ACameraCaptureSession_stopRepeating(this->d->m_captureSession); + ACameraCaptureSession_close(this->d->m_captureSession); + this->d->m_captureSession = nullptr; + } + + if (this->d->m_outputTarget) { + if (this->d->m_captureRequest) + ACaptureRequest_removeTarget(this->d->m_captureRequest, this->d->m_outputTarget); + + ACameraOutputTarget_free(this->d->m_outputTarget); + this->d->m_outputTarget = nullptr; + } + + if (this->d->m_sessionOutput) { + if (this->d->m_outputContainer) + ACaptureSessionOutputContainer_remove(this->d->m_outputContainer, + this->d->m_sessionOutput); + + ACaptureSessionOutput_free(this->d->m_sessionOutput); + this->d->m_sessionOutput = nullptr; + } + + if (this->d->m_outputContainer) { + ACaptureSessionOutputContainer_free(this->d->m_outputContainer); + this->d->m_outputContainer = nullptr; + } + + if (this->d->m_imageReaderWindow) { + ANativeWindow_release(this->d->m_imageReaderWindow); + this->d->m_imageReaderWindow = nullptr; + } + + if (this->d->m_captureRequest) { + ACaptureRequest_free(this->d->m_captureRequest); + this->d->m_captureRequest = nullptr; + } + + if (this->d->m_camera) { + ACameraDevice_close(this->d->m_camera); + this->d->m_camera = nullptr; + } + + QThread::sleep(1); + + if (this->d->m_imageReader) { + AImageReader_delete(this->d->m_imageReader); + this->d->m_imageReader = nullptr; + } +} + +void CaptureNdkCamera::setDevice(const QString &device) +{ + if (this->d->m_device == device) + return; + + this->d->m_device = device; + + if (device.isEmpty()) { + this->d->m_controlsMutex.lock(); + this->d->m_globalImageControls.clear(); + this->d->m_globalCameraControls.clear(); + this->d->m_controlsMutex.unlock(); + } else { + this->d->m_controlsMutex.lock(); + + + this->d->m_controlsMutex.unlock(); + } + + this->d->m_controlsMutex.lock(); + this->d->m_controlsMutex.unlock(); + + emit this->deviceChanged(device); +} + +void CaptureNdkCamera::setStreams(const QList &streams) +{ + if (streams.isEmpty()) + return; + + int stream = streams[0]; + + if (stream < 0) + return; + + auto supportedCaps = this->caps(this->d->m_device); + + if (stream >= supportedCaps.length()) + return; + + QList inputStreams {stream}; + + if (this->streams() == inputStreams) + return; + + this->d->m_streams = inputStreams; + emit this->streamsChanged(inputStreams); +} + +void CaptureNdkCamera::setIoMethod(const QString &ioMethod) +{ + Q_UNUSED(ioMethod) +} + +void CaptureNdkCamera::setNBuffers(int nBuffers) +{ + if (this->d->m_nBuffers == nBuffers) + return; + + this->d->m_nBuffers = nBuffers; + emit this->nBuffersChanged(nBuffers); +} + +void CaptureNdkCamera::resetDevice() +{ + this->setDevice(""); +} + +void CaptureNdkCamera::resetStreams() +{ + QVariantList supportedCaps = this->caps(this->d->m_device); + QList streams; + + if (!supportedCaps.isEmpty()) + streams << 0; + + this->setStreams(streams); +} + +void CaptureNdkCamera::resetIoMethod() +{ + this->setIoMethod("any"); +} + +void CaptureNdkCamera::resetNBuffers() +{ + this->setNBuffers(4); +} + +void CaptureNdkCamera::reset() +{ + this->resetStreams(); + this->resetImageControls(); + this->resetCameraControls(); +} + +#include "moc_capturendkcamera.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/capturendkcamera.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/capturendkcamera.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/capturendkcamera.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/capturendkcamera.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,69 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef CAPTURENDKCAMERA_H +#define CAPTURENDKCAMERA_H + +#include "capture.h" + +class CaptureNdkCameraPrivate; + +class CaptureNdkCamera: public Capture +{ + Q_OBJECT + + public: + CaptureNdkCamera(QObject *parent=nullptr); + ~CaptureNdkCamera(); + + Q_INVOKABLE QStringList webcams() const; + Q_INVOKABLE QString device() const; + Q_INVOKABLE QList streams(); + Q_INVOKABLE QList listTracks(const QString &mimeType); + Q_INVOKABLE QString ioMethod() const; + Q_INVOKABLE int nBuffers() const; + Q_INVOKABLE QString description(const QString &webcam) const; + Q_INVOKABLE QVariantList caps(const QString &webcam) const; + Q_INVOKABLE QString capsDescription(const AkCaps &caps) const; + Q_INVOKABLE QVariantList imageControls() const; + Q_INVOKABLE bool setImageControls(const QVariantMap &imageControls); + Q_INVOKABLE bool resetImageControls(); + Q_INVOKABLE QVariantList cameraControls() const; + Q_INVOKABLE bool setCameraControls(const QVariantMap &cameraControls); + Q_INVOKABLE bool resetCameraControls(); + Q_INVOKABLE AkPacket readFrame(); + + private: + CaptureNdkCameraPrivate *d; + + public slots: + bool init(); + void uninit(); + void setDevice(const QString &device); + void setStreams(const QList &streams); + void setIoMethod(const QString &ioMethod); + void setNBuffers(int nBuffers); + void resetDevice(); + void resetStreams(); + void resetIoMethod(); + void resetNBuffers(); + void reset(); +}; + +#endif // CAPTURENDKCAMERA_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/plugin.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/plugin.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/plugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/plugin.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "plugin.h" +#include "capturendkcamera.h" + +QObject *Plugin::create(const QString &key, const QString &specification) +{ + Q_UNUSED(specification) + + if (key == AK_PLUGIN_TYPE_SUBMODULE) + return new CaptureNdkCamera(); + + return nullptr; +} + +QStringList Plugin::keys() const +{ + return QStringList(); +} + +#include "moc_plugin.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/plugin.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/plugin.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/ndkcamera/src/plugin.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2019 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +class Plugin: public QObject, public AkPlugin +{ + Q_OBJECT + Q_INTERFACES(AkPlugin) + Q_PLUGIN_METADATA(IID "org.avkys.plugin" FILE "pspec.json") + + public: + QObject *create(const QString &key, const QString &specification); + QStringList keys() const; +}; + +#endif // PLUGIN_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/src.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/src.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/src.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/src.pro 2021-02-15 15:25:23.000000000 +0000 @@ -36,9 +36,10 @@ HEADERS = \ videocapture.h \ videocaptureelement.h \ + videocaptureelementsettings.h \ + videocaptureglobals.h \ capture.h \ - convertvideo.h \ - videocaptureglobals.h + convertvideo.h INCLUDEPATH += \ ../../../Lib/src @@ -56,9 +57,10 @@ SOURCES = \ videocapture.cpp \ videocaptureelement.cpp \ + videocaptureelementsettings.cpp \ + videocaptureglobals.cpp \ capture.cpp \ - convertvideo.cpp \ - videocaptureglobals.cpp + convertvideo.cpp lupdate_only { SOURCES += $$files(../share/qml/*.qml) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/src/capturev4l2.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/src/capturev4l2.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/src/capturev4l2.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/src/capturev4l2.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -96,6 +96,80 @@ Q_GLOBAL_STATIC_WITH_ARGS(IoMethodMap, ioMethodToStr, (initIoMethodMap())) +using FourccToStrMap = QMap<__u32, QString>; + +inline FourccToStrMap initFourccToStr() +{ + FourccToStrMap fourccToStr = { + {V4L2_PIX_FMT_RGB332 , "RGB332" }, + {V4L2_PIX_FMT_RGB444 , "RGB444" }, + {V4L2_PIX_FMT_ARGB444 , "ARGB444" }, + {V4L2_PIX_FMT_XRGB444 , "XRGB444" }, + {V4L2_PIX_FMT_RGB555 , "RGB555" }, + {V4L2_PIX_FMT_ARGB555 , "ARGB555" }, + {V4L2_PIX_FMT_XRGB555 , "XRGB555" }, + {V4L2_PIX_FMT_RGB565 , "RGB565" }, + {V4L2_PIX_FMT_RGB555X , "RGB555BE" }, + {V4L2_PIX_FMT_ARGB555X , "ARGB555BE" }, + {V4L2_PIX_FMT_XRGB555X , "XRGB555BE" }, + {V4L2_PIX_FMT_RGB565X , "RGB565BE" }, + {V4L2_PIX_FMT_BGR666 , "BGR666" }, + {V4L2_PIX_FMT_BGR24 , "BGR" }, + {V4L2_PIX_FMT_RGB24 , "RGB" }, + {V4L2_PIX_FMT_BGR32 , "BGRX" }, + {V4L2_PIX_FMT_ABGR32 , "ABGR" }, + {V4L2_PIX_FMT_XBGR32 , "XBGR" }, + {V4L2_PIX_FMT_RGB32 , "RGBA" }, + {V4L2_PIX_FMT_ARGB32 , "ARGB" }, + {V4L2_PIX_FMT_XRGB32 , "XRGB" }, + {V4L2_PIX_FMT_GREY , "GRAY8" }, + {V4L2_PIX_FMT_Y4 , "GRAY4" }, + {V4L2_PIX_FMT_Y6 , "GRAY6" }, + {V4L2_PIX_FMT_Y10 , "GRAY10" }, + {V4L2_PIX_FMT_Y12 , "GRAY12" }, + {V4L2_PIX_FMT_Y16 , "GRAY16" }, + {V4L2_PIX_FMT_Y16_BE , "GRAY16BE" }, + {V4L2_PIX_FMT_SBGGR8 , "SBGGR8" }, + {V4L2_PIX_FMT_SGBRG8 , "SGBRG8" }, + {V4L2_PIX_FMT_SGRBG8 , "SGRBG8" }, + {V4L2_PIX_FMT_SRGGB8 , "SRGGB8" }, + {V4L2_PIX_FMT_SBGGR10 , "SBGGR10" }, + {V4L2_PIX_FMT_SGBRG10 , "SGBRG10" }, + {V4L2_PIX_FMT_SGRBG10 , "SGRBG10" }, + {V4L2_PIX_FMT_SRGGB10 , "SRGGB10" }, + {V4L2_PIX_FMT_SBGGR10P , "SBGGR10P" }, + {V4L2_PIX_FMT_SGBRG10P , "SGBRG10P" }, + {V4L2_PIX_FMT_SGRBG10P , "SGRBG10P" }, + {V4L2_PIX_FMT_SRGGB10P , "SRGGB10P" }, + {V4L2_PIX_FMT_SBGGR10ALAW8, "SBGGR10ALAW8"}, + {V4L2_PIX_FMT_SGBRG10ALAW8, "SGBRG10ALAW8"}, + {V4L2_PIX_FMT_SGRBG10ALAW8, "SGRBG10ALAW8"}, + {V4L2_PIX_FMT_SRGGB10ALAW8, "SRGGB10ALAW8"}, + {V4L2_PIX_FMT_SBGGR10DPCM8, "SBGGR10DPCM8"}, + {V4L2_PIX_FMT_SGBRG10DPCM8, "SGBRG10DPCM8"}, + {V4L2_PIX_FMT_SGRBG10DPCM8, "SGRBG10DPCM8"}, + {V4L2_PIX_FMT_SRGGB10DPCM8, "SRGGB10DPCM8"}, + {V4L2_PIX_FMT_SBGGR12 , "SBGGR12" }, + {V4L2_PIX_FMT_SGBRG12 , "SGBRG12" }, + {V4L2_PIX_FMT_SGRBG12 , "SGRBG12" }, + {V4L2_PIX_FMT_SRGGB12 , "SRGGB12" }, +#ifdef HAVE_EXTRAFORMATS + {V4L2_PIX_FMT_SBGGR12P , "SBGGR12P" }, + {V4L2_PIX_FMT_SGBRG12P , "SGBRG12P" }, + {V4L2_PIX_FMT_SGRBG12P , "SGRBG12P" }, + {V4L2_PIX_FMT_SRGGB12P , "SRGGB12P" }, + {V4L2_PIX_FMT_SBGGR16 , "SBGGR16" }, + {V4L2_PIX_FMT_SGBRG16 , "SGBRG16" }, + {V4L2_PIX_FMT_SGRBG16 , "SGRBG16" }, + {V4L2_PIX_FMT_SRGGB16 , "SRGGB16" }, +#endif + }; + + return fourccToStr; +} + +Q_GLOBAL_STATIC_WITH_ARGS(FourccToStrMap, v4l2FourccToStr, (initFourccToStr())) + class CaptureV4L2Private { public: @@ -121,12 +195,12 @@ int m_fd {-1}; explicit CaptureV4L2Private(CaptureV4L2 *self); + ~CaptureV4L2Private(); QVariantList capsFps(int fd, const v4l2_fmtdesc &format, __u32 width, __u32 height) const; QVariantList caps(int fd) const; - AkFrac fps(int fd) const; void setFps(int fd, const AkFrac &fps); QVariantList controls(int fd, quint32 controlClass) const; bool setControls(int fd, @@ -156,29 +230,18 @@ QVariantMap controlStatus(const QVariantList &controls) const; QVariantMap mapDiff(const QVariantMap &map1, const QVariantMap &map2) const; + inline QStringList v4l2Devices() const; + void updateDevices(); }; CaptureV4L2::CaptureV4L2(QObject *parent): Capture(parent) { this->d = new CaptureV4L2Private(this); - this->d->m_fsWatcher = new QFileSystemWatcher({"/dev"}, this); - - QObject::connect(this->d->m_fsWatcher, - &QFileSystemWatcher::directoryChanged, - this, - &CaptureV4L2::onDirectoryChanged); - QObject::connect(this->d->m_fsWatcher, - &QFileSystemWatcher::fileChanged, - this, - &CaptureV4L2::onFileChanged); - - this->updateDevices(); } CaptureV4L2::~CaptureV4L2() { - delete this->d->m_fsWatcher; delete this->d; } @@ -197,12 +260,12 @@ if (!this->d->m_streams.isEmpty()) return this->d->m_streams; - QVariantList caps = this->caps(this->d->m_device); + auto caps = this->caps(this->d->m_device); if (caps.isEmpty()) - return QList(); + return {}; - return QList {0}; + return {0}; } QList CaptureV4L2::listTracks(const QString &mimeType) @@ -266,8 +329,8 @@ this->d->m_controlsMutex.unlock(); for (int i = 0; i < globalImageControls.count(); i++) { - QVariantList control = globalImageControls[i].toList(); - QString controlName = control[0].toString(); + auto control = globalImageControls[i].toList(); + auto controlName = control[0].toString(); if (imageControls.contains(controlName)) { control[6] = imageControls[controlName]; @@ -297,7 +360,6 @@ for (auto &control: this->imageControls()) { QVariantList params = control.toList(); - controls[params[0].toString()] = params[5].toInt(); } @@ -431,9 +493,253 @@ return AkPacket(); } +bool CaptureV4L2::init() +{ + this->d->m_localImageControls.clear(); + this->d->m_localCameraControls.clear(); + + // Frames read must be blocking so we does not waste CPU time. + this->d->m_fd = + x_open(this->d->m_device.toStdString().c_str(), + O_RDWR, // | O_NONBLOCK, + 0); + + if (this->d->m_fd < 0) + return false; + + v4l2_capability capabilities; + memset(&capabilities, 0, sizeof(v4l2_capability)); + + if (x_ioctl(this->d->m_fd, VIDIOC_QUERYCAP, &capabilities) < 0) { + qDebug() << "VideoCapture: Can't query capabilities."; + x_close(this->d->m_fd); + this->d->m_fd = -1; + + return false; + } + + QList streams = this->streams(); + + if (streams.isEmpty()) { + qDebug() << "VideoCapture: No streams available."; + x_close(this->d->m_fd); + + return false; + } + + QVariantList supportedCaps = this->caps(this->d->m_device); + AkCaps caps = supportedCaps[streams[0]].value(); + v4l2_format fmt {}; + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + x_ioctl(this->d->m_fd, VIDIOC_G_FMT, &fmt); + auto fourcc = caps.property("fourcc").toString(); + fmt.fmt.pix.pixelformat = + v4l2FourccToStr->key(fourcc, + this->d->strToFourCC(fourcc)); + fmt.fmt.pix.width = caps.property("width").toUInt(); + fmt.fmt.pix.height = caps.property("height").toUInt(); + + if (x_ioctl(this->d->m_fd, VIDIOC_S_FMT, &fmt) < 0) { + qDebug() << "VideoCapture: Can't set format:" + << this->d->fourccToStr(fmt.fmt.pix.pixelformat); + x_close(this->d->m_fd); + this->d->m_fd = -1; + + return false; + } + + this->d->setFps(this->d->m_fd, caps.property("fps").toString()); + this->d->m_caps = caps; + this->d->m_fps = caps.property("fps").toString(); + this->d->m_timeBase = this->d->m_fps.invert(); + + if (this->d->m_ioMethod == IoMethodReadWrite + && capabilities.capabilities & V4L2_CAP_READWRITE + && this->d->initReadWrite(fmt.fmt.pix.sizeimage)) { + } else if (this->d->m_ioMethod == IoMethodMemoryMap + && capabilities.capabilities & V4L2_CAP_STREAMING + && this->d->initMemoryMap()) { + } else if (this->d->m_ioMethod == IoMethodUserPointer + && capabilities.capabilities & V4L2_CAP_STREAMING + && this->d->initUserPointer(fmt.fmt.pix.sizeimage)) { + } else + this->d->m_ioMethod = IoMethodUnknown; + + if (this->d->m_ioMethod != IoMethodUnknown) + return this->d->startCapture(); + + if (capabilities.capabilities & V4L2_CAP_STREAMING) { + if (this->d->initMemoryMap()) + this->d->m_ioMethod = IoMethodMemoryMap; + else if (this->d->initUserPointer(fmt.fmt.pix.sizeimage)) + this->d->m_ioMethod = IoMethodUserPointer; + } + + if (this->d->m_ioMethod == IoMethodUnknown) { + if (capabilities.capabilities & V4L2_CAP_READWRITE + && this->d->initReadWrite(fmt.fmt.pix.sizeimage)) + this->d->m_ioMethod = IoMethodReadWrite; + else + return false; + } + + return this->d->startCapture(); +} + +void CaptureV4L2::uninit() +{ + this->d->stopCapture(); + + if (!this->d->m_buffers.isEmpty()) { + if (this->d->m_ioMethod == IoMethodReadWrite) + delete [] this->d->m_buffers[0].start; + else if (this->d->m_ioMethod == IoMethodMemoryMap) + for (auto &buffer: this->d->m_buffers) + x_munmap(buffer.start, buffer.length); + else if (this->d->m_ioMethod == IoMethodUserPointer) + for (auto &buffer: this->d->m_buffers) + delete [] buffer.start; + } + + x_close(this->d->m_fd); + this->d->m_caps.clear(); + this->d->m_fps = AkFrac(); + this->d->m_timeBase = AkFrac(); + this->d->m_buffers.clear(); +} + +void CaptureV4L2::setDevice(const QString &device) +{ + if (this->d->m_device == device) + return; + + this->d->m_device = device; + + if (device.isEmpty()) { + this->d->m_controlsMutex.lock(); + this->d->m_globalImageControls.clear(); + this->d->m_globalCameraControls.clear(); + this->d->m_controlsMutex.unlock(); + } else { + this->d->m_controlsMutex.lock(); + int fd = x_open(device.toStdString().c_str(), O_RDWR | O_NONBLOCK, 0); + + if (fd >= 0) { + this->d->m_globalImageControls = this->d->imageControls(fd); + this->d->m_globalCameraControls = this->d->cameraControls(fd); + x_close(fd); + } + + this->d->m_controlsMutex.unlock(); + } + + this->d->m_controlsMutex.lock(); + auto imageStatus = this->d->controlStatus(this->d->m_globalImageControls); + auto cameraStatus = this->d->controlStatus(this->d->m_globalCameraControls); + this->d->m_controlsMutex.unlock(); + + emit this->deviceChanged(device); + emit this->imageControlsChanged(imageStatus); + emit this->cameraControlsChanged(cameraStatus); +} + +void CaptureV4L2::setStreams(const QList &streams) +{ + if (streams.isEmpty()) + return; + + int stream = streams[0]; + + if (stream < 0) + return; + + auto supportedCaps = this->caps(this->d->m_device); + + if (stream >= supportedCaps.length()) + return; + + QList inputStreams {stream}; + + if (this->streams() == inputStreams) + return; + + this->d->m_streams = inputStreams; + emit this->streamsChanged(inputStreams); +} + +void CaptureV4L2::setIoMethod(const QString &ioMethod) +{ + if (this->d->m_fd >= 0) + return; + + IoMethod ioMethodEnum = ioMethodToStr->key(ioMethod, IoMethodUnknown); + + if (this->d->m_ioMethod == ioMethodEnum) + return; + + this->d->m_ioMethod = ioMethodEnum; + emit this->ioMethodChanged(ioMethod); +} + +void CaptureV4L2::setNBuffers(int nBuffers) +{ + if (this->d->m_nBuffers == nBuffers) + return; + + this->d->m_nBuffers = nBuffers; + emit this->nBuffersChanged(nBuffers); +} + +void CaptureV4L2::resetDevice() +{ + this->setDevice(""); +} + +void CaptureV4L2::resetStreams() +{ + QVariantList supportedCaps = this->caps(this->d->m_device); + QList streams; + + if (!supportedCaps.isEmpty()) + streams << 0; + + this->setStreams(streams); +} + +void CaptureV4L2::resetIoMethod() +{ + this->setIoMethod("any"); +} + +void CaptureV4L2::resetNBuffers() +{ + this->setNBuffers(32); +} + +void CaptureV4L2::reset() +{ + this->resetStreams(); + this->resetImageControls(); + this->resetCameraControls(); +} + CaptureV4L2Private::CaptureV4L2Private(CaptureV4L2 *self): self(self) { + this->m_fsWatcher = new QFileSystemWatcher({"/dev"}, self); + QObject::connect(this->m_fsWatcher, + &QFileSystemWatcher::directoryChanged, + this->self, + [this] () { + this->updateDevices(); + }); + this->updateDevices(); +} + +CaptureV4L2Private::~CaptureV4L2Private() +{ + delete this->m_fsWatcher; } QVariantList CaptureV4L2Private::capsFps(int fd, @@ -442,6 +748,9 @@ __u32 height) const { QVariantList caps; + auto fourcc = + v4l2FourccToStr->value(format.pixelformat, + this->fourccToStr(format.pixelformat)); #ifdef VIDIOC_ENUM_FRAMEINTERVALS v4l2_frmivalenum frmival {}; @@ -456,11 +765,6 @@ || !frmival.discrete.denominator) continue; - AkCaps videoCaps; - videoCaps.setMimeType("video/unknown"); - videoCaps.setProperty("fourcc", this->fourccToStr(format.pixelformat)); - videoCaps.setProperty("width", width); - videoCaps.setProperty("height", height); AkFrac fps; if (frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE) @@ -470,25 +774,40 @@ fps = AkFrac(frmival.stepwise.min.denominator, frmival.stepwise.max.numerator); - videoCaps.setProperty("fps", fps.toString()); - caps << QVariant::fromValue(videoCaps); - } -#else - struct v4l2_streamparm params; - memset(¶ms, 0, sizeof(v4l2_streamparm)); - params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (x_ioctl(fd, VIDIOC_G_PARM, ¶ms) >= 0) { AkCaps videoCaps; - auto timeperframe = ¶ms.parm.capture.timeperframe; videoCaps.setMimeType("video/unknown"); - videoCaps.setProperty("fourcc", this->fourccToStr(format.pixelformat)); + videoCaps.setProperty("fourcc", fourcc); videoCaps.setProperty("width", width); videoCaps.setProperty("height", height); - videoCaps.setProperty("fps", AkFrac(timeperframe->denominator, - timeperframe->numerator).toString()); + videoCaps.setProperty("fps", fps.toString()); caps << QVariant::fromValue(videoCaps); } + + if (caps.isEmpty()) { +#endif + struct v4l2_streamparm params; + memset(¶ms, 0, sizeof(v4l2_streamparm)); + params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (x_ioctl(fd, VIDIOC_G_PARM, ¶ms) >= 0) { + AkFrac fps; + + if (params.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) + fps = AkFrac(params.parm.capture.timeperframe.denominator, + params.parm.capture.timeperframe.numerator); + else + fps = AkFrac(30, 1); + + AkCaps videoCaps; + videoCaps.setMimeType("video/unknown"); + videoCaps.setProperty("fourcc", fourcc); + videoCaps.setProperty("width", width); + videoCaps.setProperty("height", height); + videoCaps.setProperty("fps", fps.toString()); + caps << QVariant::fromValue(videoCaps); + } +#ifdef VIDIOC_ENUM_FRAMEINTERVALS + } #endif return caps; @@ -516,14 +835,16 @@ #endif // Enumerate all supported formats. - v4l2_fmtdesc fmtdesc {}; + v4l2_fmtdesc fmtdesc; + memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; for (fmtdesc.index = 0; x_ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) >= 0; fmtdesc.index++) { #ifdef VIDIOC_ENUM_FRAMESIZES - v4l2_frmsizeenum frmsize {}; + v4l2_frmsizeenum frmsize; + memset(&frmsize, 0, sizeof(v4l2_frmsizeenum)); frmsize.pixel_format = fmtdesc.pixelformat; // Enumerate frame sizes. @@ -556,21 +877,6 @@ return caps; } -AkFrac CaptureV4L2Private::fps(int fd) const -{ - AkFrac fps(30, 1); - v4l2_streamparm streamparm {}; - streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (x_ioctl(fd, VIDIOC_G_PARM, &streamparm) >= 0) { - if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) - fps = AkFrac(streamparm.parm.capture.timeperframe.denominator, - streamparm.parm.capture.timeperframe.numerator); - } - - return fps; -} - void CaptureV4L2Private::setFps(int fd, const AkFrac &fps) { v4l2_streamparm streamparm {}; @@ -591,7 +897,8 @@ if (fd < 0) return controls; - v4l2_queryctrl queryctrl {}; + v4l2_queryctrl queryctrl; + memset(&queryctrl, 0, sizeof(v4l2_queryctrl)); queryctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; while (x_ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl) == 0) { @@ -637,35 +944,18 @@ return false; auto ctrl2id = this->findControls(fd, controlClass); - QVector mpegCtrls; - QVector userCtrls; for (auto it = controls.cbegin(); it != controls.cend(); it++) { - v4l2_ext_control ctrl {}; + if (!ctrl2id.contains(it.key())) + continue; + + v4l2_control ctrl; + memset(&ctrl, 0, sizeof(v4l2_control)); ctrl.id = ctrl2id[it.key()]; ctrl.value = it.value().toInt(); - - if (V4L2_CTRL_ID2CLASS(ctrl.id) == V4L2_CTRL_CLASS_MPEG) - mpegCtrls << ctrl; - else - userCtrls << ctrl; - } - - for (auto &user_ctrl: userCtrls) { - v4l2_control ctrl {}; - ctrl.id = user_ctrl.id; - ctrl.value = user_ctrl.value; x_ioctl(fd, VIDIOC_S_CTRL, &ctrl); } - if (!mpegCtrls.isEmpty()) { - v4l2_ext_controls ctrls {}; - ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; - ctrls.count = __u32(mpegCtrls.size()); - ctrls.controls = &mpegCtrls[0]; - x_ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls); - } - return true; } @@ -679,10 +969,12 @@ if (V4L2_CTRL_ID2CLASS(queryctrl->id) != controlClass) return {}; - v4l2_ext_control ext_ctrl {}; + v4l2_ext_control ext_ctrl; + memset(&ext_ctrl, 0, sizeof(v4l2_ext_control)); ext_ctrl.id = queryctrl->id; - v4l2_ext_controls ctrls {}; + v4l2_ext_controls ctrls; + memset(&ctrls, 0, sizeof(v4l2_ext_controls)); ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(queryctrl->id); ctrls.count = 1; ctrls.controls = &ext_ctrl; @@ -692,7 +984,8 @@ if (x_ioctl(handle, VIDIOC_G_EXT_CTRLS, &ctrls)) return {}; } else { - v4l2_control ctrl {}; + v4l2_control ctrl; + memset(&ctrl, 0, sizeof(v4l2_control)); ctrl.id = queryctrl->id; if (x_ioctl(handle, VIDIOC_G_CTRL, &ctrl)) @@ -701,7 +994,8 @@ ext_ctrl.value = ctrl.value; } - v4l2_querymenu qmenu {}; + v4l2_querymenu qmenu; + memset(&qmenu, 0, sizeof(v4l2_querymenu)); qmenu.id = queryctrl->id; QStringList menu; @@ -732,7 +1026,8 @@ QMap CaptureV4L2Private::findControls(int handle, quint32 controlClass) const { - v4l2_queryctrl qctrl {}; + v4l2_queryctrl qctrl; + memset(&qctrl, 0, sizeof(v4l2_queryctrl)); qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; QMap controls; @@ -772,7 +1067,6 @@ bool CaptureV4L2Private::initReadWrite(quint32 bufferSize) { this->m_buffers.resize(1); - this->m_buffers[0].length = bufferSize; this->m_buffers[0].start = new char[bufferSize]; @@ -789,7 +1083,8 @@ bool CaptureV4L2Private::initMemoryMap() { - v4l2_requestbuffers requestBuffers {}; + v4l2_requestbuffers requestBuffers; + memset(&requestBuffers, 0, sizeof(v4l2_requestbuffers)); requestBuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; requestBuffers.memory = V4L2_MEMORY_MMAP; requestBuffers.count = __u32(this->m_nBuffers); @@ -804,7 +1099,8 @@ bool error = false; for (int i = 0; i < int(requestBuffers.count); i++) { - v4l2_buffer buffer {}; + v4l2_buffer buffer; + memset(&buffer, 0, sizeof(v4l2_buffer)); buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.memory = V4L2_MEMORY_MMAP; buffer.index = __u32(i); @@ -845,7 +1141,8 @@ bool CaptureV4L2Private::initUserPointer(quint32 bufferSize) { - v4l2_requestbuffers requestBuffers {}; + v4l2_requestbuffers requestBuffers; + memset(&requestBuffers, 0, sizeof(v4l2_requestbuffers)); requestBuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; requestBuffers.memory = V4L2_MEMORY_USERPTR; requestBuffers.count = __u32(this->m_nBuffers); @@ -887,7 +1184,8 @@ if (this->m_ioMethod == CaptureV4L2::IoMethodMemoryMap) { for (int i = 0; i < this->m_buffers.size(); i++) { - v4l2_buffer buffer {}; + v4l2_buffer buffer; + memset(&buffer, 0, sizeof(v4l2_buffer)); buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.memory = V4L2_MEMORY_MMAP; buffer.index = __u32(i); @@ -902,7 +1200,8 @@ error = true; } else if (this->m_ioMethod == CaptureV4L2::IoMethodUserPointer) { for (int i = 0; i < this->m_buffers.size(); i++) { - v4l2_buffer buffer {}; + v4l2_buffer buffer; + memset(&buffer, 0, sizeof(v4l2_buffer)); buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.memory = V4L2_MEMORY_USERPTR; buffer.index = __u32(i); @@ -957,7 +1256,8 @@ size_t bufferSize, qint64 pts) const { - AkPacket oPacket(this->m_caps, {buffer, int(bufferSize)}); + AkPacket oPacket(this->m_caps); + oPacket.setBuffer({buffer, int(bufferSize)}); oPacket.setPts(pts); oPacket.setTimeBase(this->m_timeBase); oPacket.setIndex(0); @@ -1006,8 +1306,8 @@ QVariantMap controlStatus; for (auto &control: controls) { - QVariantList params = control.toList(); - QString controlName = params[0].toString(); + auto params = control.toList(); + auto controlName = params[0].toString(); controlStatus[controlName] = params[6]; } @@ -1028,262 +1328,41 @@ return map; } -bool CaptureV4L2::init() -{ - this->d->m_localImageControls.clear(); - this->d->m_localCameraControls.clear(); - - // Frames read must be blocking so we does not waste CPU time. - this->d->m_fd = - x_open(this->d->m_device.toStdString().c_str(), - O_RDWR, // | O_NONBLOCK, - 0); - - if (this->d->m_fd < 0) - return false; - - v4l2_capability capabilities {}; - - if (x_ioctl(this->d->m_fd, VIDIOC_QUERYCAP, &capabilities) < 0) { - qDebug() << "VideoCapture: Can't query capabilities."; - x_close(this->d->m_fd); - - return false; - } - - QList streams = this->streams(); - - if (streams.isEmpty()) { - qDebug() << "VideoCapture: No streams available."; - x_close(this->d->m_fd); - - return false; - } - - QVariantList supportedCaps = this->caps(this->d->m_device); - AkCaps caps = supportedCaps[streams[0]].value(); - v4l2_format fmt {}; - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - x_ioctl(this->d->m_fd, VIDIOC_G_FMT, &fmt); - fmt.fmt.pix.pixelformat = - this->d->strToFourCC(caps.property("fourcc").toString()); - fmt.fmt.pix.width = caps.property("width").toUInt(); - fmt.fmt.pix.height = caps.property("height").toUInt(); - - if (x_ioctl(this->d->m_fd, VIDIOC_S_FMT, &fmt) < 0) { - qDebug() << "VideoCapture: Can't set format:" - << this->d->fourccToStr(fmt.fmt.pix.pixelformat); - x_close(this->d->m_fd); - - return false; - } - - this->d->setFps(this->d->m_fd, caps.property("fps").toString()); - this->d->m_caps = caps; - this->d->m_fps = caps.property("fps").toString(); - this->d->m_timeBase = this->d->m_fps.invert(); - - if (this->d->m_ioMethod == IoMethodReadWrite - && capabilities.capabilities & V4L2_CAP_READWRITE - && this->d->initReadWrite(fmt.fmt.pix.sizeimage)) { - } else if (this->d->m_ioMethod == IoMethodMemoryMap - && capabilities.capabilities & V4L2_CAP_STREAMING - && this->d->initMemoryMap()) { - } else if (this->d->m_ioMethod == IoMethodUserPointer - && capabilities.capabilities & V4L2_CAP_STREAMING - && this->d->initUserPointer(fmt.fmt.pix.sizeimage)) { - } else - this->d->m_ioMethod = IoMethodUnknown; - - if (this->d->m_ioMethod != IoMethodUnknown) - return this->d->startCapture(); - - if (capabilities.capabilities & V4L2_CAP_STREAMING) { - if (this->d->initMemoryMap()) - this->d->m_ioMethod = IoMethodMemoryMap; - else if (this->d->initUserPointer(fmt.fmt.pix.sizeimage)) - this->d->m_ioMethod = IoMethodUserPointer; - } - - if (this->d->m_ioMethod == IoMethodUnknown) { - if (capabilities.capabilities & V4L2_CAP_READWRITE - && this->d->initReadWrite(fmt.fmt.pix.sizeimage)) - this->d->m_ioMethod = IoMethodReadWrite; - else - return false; - } - - if (this->d->startCapture()) - return true; - - return false; -} - -void CaptureV4L2::uninit() -{ - this->d->stopCapture(); - - if (!this->d->m_buffers.isEmpty()) { - if (this->d->m_ioMethod == IoMethodReadWrite) - delete [] this->d->m_buffers[0].start; - else if (this->d->m_ioMethod == IoMethodMemoryMap) - for (auto &buffer: this->d->m_buffers) - x_munmap(buffer.start, buffer.length); - else if (this->d->m_ioMethod == IoMethodUserPointer) - for (auto &buffer: this->d->m_buffers) - delete [] buffer.start; - } - - x_close(this->d->m_fd); - this->d->m_caps.clear(); - this->d->m_fps = AkFrac(); - this->d->m_timeBase = AkFrac(); - this->d->m_buffers.clear(); -} - -void CaptureV4L2::setDevice(const QString &device) -{ - if (this->d->m_device == device) - return; - - this->d->m_device = device; - - if (device.isEmpty()) { - this->d->m_controlsMutex.lock(); - this->d->m_globalImageControls.clear(); - this->d->m_globalCameraControls.clear(); - this->d->m_controlsMutex.unlock(); - } else { - this->d->m_controlsMutex.lock(); - int fd = x_open(device.toStdString().c_str(), O_RDWR | O_NONBLOCK, 0); - - if (fd >= 0) { - this->d->m_globalImageControls = this->d->imageControls(fd); - this->d->m_globalCameraControls = this->d->cameraControls(fd); - x_close(fd); - } - - this->d->m_controlsMutex.unlock(); - } - - this->d->m_controlsMutex.lock(); - auto imageStatus = this->d->controlStatus(this->d->m_globalImageControls); - auto cameraStatus = this->d->controlStatus(this->d->m_globalCameraControls); - this->d->m_controlsMutex.unlock(); - - emit this->deviceChanged(device); - emit this->imageControlsChanged(imageStatus); - emit this->cameraControlsChanged(cameraStatus); -} - -void CaptureV4L2::setStreams(const QList &streams) -{ - if (streams.isEmpty()) - return; - - int stream = streams[0]; - - if (stream < 0) - return; - - auto supportedCaps = this->caps(this->d->m_device); - - if (stream >= supportedCaps.length()) - return; - - QList inputStreams {stream}; - - if (this->streams() == inputStreams) - return; - - this->d->m_streams = inputStreams; - emit this->streamsChanged(inputStreams); -} - -void CaptureV4L2::setIoMethod(const QString &ioMethod) -{ - if (this->d->m_fd >= 0) - return; - - IoMethod ioMethodEnum = ioMethodToStr->key(ioMethod, IoMethodUnknown); - - if (this->d->m_ioMethod == ioMethodEnum) - return; - - this->d->m_ioMethod = ioMethodEnum; - emit this->ioMethodChanged(ioMethod); -} - -void CaptureV4L2::setNBuffers(int nBuffers) -{ - if (this->d->m_nBuffers == nBuffers) - return; - - this->d->m_nBuffers = nBuffers; - emit this->nBuffersChanged(nBuffers); -} - -void CaptureV4L2::resetDevice() -{ - this->setDevice(""); -} - -void CaptureV4L2::resetStreams() -{ - QVariantList supportedCaps = this->caps(this->d->m_device); - QList streams; - - if (!supportedCaps.isEmpty()) - streams << 0; - - this->setStreams(streams); -} - -void CaptureV4L2::resetIoMethod() +QStringList CaptureV4L2Private::v4l2Devices() const { - this->setIoMethod("any"); -} + QDir devicesDir("/dev"); -void CaptureV4L2::resetNBuffers() -{ - this->setNBuffers(32); + return devicesDir.entryList(QStringList() << "video*", + QDir::System + | QDir::Readable + | QDir::Writable + | QDir::NoSymLinks + | QDir::NoDotAndDotDot + | QDir::CaseSensitive, + QDir::Name); } -void CaptureV4L2::reset() -{ - this->resetStreams(); - this->resetImageControls(); - this->resetCameraControls(); -} +void CaptureV4L2Private::updateDevices() +{ + decltype(this->m_devices) devices; + decltype(this->m_descriptions) descriptions; + decltype(this->m_devicesCaps) devicesCaps; -void CaptureV4L2::updateDevices() -{ - decltype(this->d->m_devices) devices; - decltype(this->d->m_descriptions) descriptions; - decltype(this->d->m_devicesCaps) devicesCaps; QDir devicesDir("/dev"); + auto devicesFiles = this->v4l2Devices(); - auto devicesFiles = devicesDir.entryList(QStringList() << "video*", - QDir::System - | QDir::Readable - | QDir::Writable - | QDir::NoSymLinks - | QDir::NoDotAndDotDot - | QDir::CaseSensitive, - QDir::Name); - - for (const QString &devicePath: devicesFiles) { + for (auto &devicePath: devicesFiles) { auto fileName = devicesDir.absoluteFilePath(devicePath); int fd = x_open(fileName.toStdString().c_str(), O_RDWR | O_NONBLOCK, 0); if (fd < 0) continue; - auto caps = this->d->caps(fd); + auto caps = this->caps(fd); if (!caps.empty()) { - v4l2_capability capability {}; + v4l2_capability capability; + memset(&capability, 0, sizeof(v4l2_capability)); QString description; if (x_ioctl(fd, VIDIOC_QUERYCAP, &capability) >= 0) @@ -1297,32 +1376,25 @@ x_close(fd); } - this->d->m_descriptions = descriptions; - this->d->m_devicesCaps = devicesCaps; + if (devicesCaps.isEmpty()) { + devices.clear(); + descriptions.clear(); + } + + this->m_descriptions = descriptions; + this->m_devicesCaps = devicesCaps; - if (this->d->m_devices != devices) { - if (!this->d->m_devices.isEmpty()) - this->d->m_fsWatcher->removePaths(this->d->m_devices); + if (this->m_devices != devices) { + if (!this->m_devices.isEmpty()) + this->m_fsWatcher->removePaths(this->m_devices); - this->d->m_devices = devices; + this->m_devices = devices; #ifndef Q_OS_BSD4 - if (!this->d->m_devices.isEmpty()) - this->d->m_fsWatcher->addPaths(this->d->m_devices); + if (!this->m_devices.isEmpty()) + this->m_fsWatcher->addPaths(this->m_devices); #endif - emit this->webcamsChanged(this->d->m_devices); + emit self->webcamsChanged(this->m_devices); } } -void CaptureV4L2::onDirectoryChanged(const QString &path) -{ - Q_UNUSED(path) - - this->updateDevices(); -} - -void CaptureV4L2::onFileChanged(const QString &fileName) -{ - Q_UNUSED(fileName) -} - #include "moc_capturev4l2.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/src/capturev4l2.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/src/capturev4l2.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/src/capturev4l2.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/src/capturev4l2.h 2021-02-15 15:25:23.000000000 +0000 @@ -72,11 +72,6 @@ void resetIoMethod(); void resetNBuffers(); void reset(); - - private slots: - void updateDevices(); - void onDirectoryChanged(const QString &path); - void onFileChanged(const QString &fileName); }; #endif // CAPTUREV4L2_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/v4l2sys.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/v4l2sys.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/v4l2sys.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/v4l2sys/v4l2sys.pro 2021-02-15 15:25:23.000000000 +0000 @@ -43,6 +43,7 @@ OTHER_FILES += pspec.json CONFIG(config_v4l2_extendedcontrols): DEFINES += HAVE_EXTENDEDCONTROLS +CONFIG(config_v4l2_extraformats): DEFINES += HAVE_EXTRAFORMATS QT += qml diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/v4lutils/v4lutils.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/v4lutils/v4lutils.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/v4lutils/v4lutils.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/v4lutils/v4lutils.pro 2021-02-15 15:25:23.000000000 +0000 @@ -47,6 +47,7 @@ PKGCONFIG += libv4l2 CONFIG(config_v4l2_extendedcontrols): DEFINES += HAVE_EXTENDEDCONTROLS +CONFIG(config_v4l2_extraformats): DEFINES += HAVE_EXTRAFORMATS QT += qml diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocapture.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocapture.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocapture.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocapture.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include "videocapture.h" #include "videocaptureelement.h" +#include "videocaptureelementsettings.h" QObject *VideoCapture::create(const QString &key, const QString &specification) { @@ -26,13 +27,16 @@ if (key == AK_PLUGIN_TYPE_ELEMENT) return new VideoCaptureElement(); + else if (key == AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + return new VideoCaptureElementSettings(); return nullptr; } QStringList VideoCapture::keys() const { - return QStringList(); + return {AK_PLUGIN_TYPE_ELEMENT, + AK_PLUGIN_TYPE_ELEMENT_SETTINGS}; } #include "moc_videocapture.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -25,11 +25,13 @@ #include #include #include +#include #include +#include #include #include "videocaptureelement.h" -#include "videocaptureglobals.h" +#include "videocaptureelementsettings.h" #include "convertvideo.h" #include "capture.h" @@ -40,12 +42,11 @@ inline const QStringList *mirrorFormats() { - static const QStringList mirrorFormats = { - "RGB3", - "RGB4", - "RGBP", - "RGBO", - "BGR0" + static const QStringList mirrorFormats { + "RGB", + "RGB565", + "RGB555", + "BGRX", }; return &mirrorFormats; @@ -55,9 +56,10 @@ #if !defined(Q_OS_OSX) inline const QStringList *swapRgbFormats() { - static const QStringList swapRgbFormats = { + static const QStringList swapRgbFormats { #ifdef Q_OS_WIN32 - "RGB3", + "RGB", + "BGRX", #endif "YV12" }; @@ -66,8 +68,6 @@ } #endif -Q_GLOBAL_STATIC(VideoCaptureGlobals, globalVideoCapture) - template inline QSharedPointer ptr_cast(QObject *obj=nullptr) { @@ -88,6 +88,8 @@ class VideoCaptureElementPrivate { public: + VideoCaptureElement *self; + VideoCaptureElementSettings settings; ConvertVideoPtr m_convertVideo; CapturePtr m_capture; QThreadPool m_threadPool; @@ -98,33 +100,30 @@ bool m_mirror {false}; bool m_swapRgb {false}; + explicit VideoCaptureElementPrivate(VideoCaptureElement *self); void cameraLoop(); + void codecLibUpdated(const QString &codecLib); + void captureLibUpdated(const QString &captureLib); + void frameReady(const AkPacket &packet) const; }; VideoCaptureElement::VideoCaptureElement(): AkMultimediaSourceElement() { - this->d = new VideoCaptureElementPrivate; - - QObject::connect(globalVideoCapture, - SIGNAL(codecLibChanged(const QString &)), - this, - SIGNAL(codecLibChanged(const QString &))); - QObject::connect(globalVideoCapture, - SIGNAL(codecLibChanged(const QString &)), - this, - SLOT(codecLibUpdated(const QString &))); - QObject::connect(globalVideoCapture, - SIGNAL(captureLibChanged(const QString &)), - this, - SIGNAL(captureLibChanged(const QString &))); - QObject::connect(globalVideoCapture, - SIGNAL(captureLibChanged(const QString &)), - this, - SLOT(captureLibUpdated(const QString &))); + this->d = new VideoCaptureElementPrivate(this); + QObject::connect(&this->d->settings, + &VideoCaptureElementSettings::codecLibChanged, + [this] (const QString &codecLib) { + this->d->codecLibUpdated(codecLib); + }); + QObject::connect(&this->d->settings, + &VideoCaptureElementSettings::captureLibChanged, + [this] (const QString &captureLib) { + this->d->captureLibUpdated(captureLib); + }); - this->codecLibUpdated(globalVideoCapture->codecLib()); - this->captureLibUpdated(globalVideoCapture->captureLib()); + this->d->codecLibUpdated(this->d->settings.codecLib()); + this->d->captureLibUpdated(this->d->settings.captureLib()); } VideoCaptureElement::~VideoCaptureElement() @@ -192,15 +191,10 @@ if (!caps) return AkCaps(); - AkVideoCaps videoCaps; - videoCaps.isValid() = true; - videoCaps.format() = AkVideoCaps::Format_rgb24; - videoCaps.bpp() = AkVideoCaps::bitsPerPixel(videoCaps.format()); - videoCaps.width() = caps.property("width").toInt(); - videoCaps.height() = caps.property("height").toInt(); - videoCaps.fps() = caps.property("fps").toString(); - - return videoCaps; + return AkVideoCaps(AkVideoCaps::Format_rgb24, + caps.property("width").toInt(), + caps.property("height").toInt(), + caps.property("fps").toString()); } AkCaps VideoCaptureElement::rawCaps(int stream) const @@ -243,16 +237,6 @@ return this->d->m_capture->nBuffers(); } -QString VideoCaptureElement::codecLib() const -{ - return globalVideoCapture->codecLib(); -} - -QString VideoCaptureElement::captureLib() const -{ - return globalVideoCapture->captureLib(); -} - QVariantList VideoCaptureElement::imageControls() const { if (!this->d->m_capture) @@ -301,6 +285,12 @@ return this->d->m_capture->resetCameraControls(); } +VideoCaptureElementPrivate::VideoCaptureElementPrivate(VideoCaptureElement *self): + self(self) +{ + +} + void VideoCaptureElementPrivate::cameraLoop() { if (!this->m_convertVideo || !this->m_capture) @@ -321,7 +311,7 @@ continue; } - AkPacket packet = this->m_capture->readFrame(); + auto packet = this->m_capture->readFrame(); if (!packet) continue; @@ -356,6 +346,95 @@ #endif } +void VideoCaptureElementPrivate::codecLibUpdated(const QString &codecLib) +{ + auto state = self->state(); + self->setState(AkElement::ElementStateNull); + + this->m_mutexLib.lock(); + + this->m_convertVideo = + ptr_cast(VideoCaptureElement::loadSubModule("VideoCapture", + codecLib)); + + if (this->m_convertVideo) + QObject::connect(this->m_convertVideo.data(), + &ConvertVideo::frameReady, + [this] (const AkPacket &packet) { + this->frameReady(packet); + }); + + this->m_mutexLib.unlock(); + + self->setState(state); +} + +void VideoCaptureElementPrivate::captureLibUpdated(const QString &captureLib) +{ + auto state = self->state(); + self->setState(AkElement::ElementStateNull); + + this->m_mutexLib.lock(); + + this->m_capture = + ptr_cast(VideoCaptureElement::loadSubModule("VideoCapture", + captureLib)); + + this->m_mutexLib.unlock(); + + if (!this->m_capture) + return; + + QObject::connect(this->m_capture.data(), + &Capture::error, + self, + &VideoCaptureElement::error); + QObject::connect(this->m_capture.data(), + &Capture::webcamsChanged, + self, + &VideoCaptureElement::mediasChanged); + QObject::connect(this->m_capture.data(), + &Capture::deviceChanged, + self, + &VideoCaptureElement::mediaChanged); + QObject::connect(this->m_capture.data(), + &Capture::imageControlsChanged, + self, + &VideoCaptureElement::imageControlsChanged); + QObject::connect(this->m_capture.data(), + &Capture::cameraControlsChanged, + self, + &VideoCaptureElement::cameraControlsChanged); + + emit self->mediasChanged(self->medias()); + emit self->streamsChanged(self->streams()); + + auto medias = self->medias(); + + if (!medias.isEmpty()) + self->setMedia(medias.first()); + + self->setState(state); +} + +void VideoCaptureElementPrivate::frameReady(const AkPacket &packet) const +{ + if (this->m_mirror || this->m_swapRgb) { + AkVideoPacket videoPacket(packet); + QImage oImage = videoPacket.toImage(); + + if (this->m_mirror) + oImage = oImage.mirrored(); + + if (this->m_swapRgb) + oImage = oImage.rgbSwapped(); + + emit self->oStream(AkVideoPacket::fromImage(oImage, videoPacket)); + } else { + emit self->oStream(packet); + } +} + QString VideoCaptureElement::controlInterfaceProvide(const QString &controlId) const { Q_UNUSED(controlId) @@ -460,16 +539,6 @@ this->d->m_capture->setNBuffers(nBuffers); } -void VideoCaptureElement::setCodecLib(const QString &codecLib) -{ - globalVideoCapture->setCodecLib(codecLib); -} - -void VideoCaptureElement::setCaptureLib(const QString &captureLib) -{ - globalVideoCapture->setCaptureLib(captureLib); -} - void VideoCaptureElement::resetMedia() { if (this->d->m_capture) @@ -494,20 +563,46 @@ this->d->m_capture->resetNBuffers(); } -void VideoCaptureElement::resetCodecLib() -{ - globalVideoCapture->resetCodecLib(); -} - -void VideoCaptureElement::resetCaptureLib() -{ - globalVideoCapture->resetCaptureLib(); -} - void VideoCaptureElement::reset() { + bool running = this->d->m_runCameraLoop; + this->setState(AkElement::ElementStateNull); + if (this->d->m_capture) this->d->m_capture->reset(); + + if (running) + this->setState(AkElement::ElementStatePlaying); + + QSettings settings; + + settings.beginGroup("VideoCapture"); + auto ndevices = settings.beginReadArray("devices"); + auto media = this->d->m_capture->device(); + auto deviceDescription = this->d->m_capture->description(media); + decltype(ndevices) i = 0; + + for (; i < ndevices; i++) { + settings.setArrayIndex(i); + auto deviceId = settings.value("id").toString(); + auto description = settings.value("description").toString(); + + if (deviceId == media && description == deviceDescription) + break; + } + + auto streams = this->d->m_capture->streams(); + + settings.endArray(); + + settings.beginWriteArray("devices"); + settings.setArrayIndex(i); + settings.setValue("id", media); + settings.setValue("description", deviceDescription); + settings.setValue("stream", streams.isEmpty()? 0: streams.first()); + + settings.endArray(); + settings.endGroup(); } bool VideoCaptureElement::setState(AkElement::ElementState state) @@ -587,94 +682,4 @@ return false; } -void VideoCaptureElement::frameReady(const AkPacket &packet) -{ - if (this->d->m_mirror || this->d->m_swapRgb) { - AkVideoPacket videoPacket(packet); - QImage oImage = videoPacket.toImage(); - - if (this->d->m_mirror) - oImage = oImage.mirrored(); - - if (this->d->m_swapRgb) - oImage = oImage.rgbSwapped(); - - emit this->oStream(AkVideoPacket::fromImage(oImage, - videoPacket).toPacket()); - } else { - emit this->oStream(packet); - } -} - -void VideoCaptureElement::codecLibUpdated(const QString &codecLib) -{ - auto state = this->state(); - this->setState(AkElement::ElementStateNull); - - this->d->m_mutexLib.lock(); - - this->d->m_convertVideo = - ptr_cast(VideoCaptureElement::loadSubModule("VideoCapture", - codecLib)); - - if (this->d->m_convertVideo) - QObject::connect(this->d->m_convertVideo.data(), - &ConvertVideo::frameReady, - this, - &VideoCaptureElement::frameReady, - Qt::DirectConnection); - - this->d->m_mutexLib.unlock(); - - this->setState(state); -} - -void VideoCaptureElement::captureLibUpdated(const QString &captureLib) -{ - auto state = this->state(); - this->setState(AkElement::ElementStateNull); - - this->d->m_mutexLib.lock(); - - this->d->m_capture = - ptr_cast(VideoCaptureElement::loadSubModule("VideoCapture", - captureLib)); - - this->d->m_mutexLib.unlock(); - - if (!this->d->m_capture) - return; - - QObject::connect(this->d->m_capture.data(), - &Capture::error, - this, - &VideoCaptureElement::error); - QObject::connect(this->d->m_capture.data(), - &Capture::webcamsChanged, - this, - &VideoCaptureElement::mediasChanged); - QObject::connect(this->d->m_capture.data(), - &Capture::deviceChanged, - this, - &VideoCaptureElement::mediaChanged); - QObject::connect(this->d->m_capture.data(), - &Capture::imageControlsChanged, - this, - &VideoCaptureElement::imageControlsChanged); - QObject::connect(this->d->m_capture.data(), - &Capture::cameraControlsChanged, - this, - &VideoCaptureElement::cameraControlsChanged); - - emit this->mediasChanged(this->medias()); - emit this->streamsChanged(this->streams()); - - auto medias = this->medias(); - - if (!medias.isEmpty()) - this->setMedia(medias.first()); - - this->setState(state); -} - #include "moc_videocaptureelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -53,16 +53,6 @@ READ nBuffers WRITE setNBuffers RESET resetNBuffers) - Q_PROPERTY(QString codecLib - READ codecLib - WRITE setCodecLib - RESET resetCodecLib - NOTIFY codecLibChanged) - Q_PROPERTY(QString captureLib - READ captureLib - WRITE setCaptureLib - RESET resetCaptureLib - NOTIFY captureLibChanged) public: VideoCaptureElement(); @@ -71,7 +61,7 @@ Q_INVOKABLE QStringList medias(); Q_INVOKABLE QString media() const; Q_INVOKABLE QList streams(); - Q_INVOKABLE QList listTracks(const QString &mimeType=""); + Q_INVOKABLE QList listTracks(const QString &mimeType={}); Q_INVOKABLE int defaultStream(const QString &mimeType); Q_INVOKABLE QString description(const QString &media); Q_INVOKABLE AkCaps caps(int stream); @@ -79,8 +69,6 @@ Q_INVOKABLE QStringList listCapsDescription() const; Q_INVOKABLE QString ioMethod() const; Q_INVOKABLE int nBuffers() const; - Q_INVOKABLE QString codecLib() const; - Q_INVOKABLE QString captureLib() const; Q_INVOKABLE QVariantList imageControls() const; Q_INVOKABLE bool setImageControls(const QVariantMap &imageControls); Q_INVOKABLE bool resetImageControls(); @@ -102,8 +90,6 @@ void streamsChanged(const QList &streams); void loopChanged(bool loop); void error(const QString &message); - void codecLibChanged(const QString &codecLib); - void captureLibChanged(const QString &captureLib); void imageControlsChanged(const QVariantMap &imageControls) const; void cameraControlsChanged(const QVariantMap &cameraControls) const; @@ -112,21 +98,12 @@ void setStreams(const QList &streams); void setIoMethod(const QString &ioMethod); void setNBuffers(int nBuffers); - void setCodecLib(const QString &codecLib); - void setCaptureLib(const QString &captureLib); void resetMedia(); void resetStreams(); void resetIoMethod(); void resetNBuffers(); - void resetCodecLib(); - void resetCaptureLib(); void reset(); bool setState(AkElement::ElementState state); - void frameReady(const AkPacket &packet); - - private slots: - void codecLibUpdated(const QString &codecLib); - void captureLibUpdated(const QString &captureLib); }; #endif // VIDEOCAPTUREELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelementsettings.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelementsettings.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelementsettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelementsettings.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,78 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include "videocaptureelementsettings.h" +#include "videocaptureglobals.h" + +Q_GLOBAL_STATIC(VideoCaptureGlobals, globalVideoCapture) + +VideoCaptureElementSettings::VideoCaptureElementSettings(QObject *parent): + QObject(parent) +{ + QObject::connect(globalVideoCapture, + &VideoCaptureGlobals::codecLibChanged, + this, + &VideoCaptureElementSettings::codecLibChanged); + QObject::connect(globalVideoCapture, + &VideoCaptureGlobals::captureLibChanged, + this, + &VideoCaptureElementSettings::captureLibChanged); +} + +QString VideoCaptureElementSettings::codecLib() const +{ + return globalVideoCapture->codecLib(); +} + +QString VideoCaptureElementSettings::captureLib() const +{ + return globalVideoCapture->captureLib(); +} + +QStringList VideoCaptureElementSettings::codecSubModules() const +{ + return globalVideoCapture->codecSubModules(); +} + +QStringList VideoCaptureElementSettings::captureSubModules() const +{ + return globalVideoCapture->captureSubModules(); +} + +void VideoCaptureElementSettings::setCodecLib(const QString &codecLib) +{ + globalVideoCapture->setCodecLib(codecLib); +} + +void VideoCaptureElementSettings::setCaptureLib(const QString &captureLib) +{ + globalVideoCapture->setCaptureLib(captureLib); +} + +void VideoCaptureElementSettings::resetCodecLib() +{ + globalVideoCapture->resetCodecLib(); +} + +void VideoCaptureElementSettings::resetCaptureLib() +{ + globalVideoCapture->resetCaptureLib(); +} + +#include "moc_videocaptureelementsettings.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelementsettings.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelementsettings.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelementsettings.h 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureelementsettings.h 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,66 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef VIDEOCAPTUREELEMENTSETTINGS_H +#define VIDEOCAPTUREELEMENTSETTINGS_H + +#include + +class VideoCaptureElementSettings: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString codecLib + READ codecLib + WRITE setCodecLib + RESET resetCodecLib + NOTIFY codecLibChanged) + Q_PROPERTY(QString captureLib + READ captureLib + WRITE setCaptureLib + RESET resetCaptureLib + NOTIFY captureLibChanged) + Q_PROPERTY(QStringList codecSubModules + READ codecSubModules + NOTIFY codecSubModulesChanged) + Q_PROPERTY(QStringList captureSubModules + READ captureSubModules + NOTIFY captureSubModulesChanged) + + public: + VideoCaptureElementSettings(QObject *parent=nullptr); + + Q_INVOKABLE QString codecLib() const; + Q_INVOKABLE QString captureLib() const; + Q_INVOKABLE QStringList codecSubModules() const; + Q_INVOKABLE QStringList captureSubModules() const; + + signals: + void codecLibChanged(const QString &codecLib); + void captureLibChanged(const QString &captureLib); + void codecSubModulesChanged(const QStringList &codecSubModules); + void captureSubModulesChanged(const QStringList &captureSubModules); + + public slots: + void setCodecLib(const QString &codecLib); + void setCaptureLib(const QString &captureLib); + void resetCodecLib(); + void resetCaptureLib(); +}; + +#endif // VIDEOCAPTUREELEMENTSETTINGS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureglobals.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureglobals.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureglobals.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureglobals.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,58 +21,65 @@ #include "videocaptureglobals.h" -VideoCaptureGlobals::VideoCaptureGlobals(QObject *parent): - QObject(parent) +class VideoCaptureGlobalsPrivate { - this->m_preferredFramework = QStringList { - "ffmpeg", - "gstreamer", - }; + public: + QString m_codecLib; + QString m_captureLib; + QStringList m_preferredFramework; + QStringList m_preferredLibrary; - this->m_preferredLibrary = QStringList { -#ifdef Q_OS_WIN32 - "dshow", - "mediafoundation", - "libuvc", -#elif defined(Q_OS_OSX) - "avfoundation", - "libuvc", -#else - "v4lutils", - "v4l2sys", - "libuvc", -#endif - }; + VideoCaptureGlobalsPrivate(); +}; +VideoCaptureGlobals::VideoCaptureGlobals(QObject *parent): + QObject(parent) +{ + this->d = new VideoCaptureGlobalsPrivate; this->resetCodecLib(); this->resetCaptureLib(); } +VideoCaptureGlobals::~VideoCaptureGlobals() +{ + delete this->d; +} + QString VideoCaptureGlobals::codecLib() const { - return this->m_codecLib; + return this->d->m_codecLib; } QString VideoCaptureGlobals::captureLib() const { - return this->m_captureLib; + return this->d->m_captureLib; +} + +QStringList VideoCaptureGlobals::codecSubModules() const +{ + return AkElement::listSubModules("VideoCapture", "convert"); +} + +QStringList VideoCaptureGlobals::captureSubModules() const +{ + return AkElement::listSubModules("VideoCapture", "capture"); } void VideoCaptureGlobals::setCodecLib(const QString &codecLib) { - if (this->m_codecLib == codecLib) + if (this->d->m_codecLib == codecLib) return; - this->m_codecLib = codecLib; + this->d->m_codecLib = codecLib; emit this->codecLibChanged(codecLib); } void VideoCaptureGlobals::setCaptureLib(const QString &captureLib) { - if (this->m_captureLib == captureLib) + if (this->d->m_captureLib == captureLib) return; - this->m_captureLib = captureLib; + this->d->m_captureLib = captureLib; emit this->captureLibChanged(captureLib); } @@ -80,14 +87,14 @@ { auto subModules = AkElement::listSubModules("VideoCapture", "convert"); - for (auto &framework: this->m_preferredFramework) + for (auto &framework: this->d->m_preferredFramework) if (subModules.contains(framework)) { this->setCodecLib(framework); return; } - if (this->m_codecLib.isEmpty() && !subModules.isEmpty()) + if (this->d->m_codecLib.isEmpty() && !subModules.isEmpty()) this->setCodecLib(subModules.first()); else this->setCodecLib(""); @@ -97,15 +104,42 @@ { auto subModules = AkElement::listSubModules("VideoCapture", "capture"); - for (auto &framework: this->m_preferredLibrary) + for (auto &framework: this->d->m_preferredLibrary) if (subModules.contains(framework)) { this->setCaptureLib(framework); return; } - if (this->m_codecLib.isEmpty() && !subModules.isEmpty()) + if (this->d->m_codecLib.isEmpty() && !subModules.isEmpty()) this->setCaptureLib(subModules.first()); else this->setCaptureLib(""); } + +VideoCaptureGlobalsPrivate::VideoCaptureGlobalsPrivate() +{ + this->m_preferredFramework = QStringList { + "ffmpeg", + "gstreamer", + "generic", + }; + + this->m_preferredLibrary = QStringList { +#ifdef Q_OS_WIN32 + "dshow", + "mediafoundation", +#elif defined(Q_OS_OSX) + "avfoundation", +#elif defined(Q_OS_ANDROID) + "androicamera", + "ndkcamera", +#else + "v4lutils", + "v4l2sys", +#endif + "libuvc", + }; +} + +#include "moc_videocaptureglobals.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureglobals.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureglobals.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureglobals.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/src/videocaptureglobals.h 2021-02-15 15:25:23.000000000 +0000 @@ -22,7 +22,9 @@ #include -class VideoCaptureGlobals : public QObject +class VideoCaptureGlobalsPrivate; + +class VideoCaptureGlobals: public QObject { Q_OBJECT Q_PROPERTY(QString codecLib @@ -35,18 +37,22 @@ WRITE setCaptureLib RESET resetCaptureLib NOTIFY captureLibChanged) + Q_PROPERTY(QStringList codecSubModules + READ codecSubModules) + Q_PROPERTY(QStringList captureSubModules + READ captureSubModules) public: VideoCaptureGlobals(QObject *parent=nullptr); + ~VideoCaptureGlobals(); Q_INVOKABLE QString codecLib() const; Q_INVOKABLE QString captureLib() const; + Q_INVOKABLE QStringList codecSubModules() const; + Q_INVOKABLE QStringList captureSubModules() const; private: - QString m_codecLib; - QString m_captureLib; - QStringList m_preferredFramework; - QStringList m_preferredLibrary; + VideoCaptureGlobalsPrivate *d; signals: void codecLibChanged(const QString &codecLib); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/VideoCapture.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/VideoCapture.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VideoCapture/VideoCapture.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VideoCapture/VideoCapture.pro 2021-02-15 15:25:23.000000000 +0000 @@ -20,12 +20,14 @@ CONFIG(debug, debug|release): CONFIG += ordered -SUBDIRS = src +SUBDIRS = src src/generic +android: SUBDIRS += src/androidcamera CONFIG(config_avfoundation): SUBDIRS += src/avfoundation CONFIG(config_dshow): SUBDIRS += src/dshow CONFIG(config_ffmpeg): SUBDIRS += src/ffmpeg CONFIG(config_gstreamer): SUBDIRS += src/gstreamer CONFIG(config_libuvc): SUBDIRS += src/libuvc CONFIG(config_mediafoundation): SUBDIRS += src/mediafoundation +CONFIG(config_ndk_camera): SUBDIRS += src/ndkcamera CONFIG(config_v4l2): SUBDIRS += src/v4l2sys CONFIG(config_v4lutils): SUBDIRS += src/v4lutils diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Vignette/src/vignetteelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Vignette/src/vignetteelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Vignette/src/vignetteelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Vignette/src/vignetteelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "vignetteelement.h" @@ -109,6 +110,33 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket VignetteElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + QImage oFrame = src.convertToFormat(QImage::Format_ARGB32); + + if (src.size() != this->d->m_curSize) { + this->d->m_curSize = src.size(); + emit this->curSizeChanged(this->d->m_curSize); + } + + this->d->m_mutex.lock(); + QImage vignette = this->d->m_vignette; + this->d->m_mutex.unlock(); + + QPainter painter; + painter.begin(&oFrame); + painter.drawImage(0, 0, vignette); + painter.end(); + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void VignetteElement::setColor(QRgb color) { if (this->d->m_color == color) @@ -165,34 +193,6 @@ this->setSoftness(0.5); } -AkPacket VignetteElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - QImage oFrame = src.convertToFormat(QImage::Format_ARGB32); - - if (src.size() != this->d->m_curSize) { - this->d->m_curSize = src.size(); - emit this->curSizeChanged(this->d->m_curSize); - } - - this->d->m_mutex.lock(); - QImage vignette = this->d->m_vignette; - this->d->m_mutex.unlock(); - - QPainter painter; - painter.begin(&oFrame); - painter.drawImage(0, 0, vignette); - painter.end(); - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - void VignetteElement::updateVignette() { this->d->m_mutex.lock(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Vignette/src/vignetteelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Vignette/src/vignetteelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Vignette/src/vignetteelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Vignette/src/vignetteelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -65,6 +65,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void colorChanged(QRgb color); @@ -82,7 +83,6 @@ void resetAspect(); void resetScale(); void resetSoftness(); - AkPacket iStream(const AkPacket &packet); private slots: void updateVignette(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/share/qml/main.qml webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/share/qml/main.qml --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/share/qml/main.qml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/share/qml/main.qml 2021-02-15 15:25:23.000000000 +0000 @@ -219,8 +219,9 @@ } Label { id: message - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.fillWidth: true Layout.columnSpan: 2 + wrapMode: Text.WordWrap visible: false } Label { @@ -260,7 +261,7 @@ PropertyChanges { target: message visible: true - text: qsTr("Error creating camera") + text: qsTr("Error creating camera: ") + VirtualCamera.errorMessage color: "#ff0000" style: Text.Raised } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/Assistant/src/assistant.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/Assistant/src/assistant.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/Assistant/src/assistant.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/Assistant/src/assistant.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -55,8 +55,8 @@ bool swapRgb {false}; }; - typedef std::map AssistantPeers; - typedef std::map DeviceConfigs; + using AssistantPeers = std::map; + using DeviceConfigs = std::map; class AssistantPrivate { @@ -1187,9 +1187,25 @@ { UNUSED(client) AkAssistantPrivateLogMethod(); + auto reply = xpc_dictionary_create_reply(event); + bool ok = true; - for (auto &client: this->m_clients) - xpc_connection_send_message(client.second, event); + for (auto &client: this->m_clients) { + auto reply = xpc_connection_send_message_with_reply_sync(client.second, + event); + auto replyType = xpc_get_type(reply); + bool isOk = false; + + if (replyType == XPC_TYPE_DICTIONARY) + isOk = xpc_dictionary_get_bool(reply, "status"); + + ok &= isOk; + xpc_release(reply); + } + + xpc_dictionary_set_bool(reply, "status", ok); + xpc_connection_send_message(client, reply); + xpc_release(reply); } void AkVCam::AssistantPrivate::listeners(xpc_connection_t client, diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/Assistant/src/assistantglobals.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/Assistant/src/assistantglobals.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/Assistant/src/assistantglobals.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/Assistant/src/assistantglobals.h 2021-02-15 15:25:23.000000000 +0000 @@ -63,8 +63,7 @@ namespace AkVCam { - typedef std::function XpcMessage; + using XpcMessage = std::function; } #endif // ASSISTANTGLOBALS_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VCamIPC/src/ipcbridge.mm webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VCamIPC/src/ipcbridge.mm --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VCamIPC/src/ipcbridge.mm 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VCamIPC/src/ipcbridge.mm 2021-02-15 15:25:23.000000000 +0000 @@ -56,6 +56,7 @@ std::map m_messageHandlers; std::vector m_broadcasting; std::map m_options; + std::wstring m_error; bool m_asClient; bool m_uninstall; @@ -91,7 +92,7 @@ bool mkpath(const std::string &path) const; bool rm(const std::string &path) const; bool createDaemonPlist(const std::string &fileName) const; - bool loadDaemon() const; + bool loadDaemon(); void unloadDaemon() const; bool checkDaemon(); void uninstallPlugin(); @@ -104,11 +105,11 @@ std::vector m_bridges; }; - inline IpcBridgePrivate *ipcBridgePrivate() + inline IpcBridgePrivate &ipcBridgePrivate() { static IpcBridgePrivate ipcBridgePrivate; - return &ipcBridgePrivate; + return ipcBridgePrivate; } } @@ -116,16 +117,21 @@ { AkIpcBridgeLogMethod(); this->d = new IpcBridgePrivate(this); - ipcBridgePrivate()->add(this); + ipcBridgePrivate().add(this); } AkVCam::IpcBridge::~IpcBridge() { this->unregisterPeer(); - ipcBridgePrivate()->remove(this); + ipcBridgePrivate().remove(this); delete this->d; } +std::wstring AkVCam::IpcBridge::errorMessage() const +{ + return this->d->m_error; +} + void AkVCam::IpcBridge::setOption(const std::string &key, const std::string &value) { @@ -228,7 +234,7 @@ xpc_connection_set_event_handler(serverMessagePort, ^(xpc_object_t event) { if (event == XPC_ERROR_CONNECTION_INTERRUPTED) { - ipcBridgePrivate()->connectionInterrupted(); + ipcBridgePrivate().connectionInterrupted(); } }); xpc_connection_resume(serverMessagePort); @@ -263,7 +269,7 @@ auto client = reinterpret_cast(event); xpc_connection_set_event_handler(client, ^(xpc_object_t event) { - ipcBridgePrivate()->messageReceived(client, event); + ipcBridgePrivate().messageReceived(client, event); }); xpc_connection_resume(client); @@ -662,8 +668,11 @@ this->registerPeer(false); - if (!this->d->m_serverMessagePort || !this->d->m_messagePort) + if (!this->d->m_serverMessagePort || !this->d->m_messagePort) { + this->d->m_error = L"Can't register peer"; + return {}; + } auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0); xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_CREATE); @@ -691,6 +700,7 @@ auto replyType = xpc_get_type(reply); if (replyType != XPC_TYPE_DICTIONARY) { + this->d->m_error = L"Can't set virtual camera formats"; xpc_release(reply); return {}; @@ -881,8 +891,10 @@ xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_FRAME_READY); xpc_dictionary_set_string(dictionary, "device", deviceId.c_str()); xpc_dictionary_set_value(dictionary, "frame", surfaceObj); - xpc_connection_send_message(this->d->m_serverMessagePort, dictionary); + auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort, + dictionary); xpc_release(dictionary); + xpc_release(reply); xpc_release(surfaceObj); CFRelease(surface); @@ -1117,24 +1129,28 @@ auto frame = xpc_dictionary_get_value(event, "frame"); auto surface = IOSurfaceLookupFromXPCObject(frame); - if (!surface) - return; + if (surface) { + uint32_t surfaceSeed = 0; + IOSurfaceLock(surface, kIOSurfaceLockReadOnly, &surfaceSeed); + FourCC fourcc = IOSurfaceGetPixelFormat(surface); + int width = int(IOSurfaceGetWidth(surface)); + int height = int(IOSurfaceGetHeight(surface)); + size_t size = IOSurfaceGetAllocSize(surface); + auto data = reinterpret_cast(IOSurfaceGetBaseAddress(surface)); + VideoFormat videoFormat(fourcc, width, height); + VideoFrame videoFrame(videoFormat); + memcpy(videoFrame.data().data(), data, size); + IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, &surfaceSeed); + CFRelease(surface); - uint32_t surfaceSeed = 0; - IOSurfaceLock(surface, kIOSurfaceLockReadOnly, &surfaceSeed); - FourCC fourcc = IOSurfaceGetPixelFormat(surface); - int width = int(IOSurfaceGetWidth(surface)); - int height = int(IOSurfaceGetHeight(surface)); - size_t size = IOSurfaceGetAllocSize(surface); - auto data = reinterpret_cast(IOSurfaceGetBaseAddress(surface)); - VideoFormat videoFormat(fourcc, width, height); - VideoFrame videoFrame(videoFormat); - memcpy(videoFrame.data().data(), data, size); - IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, &surfaceSeed); - CFRelease(surface); + for (auto bridge: this->m_bridges) + AKVCAM_EMIT(bridge, FrameReady, deviceId, videoFrame) + } - for (auto bridge: this->m_bridges) - AKVCAM_EMIT(bridge, FrameReady, deviceId, videoFrame) + auto reply = xpc_dictionary_create_reply(event); + xpc_dictionary_set_bool(reply, "status", surface? true: false); + xpc_connection_send_message(client, reply); + xpc_release(reply); } void AkVCam::IpcBridgePrivate::setBroadcasting(xpc_connection_t client, @@ -1411,7 +1427,7 @@ return true; } -bool AkVCam::IpcBridgePrivate::loadDaemon() const +bool AkVCam::IpcBridgePrivate::loadDaemon() { AkIpcBridgePrivateLogMethod(); auto launchctl = popen("launchctl list " AKVCAM_ASSISTANT_NAME, "r"); @@ -1422,13 +1438,21 @@ auto daemonsPath = replace(CMIO_DAEMONS_PATH, "~", this->homePath()); auto dstDaemonsPath = daemonsPath + "/" AKVCAM_ASSISTANT_NAME ".plist"; - if (!this->fileExists(dstDaemonsPath)) + if (!this->fileExists(dstDaemonsPath)) { + this->m_error = L"Daemon plist does not exists"; + return false; + } launchctl = popen(("launchctl load -w '" + dstDaemonsPath + "'").c_str(), "r"); - return launchctl && !pclose(launchctl); + bool result = launchctl && !pclose(launchctl); + + if (!result) + this->m_error = L"Can't launch daemon"; + + return result; } void AkVCam::IpcBridgePrivate::unloadDaemon() const @@ -1452,8 +1476,11 @@ AkIpcBridgePrivateLogMethod(); auto driverPath = this->locateDriverPath(); - if (driverPath.empty()) + if (driverPath.empty()) { + this->m_error = L"Driver not found"; + return false; + } auto plugin = this->fileName(driverPath); std::wstring dstPath = CMIO_PLUGINS_DAL_PATH_L; @@ -1465,8 +1492,11 @@ std::wfstream cmds; cmds.open(cmdFileName, std::ios_base::out); - if (!cmds.is_open()) + if (!cmds.is_open()) { + this->m_error = L"Can't create script"; + return false; + } cmds << L"mkdir -p " << pluginInstallPath @@ -1494,11 +1524,17 @@ auto dstDaemonsPath = daemonsPath + "/" + AKVCAM_ASSISTANT_NAME + ".plist"; if (!this->fileExists(dstDaemonsPath)) { - if (!this->mkpath(daemonsPath)) + if (!this->mkpath(daemonsPath)) { + this->m_error = L"Can't create daemon path"; + return false; + } + + if (!this->createDaemonPlist(dstDaemonsPath)) { + this->m_error = L"Can't create daemon plist"; - if (!this->createDaemonPlist(dstDaemonsPath)) return false; + } } return this->loadDaemon(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/Info.plist webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/Info.plist --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/Info.plist 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/Info.plist 2021-02-15 15:25:23.000000000 +0000 @@ -17,11 +17,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 8.6.1 + 8.8.0 CFBundleSignature ???? CFBundleVersion - 8.6.1 + 8.8.0 CFBundleSupportedPlatforms MacOSX diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/src/stream.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/src/stream.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/src/stream.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/src/stream.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -18,6 +18,7 @@ */ #include +#include #include #include "stream.h" @@ -52,17 +53,14 @@ bool m_verticalMirror {false}; bool m_swapRgb {false}; - explicit StreamPrivate(Stream *self): - self(self) - { - } - + explicit StreamPrivate(Stream *self); bool startTimer(); void stopTimer(); static void streamLoop(CFRunLoopTimerRef timer, void *info); void sendFrame(const VideoFrame &frame); void updateTestFrame(); VideoFrame applyAdjusts(const VideoFrame &frame); + VideoFrame randomFrame(); }; } @@ -73,13 +71,10 @@ this->d = new StreamPrivate(this); this->m_className = "Stream"; this->m_classID = kCMIOStreamClassID; - - if (!this->d->m_testFrame.load(CMIO_PLUGINS_DAL_PATH - "/" - CMIO_PLUGIN_NAME - ".plugin/Contents/Resources/TestFrame.bmp")) { - this->d->m_testFrame.load(":/VirtualCamera/share/TestFrame/TestFrame.bmp"); - } + this->d->m_testFrame.load(CMIO_PLUGINS_DAL_PATH + "/" + CMIO_PLUGIN_NAME + ".plugin/Contents/Resources/TestFrame.bmp"); this->d->m_clock = std::make_shared("CMIO::VirtualCamera::Stream", @@ -404,6 +399,11 @@ return kCMIOHardwareUnspecifiedError; } +AkVCam::StreamPrivate::StreamPrivate(AkVCam::Stream *self): + self(self) +{ +} + bool AkVCam::StreamPrivate::startTimer() { AkLoggerLog("AkVCam::StreamPrivate::startTimer()"); @@ -462,7 +462,12 @@ return; self->m_mutex.lock(); - self->sendFrame(self->m_currentFrame); + + if (self->m_currentFrame.format().size() < 1) + self->sendFrame(self->randomFrame()); + else + self->sendFrame(self->m_currentFrame); + self->m_mutex.unlock(); } @@ -589,5 +594,25 @@ .mirror(this->m_horizontalMirror, this->m_verticalMirror) .swapRgb(this->m_swapRgb) - .convert(fourcc); + .convert(fourcc); +} + +AkVCam::VideoFrame AkVCam::StreamPrivate::randomFrame() +{ + VideoFormat format; + this->self->m_properties.getProperty(kCMIOStreamPropertyFormatDescription, + &format); + VideoData data(format.size()); + static std::uniform_int_distribution distribution(std::numeric_limits::min(), + std::numeric_limits::max()); + static std::default_random_engine engine; + std::generate(data.begin(), data.end(), [] () { + return distribution(engine); + }); + + VideoFrame frame; + frame.format() = format; + frame.data() = data; + + return frame; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/VirtualCamera.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/VirtualCamera.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/VirtualCamera.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/cmio/VirtualCamera/VirtualCamera.pro 2021-02-15 15:25:23.000000000 +0000 @@ -32,8 +32,7 @@ CONFIG -= qt CONFIG += \ unversioned_libname \ - unversioned_soname \ - resources + unversioned_soname DESTDIR = $${OUT_PWD}/$${BIN_DIR} @@ -78,12 +77,6 @@ src/objectproperties.cpp \ src/clock.cpp -RESOURCES += \ - ../../../TestFrame.qrc - -QMAKE_RESOURCE_FLAGS += \ - --no-compress - OTHER_FILES = \ Info.plist @@ -94,5 +87,7 @@ QMAKE_POST_LINK = \ $$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/MacOS)) $${CMD_SEP} \ + $$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/Resources)) $${CMD_SEP} \ $(COPY) $$shell_path($${PWD}/Info.plist) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents) $${CMD_SEP} \ - $(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/lib$${TARGET}.dylib) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/MacOS/$${TARGET}) + $(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/lib$${TARGET}.dylib) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/MacOS/$${TARGET}) $${CMD_SEP} \ + $(COPY) $$shell_path($${PWD}/../../../share/TestFrame/TestFrame.bmp) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/Resources) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/ipcbridge.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/ipcbridge.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/ipcbridge.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/ipcbridge.h 2021-02-15 15:25:23.000000000 +0000 @@ -80,6 +80,9 @@ /* Server & Client */ + // Get the last error message. + std::wstring errorMessage() const; + // Pass extra options to the bridge. void setOption(const std::string &key, const std::string &value); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/v4l2sys/VCamIPC/src/ipcbridge.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/v4l2sys/VCamIPC/src/ipcbridge.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/v4l2sys/VCamIPC/src/ipcbridge.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/v4l2sys/VCamIPC/src/ipcbridge.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -131,6 +131,7 @@ QFileSystemWatcher *m_fsWatcher; QVector m_buffers; VideoFormat m_curFormat; + std::wstring m_error; IoMethod m_ioMethod {IoMethodUnknown}; int m_fd {-1}; int m_nBuffers {32}; @@ -148,9 +149,9 @@ QStringList supportedDrivers(); inline int xioctl(int fd, ulong request, void *arg) const; bool sudo(const QString &command, - const QStringList &argumments) const; + const QStringList &argumments); bool sudo(const std::string &command, - const QStringList &argumments) const; + const QStringList &argumments); QString sysfsControls(const QString &deviceId) const; QString sysfsControls(const std::string &deviceId) const; bool isSplitDevice(const QString &deviceId) const; @@ -221,6 +222,11 @@ delete this->d; } +std::wstring AkVCam::IpcBridge::errorMessage() const +{ + return this->d->m_error; +} + void AkVCam::IpcBridge::setOption(const std::string &key, const std::string &value) { if (value.empty()) @@ -1410,7 +1416,7 @@ } bool AkVCam::IpcBridgePrivate::sudo(const QString &command, - const QStringList &argumments) const + const QStringList &argumments) { QProcess su; @@ -1419,15 +1425,20 @@ su.waitForFinished(-1); if (su.exitCode()) { - QByteArray outMsg = su.readAllStandardOutput(); + auto outMsg = su.readAllStandardOutput(); + this->m_error = {}; - if (!outMsg.isEmpty()) + if (!outMsg.isEmpty()) { qDebug() << outMsg.toStdString().c_str(); + this->m_error += QString(outMsg).toStdWString() + L" "; + } - QByteArray errorMsg = su.readAllStandardError(); + auto errorMsg = su.readAllStandardError(); - if (!errorMsg.isEmpty()) + if (!errorMsg.isEmpty()) { qDebug() << errorMsg.toStdString().c_str(); + this->m_error += QString(outMsg).toStdWString(); + } return false; } @@ -1436,7 +1447,7 @@ } bool AkVCam::IpcBridgePrivate::sudo(const std::string &command, - const QStringList &argumments) const + const QStringList &argumments) { return this->sudo(QString::fromStdString(command), argumments); } @@ -2364,8 +2375,11 @@ { auto deviceNR = requestDeviceNR(2); - if (deviceNR.count() < 2) + if (deviceNR.count() < 2) { + this->m_error = L"No available devices to create a virtual camera"; + return {}; + } auto devices = this->devicesInfo("akvcam"); @@ -2547,8 +2561,11 @@ QFile cmds(tempDir.path() + "/akvcam_exec.sh"); - if (!cmds.open(QIODevice::WriteOnly | QIODevice::Text)) + if (!cmds.open(QIODevice::WriteOnly | QIODevice::Text)) { + this->m_error = L"Can't create install script"; + return {}; + } cmds.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner @@ -2610,8 +2627,11 @@ auto devicePath = QString("/dev/video%1").arg(deviceNR[1]); - if (!this->waitFroDevice(devicePath)) + if (!this->waitFroDevice(devicePath)) { + this->m_error = L"Time exceeded while waiting for the device"; + return {}; + } return devicePath.toStdString(); } @@ -3135,8 +3155,11 @@ { auto deviceNR = requestDeviceNR(1); - if (deviceNR.count() < 1) + if (deviceNR.count() < 1) { + this->m_error = L"No available devices to create a virtual camera"; + return {}; + } auto devicePath = QString("/dev/video%1").arg(deviceNR.front()); auto devices = this->devicesInfo("v4l2 loopback"); @@ -3168,8 +3191,11 @@ QTemporaryDir tempDir; QFile cmds(tempDir.path() + "/akvcam_exec.sh"); - if (!cmds.open(QIODevice::WriteOnly | QIODevice::Text)) + if (!cmds.open(QIODevice::WriteOnly | QIODevice::Text)) { + this->m_error = L"Can't create install script"; + return {}; + } cmds.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner @@ -3206,8 +3232,11 @@ if (!this->sudo(this->self->rootMethod(), {"sh", cmds.fileName()})) return {}; - if (!this->waitFroDevice(devicePath)) + if (!this->waitFroDevice(devicePath)) { + this->m_error = L"Time exceeded while waiting for the device"; + return {}; + } auto devicesInfo = this->readDevicesConfigs(); QSettings settings(QCoreApplication::organizationName(), diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/fraction.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/fraction.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/fraction.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/fraction.h 2021-02-15 15:25:23.000000000 +0000 @@ -27,7 +27,7 @@ { class Fraction; class FractionPrivate; - typedef std::pair FractionRange; + using FractionRange = std::pair; class Fraction { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformat.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -257,7 +257,7 @@ size_t AkVCam::VideoFormat::planeSize(size_t plane) const { - return size_t(this->d->m_height) * this->bypl( plane); + return size_t(this->d->m_height) * this->bypl(plane); } bool AkVCam::VideoFormat::isValid() const diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformattypes.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformattypes.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformattypes.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoformattypes.h 2021-02-15 15:25:23.000000000 +0000 @@ -30,7 +30,7 @@ namespace AkVCam { - typedef uint32_t FourCC; + using FourCC = uint32_t; enum PixelFormat { diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoframe.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoframe.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoframe.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoframe.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -25,8 +25,6 @@ #include "videoframe.h" #include "videoformat.h" #include "../utils.h" -#include "../membuffer/imembuffer.h" -#include "../resources/rcloader.h" namespace AkVCam { @@ -304,18 +302,6 @@ this->load(fileName); } -AkVCam::VideoFrame::VideoFrame(std::streambuf *stream) -{ - this->d = new VideoFramePrivate(this); - this->load(stream); -} - -AkVCam::VideoFrame::VideoFrame(std::istream *stream) -{ - this->d = new VideoFramePrivate(this); - this->load(stream); -} - AkVCam::VideoFrame::VideoFrame(const AkVCam::VideoFormat &format) { this->d = new VideoFramePrivate(this); @@ -347,49 +333,28 @@ delete this->d; } +// http://www.dragonwins.com/domains/getteched/bmp/bmpfileformat.htm bool AkVCam::VideoFrame::load(const std::string &fileName) { if (fileName.empty()) return false; - if (fileName[0] == ':') { - IMemBuffer stream; - - if (!RcLoader::load(fileName, &stream)) - return false; - - return this->load(&stream); - } - std::ifstream stream(fileName); if (!stream.is_open()) return false; - return this->load(&stream); -} - -bool AkVCam::VideoFrame::load(std::streambuf *stream) -{ - std::istream stream_(stream); - - return this->load(&stream_); -} - -// http://www.dragonwins.com/domains/getteched/bmp/bmpfileformat.htm -bool AkVCam::VideoFrame::load(std::istream *stream) -{ char type[2]; - stream->read(type, 2); + stream.read(type, 2); if (memcmp(type, "BM", 2) != 0) return false; BmpHeader header {}; - stream->read(reinterpret_cast(&header), sizeof(BmpHeader)); + stream.read(reinterpret_cast(&header), sizeof(BmpHeader)); BmpImageHeader imageHeader {}; - stream->read(reinterpret_cast(&imageHeader), sizeof(BmpImageHeader)); + stream.read(reinterpret_cast(&imageHeader), sizeof(BmpImageHeader)); VideoFormat format(PixelFormatRGB24, int(imageHeader.width), int(imageHeader.height)); @@ -397,50 +362,62 @@ if (format.size() < 1) return false; - stream->seekg(header.offBits, std::ios_base::beg); + stream.seekg(header.offBits, std::ios_base::beg); this->d->m_format = format; this->d->m_data.resize(format.size()); + VideoData data(imageHeader.sizeImage); + stream.read(reinterpret_cast(data.data()), + imageHeader.sizeImage); + switch (imageHeader.bitCount) { - case 24: - for (uint32_t y = 0; y < imageHeader.height; y++) { - auto line = reinterpret_cast - (this->line(0, size_t(imageHeader.height - y - 1))); - - for (uint32_t x = 0; x < imageHeader.width; x++) { - BGR24 pixel {}; - stream->read(reinterpret_cast(&pixel), - sizeof(BGR24)); - line[x].r = pixel.r; - line[x].g = pixel.g; - line[x].b = pixel.b; - } + case 24: { + VideoFormat bmpFormat(PixelFormatBGR24, + int(imageHeader.width), + int(imageHeader.height)); + + for (uint32_t y = 0; y < imageHeader.height; y++) { + auto srcLine = reinterpret_cast + (data.data() + y * bmpFormat.bypl(0)); + auto dstLine = reinterpret_cast + (this->line(0, size_t(imageHeader.height - y - 1))); + + for (uint32_t x = 0; x < imageHeader.width; x++) { + dstLine[x].r = srcLine[x].r; + dstLine[x].g = srcLine[x].g; + dstLine[x].b = srcLine[x].b; } + } - break; + break; + } - case 32: - for (uint32_t y = 0; y < imageHeader.height; y++) { - auto line = reinterpret_cast - (this->line(0, size_t(imageHeader.height - y - 1))); - - for (uint32_t x = 0; x < imageHeader.width; x++) { - BGR32 pixel {}; - stream->read(reinterpret_cast(&pixel), - sizeof(BGR32)); - line[x].r = pixel.r; - line[x].g = pixel.g; - line[x].b = pixel.b; - } + case 32: { + VideoFormat bmpFormat(PixelFormatBGR32, + int(imageHeader.width), + int(imageHeader.height)); + + for (uint32_t y = 0; y < imageHeader.height; y++) { + auto srcLine = reinterpret_cast + (data.data() + y * bmpFormat.bypl(0)); + auto dstLine = reinterpret_cast + (this->line(0, size_t(imageHeader.height - y - 1))); + + for (uint32_t x = 0; x < imageHeader.width; x++) { + dstLine[x].r = srcLine[x].r; + dstLine[x].g = srcLine[x].g; + dstLine[x].b = srcLine[x].b; } + } - break; + break; + } - default: - this->d->m_format.clear(); - this->d->m_data.clear(); + default: + this->d->m_format.clear(); + this->d->m_data.clear(); - return false; + return false; } return true; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoframe.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoframe.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoframe.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/image/videoframe.h 2021-02-15 15:25:23.000000000 +0000 @@ -38,16 +38,12 @@ public: VideoFrame(); VideoFrame(const std::string &fileName); - VideoFrame(std::streambuf *stream); - VideoFrame(std::istream *stream); VideoFrame(const VideoFormat &format); VideoFrame(const VideoFrame &other); VideoFrame &operator =(const VideoFrame &other); ~VideoFrame(); bool load(const std::string &fileName); - bool load(std::streambuf *stream); - bool load(std::istream *stream); VideoFormat format() const; VideoFormat &format(); VideoData data() const; diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/membuffer/imembuffer.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/membuffer/imembuffer.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/membuffer/imembuffer.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/membuffer/imembuffer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,343 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "imembuffer.h" -#include "../utils.h" - -namespace AkVCam -{ - class IMemBufferPrivate - { - public: - size_t m_size; - uint64_t *m_ref; - IMemBuffer::Mode m_mode; - bool m_isBigEndian; - }; -} - -AkVCam::IMemBuffer::IMemBuffer(const char *stream, - size_t size, - bool isBigEndian, - Mode mode) -{ - this->d = new IMemBufferPrivate; - this->d->m_mode = mode; - char *data = nullptr; - - if (mode == ModeRead) { - data = const_cast(stream); - this->d->m_ref = nullptr; - } else if (mode == ModeHold) { - data = const_cast(stream); - this->d->m_ref = new uint64_t(1); - } else { - data = new char[size]; - memcpy(data, stream, size); - this->d->m_ref = new uint64_t(1); - } - - this->d->m_size = size; - this->d->m_isBigEndian = isBigEndian; - this->setg(data, data, data + size - 1); -} - -AkVCam::IMemBuffer::IMemBuffer(const unsigned char *stream, - size_t size, - bool isBigEndian, - Mode mode) -{ - this->d = new IMemBufferPrivate; - this->d->m_mode = mode; - char *data = nullptr; - - if (mode == ModeRead) { - data = reinterpret_cast(const_cast(stream)); - this->d->m_ref = nullptr; - } else if (mode == ModeHold) { - data = reinterpret_cast(const_cast(stream)); - this->d->m_ref = new uint64_t(1); - } else { - data = new char[size]; - memcpy(data, stream, size); - this->d->m_ref = new uint64_t(1); - } - - this->d->m_size = size; - this->d->m_isBigEndian = isBigEndian; - this->setg(data, data, data + size - 1); -} - -AkVCam::IMemBuffer::IMemBuffer(const char *stream, size_t size, Mode mode) -{ - this->d = new IMemBufferPrivate(); - this->d->m_mode = mode; - char *data = nullptr; - - if (mode == ModeRead) { - data = const_cast(stream); - this->d->m_ref = nullptr; - } else if (mode == ModeHold) { - data = const_cast(stream); - this->d->m_ref = new uint64_t(1); - } else { - data = new char[size]; - memcpy(data, stream, size); - this->d->m_ref = new uint64_t(1); - } - - this->d->m_size = size; - this->d->m_isBigEndian = false; - this->setg(data, data, data + size - 1); -} - -AkVCam::IMemBuffer::IMemBuffer(const unsigned char *stream, - size_t size, - Mode mode) -{ - this->d = new IMemBufferPrivate(); - this->d->m_mode = mode; - char *data = nullptr; - - if (mode == ModeRead) { - data = reinterpret_cast(const_cast(stream)); - this->d->m_ref = nullptr; - } else if (mode == ModeHold) { - data = reinterpret_cast(const_cast(stream)); - this->d->m_ref = new uint64_t(1); - } else { - data = new char[size]; - memcpy(data, stream, size); - this->d->m_ref = new uint64_t(1); - } - - this->d->m_size = size; - this->d->m_isBigEndian = false; - this->setg(data, data, data + size - 1); -} - -AkVCam::IMemBuffer::IMemBuffer(const char *stream, bool isBigEndian) -{ - this->d = new IMemBufferPrivate(); - this->d->m_mode = ModeRead; - this->d->m_size = 0; - this->d->m_ref = nullptr; - this->d->m_isBigEndian = isBigEndian; - this->setg(const_cast(stream), - const_cast(stream), - const_cast(stream)); -} - -AkVCam::IMemBuffer::IMemBuffer(const unsigned char *stream, bool isBigEndian) -{ - this->d = new IMemBufferPrivate(); - this->d->m_mode = ModeRead; - this->d->m_size = 0; - this->d->m_ref = nullptr; - this->d->m_isBigEndian = isBigEndian; - this->setg(reinterpret_cast(const_cast(stream)), - reinterpret_cast(const_cast(stream)), - reinterpret_cast(const_cast(stream))); -} - -AkVCam::IMemBuffer::~IMemBuffer() -{ - if (this->d->m_mode != ModeRead) { - (*this->d->m_ref)--; - - if (!*this->d->m_ref) { - delete [] this->eback(); - delete this->d->m_ref; - } - } - - delete this->d; -} - -void AkVCam::IMemBuffer::setMem(const char *stream, - size_t size, - bool isBigEndian, - Mode mode) -{ - if (this->d->m_mode != ModeRead) { - (*this->d->m_ref)--; - - if (!*this->d->m_ref) { - delete [] this->eback(); - delete this->d->m_ref; - } - } - - this->d->m_mode = mode; - char *data = nullptr; - - if (mode == ModeRead) { - data = const_cast(stream); - this->d->m_ref = nullptr; - } else if (mode == ModeHold) { - data = const_cast(stream); - this->d->m_ref = new uint64_t(1); - } else { - data = new char[size]; - memcpy(data, stream, size); - this->d->m_ref = new uint64_t(1); - } - - this->d->m_size = size; - this->d->m_isBigEndian = isBigEndian; - this->setg(data, data, data + size - 1); -} - -void AkVCam::IMemBuffer::setMem(const unsigned char *stream, - size_t size, - bool isBigEndian, - Mode mode) -{ - this->setMem(reinterpret_cast(stream), - size, - isBigEndian, - mode); -} - -void AkVCam::IMemBuffer::setMem(const char *stream, - size_t size, - Mode mode) -{ - this->setMem(stream, size, false, mode); -} - -void AkVCam::IMemBuffer::setMem(const unsigned char *stream, - size_t size, - Mode mode) -{ - this->setMem(reinterpret_cast(stream), size, mode); -} - -void AkVCam::IMemBuffer::setMem(const char *stream, bool isBigEndian) -{ - this->setMem(stream, 0, isBigEndian, ModeRead); -} - -void AkVCam::IMemBuffer::setMem(const unsigned char *stream, bool isBigEndian) -{ - this->setMem(reinterpret_cast(stream), isBigEndian); -} - -void AkVCam::IMemBuffer::copy(const AkVCam::IMemBuffer &other) -{ - if (this->d->m_mode != ModeRead) { - (*this->d->m_ref)--; - - if (!*this->d->m_ref) { - delete [] this->eback(); - delete this->d->m_ref; - } - } - - this->d->m_mode = other.d->m_mode; - this->d->m_size = other.d->m_size; - this->d->m_ref = other.d->m_ref; - this->d->m_isBigEndian = other.d->m_isBigEndian; - this->setg(other.eback(), other.gptr(), other.egptr()); - - if (this->d->m_mode != ModeRead) - (*this->d->m_ref)++; -} - -AkVCam::IMemBuffer::operator bool() const -{ - return this->eback() != nullptr; -} - -const char *AkVCam::IMemBuffer::data() const -{ - return this->gptr(); -} - -size_t AkVCam::IMemBuffer::size() const -{ - return this->d->m_size; -} - -bool AkVCam::IMemBuffer::isBigEndian() const -{ - return this->d->m_isBigEndian; -} - -std::streampos AkVCam::IMemBuffer::seekoff(std::streamoff off, - std::ios_base::seekdir way, - std::ios_base::openmode which) -{ - UNUSED(which) - - switch (way) { - case std::ios_base::beg: - this->setg(this->eback(), - this->eback() + off, - this->eback() + this->d->m_size - 1); - - break; - - case std::ios_base::cur: - this->gbump(int(off)); - - break; - - case std::ios_base::end: - this->setg(this->eback(), - this->eback() - + (int64_t(this->d->m_size) + off - 1) - % int64_t(this->d->m_size), - this->eback() + this->d->m_size - 1); - - break; - - default: - break; - } - - return this->gptr() - this->eback(); -} - -std::streampos AkVCam::IMemBuffer::seekpos(std::streampos sp, - std::ios_base::openmode which) -{ - return this->seekoff(sp, std::ios_base::beg, which); -} - -std::streamsize AkVCam::IMemBuffer::showmanyc() -{ - return std::streamsize(this->d->m_size) - - std::streamsize(this->gptr()) - + std::streamsize(this->eback()); -} - -std::streamsize AkVCam::IMemBuffer::xsgetn(char *s, std::streamsize n) -{ - auto available = this->showmanyc(); - - if (available < 1) - return 0; - - n = std::min(n, std::streamsize(available)); - memcpy(s, this->data(), size_t(n)); - this->gbump(int(n)); - - return n; -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/membuffer/imembuffer.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/membuffer/imembuffer.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/membuffer/imembuffer.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/membuffer/imembuffer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef AKVCAMUTILS_IMEMBUFFER_H -#define AKVCAMUTILS_IMEMBUFFER_H - -#include -#include -#include - -namespace AkVCam -{ - class IMemBufferPrivate; - - class IMemBuffer: public std::streambuf - { - public: - enum Mode - { - ModeRead, - ModeHold, - ModeCopy - }; - - IMemBuffer(const char *stream=nullptr, - size_t size=0, - bool isBigEndian=false, - Mode mode=ModeRead); - IMemBuffer(const unsigned char *stream, - size_t size=0, - bool isBigEndian=false, - Mode mode=ModeRead); - IMemBuffer(const char *stream, size_t size, Mode mode); - IMemBuffer(const unsigned char *stream, size_t size, Mode mode); - IMemBuffer(const char *stream, bool isBigEndian); - IMemBuffer(const unsigned char *stream, bool isBigEndian); - ~IMemBuffer(); - operator bool() const; - void setMem(const char *stream=nullptr, - size_t size=0, - bool isBigEndian=false, - Mode mode=ModeRead); - void setMem(const unsigned char *stream=nullptr, - size_t size=0, - bool isBigEndian=false, - Mode mode=ModeRead); - void setMem(const char *stream, size_t size, Mode mode); - void setMem(const unsigned char *stream, size_t size, Mode mode); - void setMem(const char *stream, bool isBigEndian); - void setMem(const unsigned char *stream, bool isBigEndian); - void copy(const IMemBuffer &other); - const char *data() const; - - template - inline const T *data() const - { - return reinterpret_cast(this->data()); - } - - size_t size() const; - bool isBigEndian() const; - - template - inline T read() - { - T value = 0; - - if (!memcpy(&value, this->data(), sizeof(T))) - return T(0); - - if (this->isBigEndian()) - std::reverse(reinterpret_cast(&value), - reinterpret_cast(&value) + sizeof(T)); - - this->gbump(sizeof(T)); - - return value; - } - - template - inline std::streampos seek(std::ios_base::seekdir way=std::ios_base::cur) - { - return this->seekoff(sizeof(T), way); - } - - private: - IMemBufferPrivate *d; - - protected: - std::streampos seekoff(std::streamoff off, - std::ios_base::seekdir way=std::ios_base::cur, - std::ios_base::openmode which=std::ios_base::in|std::ios_base::out); - std::streampos seekpos(std::streampos sp, - std::ios_base::openmode which=std::ios_base::in | std::ios_base::out); - std::streamsize showmanyc(); - std::streamsize xsgetn(char *s, std::streamsize n); - }; - - template<> - inline std::string IMemBuffer::read() - { - if (!this->data()) - return {}; - - std::string str(this->data()); - this->gbump(int(str.size() + 1)); - - return str; -}} - -#endif // AKVCAMUTILS_IMEMBUFFER_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcdata.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcdata.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcdata.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcdata.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "rcdata.h" -#include "../membuffer/imembuffer.h" - -uint32_t AkVCam::RcData::size() const -{ - return this->m_size; -} - -AkVCam::RcData AkVCam::RcData::read(const unsigned char *rcData) -{ - IMemBuffer dataStream(rcData, true); - RcData data {}; - data.m_size = dataStream.read(); - data.m_data = dataStream.data(); - - return data; -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcdata.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcdata.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcdata.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcdata.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef AKVCAMUTILS_RCDATA_H -#define AKVCAMUTILS_RCDATA_H - -#include - -namespace AkVCam -{ - struct RcData - { - uint32_t m_size; - const unsigned char *m_data; - - uint32_t size() const; - static RcData read(const unsigned char *rcData); - }; -} - -#endif // AKVCAMUTILS_RCDATA_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcloader.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcloader.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcloader.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcloader.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include -#include - -#include "rcloader.h" -#include "rcnode.h" -#include "rcname.h" -#include "rcdata.h" -#include "../membuffer/imembuffer.h" - -#ifndef UNUSED - #define UNUSED(x) (void)(x); -#endif - -namespace AkVCam -{ - std::map *rcLoaderResources() - { - static std::map resources; - - return &resources; - } -} - -std::list AkVCam::RcLoader::list() -{ - std::list resources; - - for (auto &res: *rcLoaderResources()) - resources.push_back(res.first); - - return resources; -} - -bool AkVCam::RcLoader::load(const std::string &resource, - IMemBuffer *buffer) -{ - if (!buffer) - return false; - - for (auto &res: *rcLoaderResources()) - if (res.first == resource) { - buffer->setMem(res.second.m_data, size_t(res.second.m_size)); - - return true; - } - - return false; -} - -namespace QT_NAMESPACE -{ - bool qRegisterResourceData(int rcVersion, - const unsigned char *rcTree, - const unsigned char *rcName, - const unsigned char *rcData) - { - if (rcVersion != 0x1 && rcVersion != 0x2) - return false; - - std::queue nodes; - nodes.push(RcNode::read(rcTree, rcVersion)); - bool isRoot = true; - const unsigned int nodeSize = rcVersion == 1? 14: 22; - - while (!nodes.empty()) { - auto node = nodes.front(); - nodes.pop(); - std::string path; - - if (isRoot) { - path = ":"; - isRoot = false; - } else { - path = node.parent + "/" + RcName::read(rcName + node.nameOffset); - } - - if (node.flags == RcNode::NodeType_Folder) { - for (uint32_t i = 0; i < node.fd.count; i++) { - nodes.push(RcNode::read(rcTree + nodeSize * (node.firstChild + i), rcVersion)); - nodes.back().parent = path; - } - } else { - (*rcLoaderResources())[path] = - RcData::read(rcData + node.dataOffset); - } - }; - - return true; - } - - bool qUnregisterResourceData(int rcVersion, - const unsigned char *rcTree, - const unsigned char *rcName, - const unsigned char *rcData) - { - UNUSED(rcVersion) - UNUSED(rcTree) - UNUSED(rcName) - UNUSED(rcData) - - return true; - } -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcloader.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcloader.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcloader.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcloader.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef AKVCAMUTILS_RCLOADER_H -#define AKVCAMUTILS_RCLOADER_H - -#include -#include - -namespace AkVCam -{ - class IMemBuffer; - - namespace RcLoader - { - std::list list(); - bool load(const std::string &resource, IMemBuffer *buffer); - } -} - -#endif // AKVCAMUTILS_RCLOADER_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcname.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcname.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcname.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcname.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "rcname.h" -#include "../membuffer/imembuffer.h" - -std::string AkVCam::RcName::read(const unsigned char *rcName) -{ - IMemBuffer nameStream(rcName, true); - auto size = nameStream.read(); - nameStream.seek(); - std::wstring wstr; - - for (decltype(size) i = 0; i < size; i++) - wstr += wchar_t(nameStream.read()); - - return std::string(wstr.begin(), wstr.end()); -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcname.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcname.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcname.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcname.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef AKVCAMUTILS_RCNAME_H -#define AKVCAMUTILS_RCNAME_H - -#include -#include - -namespace AkVCam -{ - struct RcName - { - uint16_t m_size; - uint32_t m_hash; - uint16_t *m_data; - - static std::string read(const unsigned char *rcName); - }; -} - -#endif // AKVCAMUTILS_RCNAME_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcnode.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcnode.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcnode.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcnode.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include "rcnode.h" -#include "../membuffer/imembuffer.h" - -AkVCam::RcNode::RcNode(): - nameOffset(0), - flags(0), - lastModified(0) -{ - this->fd.count = 0; - this->fd.locale.country = 0; - this->fd.locale.language = 0; - this->firstChild = 0; - this->dataOffset = 0; -} - -AkVCam::RcNode::RcNode(const RcNode &other): - nameOffset(other.nameOffset), - flags(other.flags), - lastModified(other.lastModified), - parent(other.parent) -{ - this->fd.count = other.fd.count; - this->fd.locale.country = other.fd.locale.country; - this->fd.locale.language = other.fd.locale.language; - this->firstChild = other.firstChild; - this->dataOffset = other.dataOffset; -} - -AkVCam::RcNode AkVCam::RcNode::read(const unsigned char *rcTree, - int rcVersion) -{ - IMemBuffer treeStream(rcTree, true); - RcNode node; - node.nameOffset = treeStream.read(); - node.flags = treeStream.read(); - - if (node.flags == NodeType_Folder) { - node.fd.count = treeStream.read(); - node.firstChild = treeStream.read(); - } else { - node.fd.locale.country = treeStream.read(); - node.fd.locale.language = treeStream.read(); - node.dataOffset = treeStream.read(); - } - - if (rcVersion > 1) - node.lastModified = treeStream.read(); - - return node; -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcnode.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcnode.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcnode.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/resources/rcnode.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2017 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifndef AKVCAMUTILS_RCNODE_H -#define AKVCAMUTILS_RCNODE_H - -#include -#include - -namespace AkVCam -{ - struct RcNode - { - enum - { - NodeType_File, - NodeType_Compressed, - NodeType_Folder - }; - - uint32_t nameOffset; - uint16_t flags; - - union - { - uint32_t count; - - struct - { - uint16_t country; - uint16_t language; - } locale; - } fd; - - union - { - uint32_t firstChild; - uint32_t dataOffset; - }; - - uint64_t lastModified; - std::string parent; - - RcNode(); - RcNode(const RcNode &other); - static RcNode read(const unsigned char *rcTree, int rcVersion); - }; -} - -#endif // AKVCAMUTILS_RCNODE_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/utils.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/utils.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/utils.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/src/utils.h 2021-02-15 15:25:23.000000000 +0000 @@ -45,17 +45,17 @@ } #define AKVCAM_CALLBACK(CallbackName, ...) \ - typedef void (*CallbackName##CallbackT)(void *userData, __VA_ARGS__); \ - typedef std::pair CallbackName##Callback; + using CallbackName##CallbackT = void (*)(void *userData, __VA_ARGS__); \ + using CallbackName##Callback = std::pair; #define AKVCAM_CALLBACK_NOARGS(CallbackName) \ - typedef void (*CallbackName##CallbackT)(void *userData); \ - typedef std::pair CallbackName##Callback; + using CallbackName##CallbackT = void (*)(void *userData); \ + using CallbackName##Callback = std::pair; #define AKVCAM_SIGNAL(CallbackName, ...) \ public: \ - typedef void (*CallbackName##CallbackT)(void *userData, __VA_ARGS__); \ - typedef std::pair CallbackName##Callback; \ + using CallbackName##CallbackT = void (*)(void *userData, __VA_ARGS__); \ + using CallbackName##Callback = std::pair; \ \ void connect##CallbackName(void *userData, \ CallbackName##CallbackT callback) \ @@ -93,8 +93,8 @@ #define AKVCAM_SIGNAL_NOARGS(CallbackName) \ public: \ - typedef void (*CallbackName##CallbackT)(void *userData); \ - typedef std::pair CallbackName##Callback; \ + using CallbackName##CallbackT = void (*)(void *userData); \ + using CallbackName##Callback = std::pair; \ \ void connect##CallbackName(void *userData, \ CallbackName##CallbackT callback) \ diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/VCamUtils.pro webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/VCamUtils.pro --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/VCamUtils.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/VCamUtils/VCamUtils.pro 2021-02-15 15:25:23.000000000 +0000 @@ -42,11 +42,6 @@ src/image/videoformat.cpp \ src/image/videoframe.cpp \ src/logger/logger.cpp \ - src/membuffer/imembuffer.cpp \ - src/resources/rcdata.cpp \ - src/resources/rcloader.cpp \ - src/resources/rcname.cpp \ - src/resources/rcnode.cpp \ src/timer.cpp \ src/utils.cpp @@ -58,11 +53,6 @@ src/image/videoframetypes.h \ src/image/videoformattypes.h \ src/logger/logger.h \ - src/membuffer/imembuffer.h \ - src/resources/rcdata.h \ - src/resources/rcloader.h \ - src/resources/rcname.h \ - src/resources/rcnode.h \ src/timer.h \ src/utils.h diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/virtualcameraelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/virtualcameraelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/virtualcameraelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/virtualcameraelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,11 @@ delete this->d; } +QString VirtualCameraElement::errorMessage() const +{ + return QString::fromStdWString(this->d->m_ipcBridge.errorMessage()); +} + QStringList VirtualCameraElement::driverPaths() const { QStringList driverPaths; @@ -168,13 +174,12 @@ return {}; AkVideoCaps videoCaps(streamCaps); - videoCaps.format() = AkVideoCaps::Format_rgb24; - videoCaps.bpp() = AkVideoCaps::bitsPerPixel(AkVideoCaps::Format_rgb24); - videoCaps.width() = roundTo(videoCaps.width(), PREFERRED_ROUNDING); - videoCaps.height() = roundTo(videoCaps.height(), PREFERRED_ROUNDING); + videoCaps.setFormat(AkVideoCaps::Format_rgb24); + videoCaps.setWidth(roundTo(videoCaps.width(), PREFERRED_ROUNDING)); + videoCaps.setHeight(roundTo(videoCaps.height(), PREFERRED_ROUNDING)); this->d->m_streamIndex = streamIndex; - this->d->m_streamCaps = videoCaps.toCaps(); + this->d->m_streamCaps = videoCaps; QVariantMap outputParams = { {"caps", QVariant::fromValue(streamCaps)} @@ -195,15 +200,14 @@ return {}; AkVideoCaps videoCaps(streamCaps); - videoCaps.format() = AkVideoCaps::Format_rgb24; - videoCaps.bpp() = AkVideoCaps::bitsPerPixel(AkVideoCaps::Format_rgb24); - videoCaps.width() = roundTo(videoCaps.width(), PREFERRED_ROUNDING); - videoCaps.height() = roundTo(videoCaps.height(), PREFERRED_ROUNDING); + videoCaps.setFormat(AkVideoCaps::Format_rgb24); + videoCaps.setWidth(roundTo(videoCaps.width(), PREFERRED_ROUNDING)); + videoCaps.setHeight(roundTo(videoCaps.height(), PREFERRED_ROUNDING)); this->d->m_streamIndex = streamIndex; - this->d->m_streamCaps = videoCaps.toCaps(); + this->d->m_streamCaps = videoCaps; - QVariantMap outputParams = { + QVariantMap outputParams { {"caps", QVariant::fromValue(streamCaps)} }; @@ -248,8 +252,12 @@ description.toStdWString(), formats); - if (webcam.empty()) + if (webcam.empty()) { + auto error = this->d->m_ipcBridge.errorMessage(); + emit this->errorMessageChanged(QString::fromStdWString(error)); + return {}; + } emit this->mediasChanged(this->medias()); @@ -304,6 +312,30 @@ context->setContextProperty("controlId", controlId); } +AkPacket VirtualCameraElement::iVideoStream(const AkVideoPacket &packet) +{ + this->d->m_mutex.lock(); + + if (this->state() == AkElement::ElementStatePlaying) { + auto videoPacket = packet.convert(AkVideoCaps::Format_rgb24, 32); + auto fps = AkVCam::Fraction {uint32_t(videoPacket.caps().fps().num()), + uint32_t(videoPacket.caps().fps().den())}; + AkVCam::VideoFormat format(videoPacket.caps().fourCC(), + videoPacket.caps().width(), + videoPacket.caps().height(), + {fps}); + AkVCam::VideoFrame frame(format); + memcpy(frame.data().data(), + videoPacket.buffer().constData(), + size_t(videoPacket.buffer().size())); + this->d->m_ipcBridge.write(this->d->m_curDevice.toStdString(), frame); + } + + this->d->m_mutex.unlock(); + + akSend(packet) +} + void VirtualCameraElement::setDriverPaths(const QStringList &driverPaths) { std::vector paths; @@ -552,32 +584,6 @@ return false; } -AkPacket VirtualCameraElement::iStream(const AkPacket &packet) -{ - this->d->m_mutex.lock(); - - if (this->state() == AkElement::ElementStatePlaying) { - auto videoPacket = AkVideoPacket(packet) - .convert(AkVideoCaps::Format_rgb24) - .roundSizeTo(PREFERRED_ROUNDING); - auto fps = AkVCam::Fraction {uint32_t(videoPacket.caps().fps().num()), - uint32_t(videoPacket.caps().fps().den())}; - AkVCam::VideoFormat format(videoPacket.caps().fourCC(), - videoPacket.caps().width(), - videoPacket.caps().height(), - {fps}); - AkVCam::VideoFrame frame(format); - memcpy(frame.data().data(), - videoPacket.buffer().constData(), - size_t(videoPacket.buffer().size())); - this->d->m_ipcBridge.write(this->d->m_curDevice.toStdString(), frame); - } - - this->d->m_mutex.unlock(); - - akSend(packet) -} - void VirtualCameraElement::rootMethodUpdated(const QString &rootMethod) { this->d->m_ipcBridge.setRootMethod(rootMethod.toStdString()); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/virtualcameraelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/virtualcameraelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/VirtualCamera/src/virtualcameraelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/VirtualCamera/src/virtualcameraelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -29,6 +29,9 @@ class VirtualCameraElement: public AkElement { Q_OBJECT + Q_PROPERTY(QString errorMessage + READ errorMessage + NOTIFY errorMessageChanged) Q_PROPERTY(QStringList driverPaths READ driverPaths WRITE setDriverPaths @@ -69,6 +72,7 @@ VirtualCameraElement(); ~VirtualCameraElement(); + Q_INVOKABLE QString errorMessage() const; Q_INVOKABLE QStringList driverPaths() const; Q_INVOKABLE QStringList medias() const; Q_INVOKABLE QString media() const; @@ -100,8 +104,10 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: + void errorMessageChanged(const QString &error); void driverPathsChanged(const QStringList &driverPaths); void mediasChanged(const QStringList &medias) const; void mediaChanged(const QString &media); @@ -111,7 +117,6 @@ void availableDriversChanged(const QStringList &availableDrivers); void rootMethodChanged(const QString &rootMethod); void availableMethodsChanged(const QStringList &availableMethods); - void error(const QString &message); public slots: void setDriverPaths(const QStringList &driverPaths); @@ -129,7 +134,6 @@ void clearStreams(); bool setState(AkElement::ElementState state); - AkPacket iStream(const AkPacket &packet); private slots: void rootMethodUpdated(const QString &rootMethod); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Warhol/src/warholelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Warhol/src/warholelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Warhol/src/warholelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Warhol/src/warholelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include "warholelement.h" @@ -66,34 +67,19 @@ context->setContextProperty("controlId", this->objectName()); } -void WarholElement::setNFrames(int nFrames) -{ - if (this->d->m_nFrames == nFrames) - return; - - this->d->m_nFrames = nFrames; - emit this->nFramesChanged(nFrames); -} - -void WarholElement::resetNFrames() -{ - this->setNFrames(3); -} - -AkPacket WarholElement::iStream(const AkPacket &packet) +AkPacket WarholElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); src = src.convertToFormat(QImage::Format_ARGB32); - QImage oFrame = QImage(src.size(), src.format()); + QImage oFrame(src.size(), src.format()); int nFrames = this->d->m_nFrames; for (int y = 0; y < src.height(); y++) { - QRgb *oLine = reinterpret_cast(oFrame.scanLine(y)); + auto oLine = reinterpret_cast(oFrame.scanLine(y)); for (int x = 0; x < src.width(); x++) { int p = (x * nFrames) % src.width(); @@ -102,13 +88,27 @@ ((x * nFrames) / src.width()); i = qBound(0, i, this->d->m_colorTable.size() - 1); - const QRgb *iLine = reinterpret_cast(src.constScanLine(q)); + auto iLine = reinterpret_cast(src.constScanLine(q)); oLine[x] = (iLine[p] ^ this->d->m_colorTable[i]) | 0xff000000; } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void WarholElement::setNFrames(int nFrames) +{ + if (this->d->m_nFrames == nFrames) + return; + + this->d->m_nFrames = nFrames; + emit this->nFramesChanged(nFrames); +} + +void WarholElement::resetNFrames() +{ + this->setNFrames(3); +} + #include "moc_warholelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Warhol/src/warholelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Warhol/src/warholelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Warhol/src/warholelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Warhol/src/warholelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void nFramesChanged(int nFrames); @@ -53,8 +54,6 @@ public slots: void setNFrames(int nFrames); void resetNFrames(); - - AkPacket iStream(const AkPacket &packet); }; #endif // WARHOLELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Warp/src/warpelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Warp/src/warpelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Warp/src/warpelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Warp/src/warpelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "warpelement.h" @@ -63,24 +64,9 @@ context->setContextProperty("controlId", this->objectName()); } -void WarpElement::setRipples(qreal ripples) -{ - if (qFuzzyCompare(this->d->m_ripples, ripples)) - return; - - this->d->m_ripples = ripples; - emit this->ripplesChanged(ripples); -} - -void WarpElement::resetRipples() -{ - this->setRipples(4); -} - -AkPacket WarpElement::iStream(const AkPacket &packet) +AkPacket WarpElement::iVideoStream(const AkVideoPacket &packet) { - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); + auto src = packet.toImage(); if (src.isNull()) return AkPacket(); @@ -115,7 +101,7 @@ qreal ripples = this->d->m_ripples * sin((tval - 70) * M_PI / 64); tval = (tval + 1) & 511; - qreal *phiTable = this->d->m_phiTable.data(); + auto phiTable = this->d->m_phiTable.data(); for (int y = 0, i = 0; y < src.height(); y++) { auto oLine = reinterpret_cast(oFrame.scanLine(y)); @@ -126,16 +112,30 @@ int xOrig = int(dx * cos(phi) + x); int yOrig = int(dy * sin(phi) + y); - xOrig = qBound(0, xOrig, src.width()); - yOrig = qBound(0, yOrig, src.height()); + xOrig = qBound(0, xOrig, src.width() - 1); + yOrig = qBound(0, yOrig, src.height() - 1); auto iLine = reinterpret_cast(src.constScanLine(yOrig)); oLine[x] = iLine[xOrig]; } } - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); akSend(oPacket) } +void WarpElement::setRipples(qreal ripples) +{ + if (qFuzzyCompare(this->d->m_ripples, ripples)) + return; + + this->d->m_ripples = ripples; + emit this->ripplesChanged(ripples); +} + +void WarpElement::resetRipples() +{ + this->setRipples(4); +} + #include "moc_warpelement.cpp" diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Warp/src/warpelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Warp/src/warpelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Warp/src/warpelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Warp/src/warpelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -46,6 +46,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void ripplesChanged(qreal ripples); @@ -54,8 +55,6 @@ public slots: void setRipples(qreal ripples); void resetRipples(); - - AkPacket iStream(const AkPacket &packet); }; #endif // WARPELEMENT_H diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Wave/src/waveelement.cpp webcamoid-8.8.0+dfsg/libAvKys/Plugins/Wave/src/waveelement.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Wave/src/waveelement.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Wave/src/waveelement.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "waveelement.h" @@ -105,6 +106,65 @@ context->setContextProperty("controlId", this->objectName()); } +AkPacket WaveElement::iVideoStream(const AkVideoPacket &packet) +{ + auto src = packet.toImage(); + + if (src.isNull()) + return AkPacket(); + + src = src.convertToFormat(QImage::Format_ARGB32); + qreal amplitude = this->d->m_amplitude; + + QImage oFrame(src.width(), src.height(), src.format()); + oFrame.fill(this->d->m_background); + + if (amplitude <= 0.0) + akSend(packet) + + if (amplitude >= 1.0) { + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) + } + + if (src.size() != this->d->m_frameSize) { + this->d->m_frameSize = src.size(); + emit this->frameSizeChanged(src.size()); + } + + this->d->m_mutex.lock(); + QVector sineMap(this->d->m_sineMap); + this->d->m_mutex.unlock(); + + if (sineMap.isEmpty()) + akSend(packet) + + for (int y = 0; y < oFrame.height(); y++) { + // Get input line. + int yi = int(y / (1.0 - amplitude)); + + if (yi < 0 || yi >= src.height()) + continue; + + auto iLine = reinterpret_cast(src.constScanLine(yi)); + + for (int x = 0; x < oFrame.width(); x++) { + // Get output line. + int yo = y + sineMap[x]; + + if (yo < 0 + || yo >= src.height()) + continue; + + QRgb *oLine = reinterpret_cast(oFrame.scanLine(yo)); + oLine[x] = iLine[x]; + } + } + + auto oPacket = AkVideoPacket::fromImage(oFrame, packet); + akSend(oPacket) +} + void WaveElement::setAmplitude(qreal amplitude) { if (qFuzzyCompare(amplitude, this->d->m_amplitude)) @@ -161,66 +221,6 @@ this->setBackground(qRgb(0, 0, 0)); } -AkPacket WaveElement::iStream(const AkPacket &packet) -{ - AkVideoPacket videoPacket(packet); - auto src = videoPacket.toImage(); - - if (src.isNull()) - return AkPacket(); - - src = src.convertToFormat(QImage::Format_ARGB32); - qreal amplitude = this->d->m_amplitude; - - QImage oFrame(src.width(), src.height(), src.format()); - oFrame.fill(this->d->m_background); - - if (amplitude <= 0.0) - akSend(packet) - - if (amplitude >= 1.0) { - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) - } - - if (src.size() != this->d->m_frameSize) { - this->d->m_frameSize = src.size(); - emit this->frameSizeChanged(src.size()); - } - - this->d->m_mutex.lock(); - QVector sineMap(this->d->m_sineMap); - this->d->m_mutex.unlock(); - - if (sineMap.isEmpty()) - akSend(packet) - - for (int y = 0; y < oFrame.height(); y++) { - // Get input line. - int yi = int(y / (1.0 - amplitude)); - - if (yi < 0 || yi >= src.height()) - continue; - - auto iLine = reinterpret_cast(src.constScanLine(yi)); - - for (int x = 0; x < oFrame.width(); x++) { - // Get output line. - int yo = y + sineMap[x]; - - if (yo < 0 - || yo >= src.height()) - continue; - - QRgb *oLine = reinterpret_cast(oFrame.scanLine(yo)); - oLine[x] = iLine[x]; - } - } - - auto oPacket = AkVideoPacket::fromImage(oFrame, videoPacket).toPacket(); - akSend(oPacket) -} - void WaveElement::updateSineMap() { if (this->d->m_frameSize.isEmpty()) diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Plugins/Wave/src/waveelement.h webcamoid-8.8.0+dfsg/libAvKys/Plugins/Wave/src/waveelement.h --- webcamoid-8.6.1+dfsg/libAvKys/Plugins/Wave/src/waveelement.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Plugins/Wave/src/waveelement.h 2021-02-15 15:25:23.000000000 +0000 @@ -65,6 +65,7 @@ QString controlInterfaceProvide(const QString &controlId) const; void controlInterfaceConfigure(QQmlContext *context, const QString &controlId) const; + AkPacket iVideoStream(const AkVideoPacket &packet); signals: void amplitudeChanged(qreal amplitude); @@ -82,7 +83,6 @@ void resetFrequency(); void resetPhase(); void resetBackground(); - AkPacket iStream(const AkPacket &packet); private slots: void updateSineMap(); diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/alsa/alsa.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/alsa/alsa.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/alsa/alsa.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/alsa/alsa.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,10 +16,13 @@ # # Web-Site: http://webcamoid.github.io/ +include(../tests.pri) + SOURCES = \ test.cpp CONFIG += link_pkgconfig PKGCONFIG += alsa +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/avfoundation/avfoundation.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/avfoundation/avfoundation.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/avfoundation/avfoundation.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/avfoundation/avfoundation.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,6 +16,8 @@ # # Web-Site: http://webcamoid.github.io/ +include(../tests.pri) + OBJECTIVE_SOURCES = \ test.mm @@ -25,4 +27,5 @@ -framework Foundation \ -framework AVFoundation +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/cmio/cmio.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/cmio/cmio.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/cmio/cmio.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/cmio/cmio.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,6 +16,8 @@ # # Web-Site: http://webcamoid.github.io/ +include(../tests.pri) + OBJECTIVE_SOURCES = \ test.mm @@ -27,4 +29,5 @@ -framework IOKit \ -framework IOSurface +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/coreaudio/coreaudio.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/coreaudio/coreaudio.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/coreaudio/coreaudio.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/coreaudio/coreaudio.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,6 +16,8 @@ # # Web-Site: http://webcamoid.github.io/ +include(../tests.pri) + OBJECTIVE_SOURCES = \ test.mm @@ -24,4 +26,5 @@ -framework CoreAudio \ -framework AudioUnit +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/dshow/dshow.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/dshow/dshow.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/dshow/dshow.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/dshow/dshow.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,7 +16,7 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) DEFINES += __STDC_CONSTANT_MACROS NO_DSHOW_STRSAFE @@ -34,4 +34,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg/ffmpeg.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg/ffmpeg.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg/ffmpeg.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg/ffmpeg.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config DEFINES += __STDC_CONSTANT_MACROS @@ -38,4 +38,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avcodec_sendrecv/ffmpeg_avcodec_sendrecv.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avcodec_sendrecv/ffmpeg_avcodec_sendrecv.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avcodec_sendrecv/ffmpeg_avcodec_sendrecv.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avcodec_sendrecv/ffmpeg_avcodec_sendrecv.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config DEFINES += __STDC_CONSTANT_MACROS @@ -35,4 +35,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avcodec_subtitledata/ffmpeg_avcodec_subtitledata.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avcodec_subtitledata/ffmpeg_avcodec_subtitledata.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avcodec_subtitledata/ffmpeg_avcodec_subtitledata.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avcodec_subtitledata/ffmpeg_avcodec_subtitledata.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config DEFINES += __STDC_CONSTANT_MACROS @@ -35,4 +35,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avformat_codecpar/ffmpeg_avformat_codecpar.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avformat_codecpar/ffmpeg_avformat_codecpar.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avformat_codecpar/ffmpeg_avformat_codecpar.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avformat_codecpar/ffmpeg_avformat_codecpar.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config DEFINES += __STDC_CONSTANT_MACROS @@ -35,4 +35,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avresample/ffmpeg_avresample.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avresample/ffmpeg_avresample.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avresample/ffmpeg_avresample.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avresample/ffmpeg_avresample.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config DEFINES += __STDC_CONSTANT_MACROS @@ -35,4 +35,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avutil_extraoptions/ffmpeg_avutil_extraoptions.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avutil_extraoptions/ffmpeg_avutil_extraoptions.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avutil_extraoptions/ffmpeg_avutil_extraoptions.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avutil_extraoptions/ffmpeg_avutil_extraoptions.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config DEFINES += __STDC_CONSTANT_MACROS @@ -35,4 +35,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avutil_sampleformat64/ffmpeg_avutil_sampleformat64.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avutil_sampleformat64/ffmpeg_avutil_sampleformat64.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_avutil_sampleformat64/ffmpeg_avutil_sampleformat64.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_avutil_sampleformat64/ffmpeg_avutil_sampleformat64.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config DEFINES += __STDC_CONSTANT_MACROS @@ -35,4 +35,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_swresample/ffmpeg_swresample.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_swresample/ffmpeg_swresample.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ffmpeg_swresample/ffmpeg_swresample.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ffmpeg_swresample/ffmpeg_swresample.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config DEFINES += __STDC_CONSTANT_MACROS @@ -35,4 +35,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/gstreamer/gstreamer.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/gstreamer/gstreamer.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/gstreamer/gstreamer.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/gstreamer/gstreamer.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config !isEmpty(GSTREAMERINCLUDES): INCLUDEPATH += $${GSTREAMERINCLUDES} !isEmpty(GSTREAMERLIBS): LIBS += $${GSTREAMERLIBS} @@ -37,4 +37,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/jack/jack.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/jack/jack.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/jack/jack.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/jack/jack.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,7 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -macx: QT_CONFIG -= no-pkg-config +include(../tests.pri) + +macx | android: QT_CONFIG -= no-pkg-config SOURCES = \ test.cpp @@ -24,4 +26,5 @@ CONFIG += link_pkgconfig PKGCONFIG += jack +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/libusb_has_hotplug/libusb.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/libusb_has_hotplug/libusb.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/libusb_has_hotplug/libusb.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/libusb_has_hotplug/libusb.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2016 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +include(../tests.pri) + +macx | android: QT_CONFIG -= no-pkg-config + +SOURCES = \ + test.cpp + +!isEmpty(LIBUSBINCLUDES): INCLUDEPATH += $${LIBUSBINCLUDES} +!isEmpty(LIBUSBLIBS): LIBS += $${LIBUSBLIBS} + +isEmpty(LIBUSBLIBS) { + CONFIG += link_pkgconfig + + PKGCONFIG += libusb-1.0 +} + +DESTDIR = $${OUT_PWD}/$${BIN_DIR} +TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/libusb_has_hotplug/libuvc.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/libusb_has_hotplug/libuvc.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/libusb_has_hotplug/libuvc.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/libusb_has_hotplug/libuvc.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -# Webcamoid, webcam capture application. -# Copyright (C) 2016 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -CONFIG += console c++11 - -macx: QT_CONFIG -= no-pkg-config - -SOURCES = \ - test.cpp - -!isEmpty(LIBUSBINCLUDES): INCLUDEPATH += $${LIBUSBINCLUDES} -!isEmpty(LIBUSBLIBS): LIBS += $${LIBUSBLIBS} - -isEmpty(LIBUSBLIBS) { - CONFIG += link_pkgconfig - - PKGCONFIG += libusb-1.0 -} - -TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/libuvc/libuvc.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/libuvc/libuvc.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/libuvc/libuvc.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/libuvc/libuvc.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,9 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) -macx: QT_CONFIG -= no-pkg-config +macx | android: QT_CONFIG -= no-pkg-config SOURCES = \ test.cpp @@ -33,4 +33,5 @@ !isEmpty(LIBUVCLIBS): LIBS += $${LIBUVCLIBS} isEmpty(LIBUVCLIBS): PKGCONFIG += libuvc +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/mediafoundation/mediafoundation.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/mediafoundation/mediafoundation.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/mediafoundation/mediafoundation.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/mediafoundation/mediafoundation.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,7 +16,7 @@ # # Web-Site: http://webcamoid.github.io/ -CONFIG += console c++11 +include(../tests.pri) LIBS += \ -lmf \ @@ -29,4 +29,5 @@ SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/mediafoundation/test.cpp webcamoid-8.8.0+dfsg/libAvKys/Tests/mediafoundation/test.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Tests/mediafoundation/test.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/mediafoundation/test.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -26,5 +26,7 @@ int main() { + MFEnumDeviceSources(nullptr, nullptr, nullptr); + return 0; } diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_audio/ndkaudio.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_audio/ndkaudio.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_audio/ndkaudio.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_audio/ndkaudio.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,28 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2016 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +include(../tests.pri) + +SOURCES = \ + test.cpp + +LIBS += \ + -laaudio + +DESTDIR = $${OUT_PWD}/$${BIN_DIR} +TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_audio/test.cpp webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_audio/test.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_audio/test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_audio/test.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,25 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include + +int main() +{ + return 0; +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_camera/ndkcamera.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_camera/ndkcamera.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_camera/ndkcamera.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_camera/ndkcamera.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,30 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2016 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +include(../tests.pri) + +SOURCES = \ + test.cpp + +LIBS += \ + -landroid \ + -lcamera2ndk \ + -lmediandk + +DESTDIR = $${OUT_PWD}/$${BIN_DIR} +TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_camera/test.cpp webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_camera/test.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_camera/test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_camera/test.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,30 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include + +int main() +{ + ACaptureSessionOutputContainer_create(nullptr); + AImageReader_setImageListener(nullptr, nullptr); + ANativeWindow_acquire(nullptr); + + return 0; +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_media/ndkmedia.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_media/ndkmedia.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_media/ndkmedia.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_media/ndkmedia.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,28 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2016 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +include(../tests.pri) + +SOURCES = \ + test.cpp + +LIBS += \ + -lmediandk + +DESTDIR = $${OUT_PWD}/$${BIN_DIR} +TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_media/test.cpp webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_media/test.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Tests/ndk_media/test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/ndk_media/test.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,26 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include + +int main() +{ + return 0; +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/opensl/opensl.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/opensl/opensl.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/opensl/opensl.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/opensl/opensl.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,26 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2016 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +include(../tests.pri) + +SOURCES = \ + test.cpp + +LIBS += -lOpenSLES +DESTDIR = $${OUT_PWD}/$${BIN_DIR} +TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/opensl/test.cpp webcamoid-8.8.0+dfsg/libAvKys/Tests/opensl/test.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Tests/opensl/test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/opensl/test.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,25 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2016 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include + +int main() +{ + return 0; +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/oss/oss.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/oss/oss.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/oss/oss.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/oss/oss.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# Webcamoid, webcam capture application. -# Copyright (C) 2016 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -exists($${INCLUDEDIR}/linux/soundcard.h): DEFINES += HAVE_OSS_LINUX - -SOURCES = \ - test.cpp - -TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/oss/test.cpp webcamoid-8.8.0+dfsg/libAvKys/Tests/oss/test.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Tests/oss/test.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/oss/test.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#ifdef HAVE_OSS_LINUX -#include -#else -#include -#endif - -int main() -{ - return 0; -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/pulseaudio/pulseaudio.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/pulseaudio/pulseaudio.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/pulseaudio/pulseaudio.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/pulseaudio/pulseaudio.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,7 +16,9 @@ # # Web-Site: http://webcamoid.github.io/ -macx: QT_CONFIG -= no-pkg-config +include(../tests.pri) + +macx | android: QT_CONFIG -= no-pkg-config SOURCES = \ test.cpp @@ -24,4 +26,5 @@ CONFIG += link_pkgconfig PKGCONFIG += libpulse-simple +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/qtaudio/qtaudio.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/qtaudio/qtaudio.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/qtaudio/qtaudio.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/qtaudio/qtaudio.pro 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# Webcamoid, webcam capture application. -# Copyright (C) 2016 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -SOURCES = \ - test.cpp - -CONFIG += qt -QT += multimedia - -TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/qtaudio/test.cpp webcamoid-8.8.0+dfsg/libAvKys/Tests/qtaudio/test.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Tests/qtaudio/test.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/qtaudio/test.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* Webcamoid, webcam capture application. - * Copyright (C) 2016 Gonzalo Exequiel Pedone - * - * Webcamoid 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. - * - * Webcamoid 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 Webcamoid. If not, see . - * - * Web-Site: http://webcamoid.github.io/ - */ - -#include -#include -#include - -int main() -{ - return 0; -} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/tests.pri webcamoid-8.8.0+dfsg/libAvKys/Tests/tests.pri --- webcamoid-8.6.1+dfsg/libAvKys/Tests/tests.pri 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/tests.pri 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,45 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +CONFIG += console c++11 + +android { + TARGET_ARCH = $$ANDROID_TARGET_ARCH +} else: msvc { + TARGET_ARCH = $${QMAKE_TARGET.arch} + TARGET_ARCH = $$basename(TARGET_ARCH) + TARGET_ARCH = $$replace(TARGET_ARCH, x64, x86_64) +} else { + TARGET_ARCH = $$system($${QMAKE_CXX} -dumpmachine) + TARGET_ARCH = $$split(TARGET_ARCH, -) + TARGET_ARCH = $$first(TARGET_ARCH) +} + +COMPILER = $$basename(QMAKE_CXX) +COMPILER = $$replace(COMPILER, \+\+, pp) +COMPILER = $$join(COMPILER, _) + +CONFIG(debug, debug|release) { + COMMONS_BUILD_PATH = debug/Qt$${QT_VERSION}/$${COMPILER}/$${TARGET_ARCH} +} else { + COMMONS_BUILD_PATH = release/Qt$${QT_VERSION}/$$COMPILER/$${TARGET_ARCH} +} + +android: COMMONS_BUILD_PATH = $${COMMONS_BUILD_PATH}/$${ANDROID_PLATFORM} + +BIN_DIR = $${COMMONS_BUILD_PATH}/bin diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/v4l2/v4l2.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/v4l2/v4l2.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/v4l2/v4l2.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/v4l2/v4l2.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,7 +16,10 @@ # # Web-Site: http://webcamoid.github.io/ +include(../tests.pri) + SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/v4l2_extendedcontrols/v4l2extendedcontrols.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/v4l2_extendedcontrols/v4l2extendedcontrols.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/v4l2_extendedcontrols/v4l2extendedcontrols.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/v4l2_extendedcontrols/v4l2extendedcontrols.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,7 +16,10 @@ # # Web-Site: http://webcamoid.github.io/ +include(../tests.pri) + SOURCES = \ test.cpp +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/v4l2_extraformats/test.cpp webcamoid-8.8.0+dfsg/libAvKys/Tests/v4l2_extraformats/test.cpp --- webcamoid-8.6.1+dfsg/libAvKys/Tests/v4l2_extraformats/test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/v4l2_extraformats/test.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,38 @@ +/* Webcamoid, webcam capture application. + * Copyright (C) 2017 Gonzalo Exequiel Pedone + * + * Webcamoid 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. + * + * Webcamoid 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 Webcamoid. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + std::cout << V4L2_PIX_FMT_SBGGR12P + << V4L2_PIX_FMT_SGBRG12P + << V4L2_PIX_FMT_SGRBG12P + << V4L2_PIX_FMT_SRGGB12P + << V4L2_PIX_FMT_SGBRG16 + << V4L2_PIX_FMT_SGRBG16 + << V4L2_PIX_FMT_SRGGB16; +} diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/v4l2_extraformats/v4l2extraformats.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/v4l2_extraformats/v4l2extraformats.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/v4l2_extraformats/v4l2extraformats.pro 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/v4l2_extraformats/v4l2extraformats.pro 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,25 @@ +# Webcamoid, webcam capture application. +# Copyright (C) 2017 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +include(../tests.pri) + +SOURCES = \ + test.cpp + +DESTDIR = $${OUT_PWD}/$${BIN_DIR} +TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/v4lutils/v4lutils.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/v4lutils/v4lutils.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/v4lutils/v4lutils.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/v4lutils/v4lutils.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,10 +16,13 @@ # # Web-Site: http://webcamoid.github.io/ +include(../tests.pri) + SOURCES = \ test.cpp CONFIG += link_pkgconfig PKGCONFIG += libv4l2 +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/libAvKys/Tests/wasapi/wasapi.pro webcamoid-8.8.0+dfsg/libAvKys/Tests/wasapi/wasapi.pro --- webcamoid-8.6.1+dfsg/libAvKys/Tests/wasapi/wasapi.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/libAvKys/Tests/wasapi/wasapi.pro 2021-02-15 15:25:23.000000000 +0000 @@ -16,6 +16,8 @@ # # Web-Site: http://webcamoid.github.io/ +include(../tests.pri) + CONFIG += console c++11 SOURCES = \ @@ -25,4 +27,5 @@ -lole32 \ -lwinmm +DESTDIR = $${OUT_PWD}/$${BIN_DIR} TARGET = test_auto diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/build.bat webcamoid-8.8.0+dfsg/ports/ci/appveyor/build.bat --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/build.bat 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/build.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -REM Webcamoid, webcam capture application. -REM Copyright (C) 2016 Gonzalo Exequiel Pedone -REM -REM Webcamoid is free software: you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation, either version 3 of the License, or -REM (at your option) any later version. -REM -REM Webcamoid is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with Webcamoid. If not, see . -REM -REM Web-Site: http://webcamoid.github.io/ - -if "%PLATFORM%" == "x86" ( - set FF_ARCH=win32 - set GST_ARCH=x86 - set VC_ARGS=x86 -) else ( - set FF_ARCH=win64 - set GST_ARCH=x86_64 - set VC_ARGS=amd64 -) - -rem Visual Studio init -if not "%VSPATH%" == "" call "%VSPATH%\vcvarsall" %VC_ARGS% - -set FFMPEG_DEV_PATH=%CD%\ffmpeg-%FFMPEG_VERSION%-%FF_ARCH%-dev -set PATH_ORIG=%PATH% - -if not "%DAILY_BUILD%" == "" goto DailyBuild - -set GSTREAMER_DEV_PATH=C:\gstreamer\1.0\%GST_ARCH% -set PATH=%QTDIR%\bin;%TOOLSDIR%\bin;%CD%\ffmpeg-%FFMPEG_VERSION%-%FF_ARCH%-shared\bin;%GSTREAMER_DEV_PATH%\bin;%PATH% - -qmake -query -qmake Webcamoid.pro ^ - CONFIG+=%CONFIGURATION% ^ - CONFIG+=silent ^ - PREFIX="%INSTALL_PREFIX%" ^ - FFMPEGINCLUDES="%FFMPEG_DEV_PATH%\include" ^ - FFMPEGLIBS=-L"%FFMPEG_DEV_PATH%\lib" ^ - FFMPEGLIBS+=-lavcodec ^ - FFMPEGLIBS+=-lavdevice ^ - FFMPEGLIBS+=-lavformat ^ - FFMPEGLIBS+=-lavutil ^ - FFMPEGLIBS+=-lswresample ^ - FFMPEGLIBS+=-lswscale ^ - GSTREAMERINCLUDES="%GSTREAMER_DEV_PATH%\include" ^ - GSTREAMERINCLUDES+="%GSTREAMER_DEV_PATH%\include\glib-2.0" ^ - GSTREAMERINCLUDES+="%GSTREAMER_DEV_PATH%\lib\glib-2.0\include" ^ - GSTREAMERINCLUDES+="%GSTREAMER_DEV_PATH%\include\gstreamer-1.0" ^ - GSTREAMERLIBS=-L"%GSTREAMER_DEV_PATH%\lib2" ^ - GSTREAMERLIBS+=-lgobject-2.0 ^ - GSTREAMERLIBS+=-lglib-2.0 ^ - GSTREAMERLIBS+=-lgstreamer-1.0 ^ - GSTREAMERLIBS+=-lgstapp-1.0 ^ - GSTREAMERLIBS+=-lgstpbutils-1.0 ^ - GSTREAMERLIBS+=-lgstaudio-1.0 ^ - GSTREAMERLIBS+=-lgstvideo-1.0 - -goto Make - -:DailyBuild - -set PATH=%QTDIR%\bin;%TOOLSDIR%\bin;%CD%\ffmpeg-%FFMPEG_VERSION%-%FF_ARCH%-shared\bin;%PATH% - -qmake -query -qmake Webcamoid.pro ^ - CONFIG+=%CONFIGURATION% ^ - CONFIG+=silent ^ - PREFIX="%INSTALL_PREFIX%" ^ - FFMPEGINCLUDES="%FFMPEG_DEV_PATH%\include" ^ - FFMPEGLIBS=-L"%FFMPEG_DEV_PATH%\lib" ^ - FFMPEGLIBS+=-lavcodec ^ - FFMPEGLIBS+=-lavdevice ^ - FFMPEGLIBS+=-lavformat ^ - FFMPEGLIBS+=-lavutil ^ - FFMPEGLIBS+=-lswresample ^ - FFMPEGLIBS+=-lswscale - -:Make - -%MAKETOOL% -j4 - -if "%DAILY_BUILD%" == "" goto EndScript - -if "%PLATFORM%" == "x86" ( - set DRV_ARCH=x64 -) else ( - set DRV_ARCH=x86 -) - -echo. -echo Building %DRV_ARCH% virtual camera driver -echo. - -mkdir akvcam -cd akvcam - -set PATH=%QTDIR_ALT%\bin;%TOOLSDIR_ALT%\bin;%PATH_ORIG% -qmake -query -qmake ^ - CONFIG+=silent ^ - ..\libAvKys\Plugins\VirtualCamera\VirtualCamera.pro ^ - VIRTUALCAMERAONLY=1 -%MAKETOOL% -j4 - -cd .. -mkdir libAvKys\Plugins\VirtualCamera\src\dshow\VirtualCamera\AkVirtualCamera.plugin\%DRV_ARCH% -xcopy ^ - akvcam\src\dshow\VirtualCamera\AkVirtualCamera.plugin\%DRV_ARCH%\* ^ - libAvKys\Plugins\VirtualCamera\src\dshow\VirtualCamera\AkVirtualCamera.plugin\%DRV_ARCH% ^ - /i /y - -:EndScript - -set PATH=%PATH_ORIG% diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/build.sh webcamoid-8.8.0+dfsg/ports/ci/appveyor/build.sh --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/build.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/build.sh 2021-02-15 15:25:23.000000000 +0000 @@ -18,9 +18,16 @@ # # Web-Site: http://webcamoid.github.io/ -export PATH=/mingw64/bin:$PATH +[ -f environment.sh ] && source environment.sh + +if [ "${PLATFORM}" = x86 ]; then + export PATH=/mingw32/bin:$PATH +else + export PATH=/mingw64/bin:$PATH +fi + qmake -query qmake Webcamoid.pro \ CONFIG+=silent \ - PREFIX="$1" + PREFIX="$INSTALL_PREFIX" make -j4 diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/deploy.bat webcamoid-8.8.0+dfsg/ports/ci/appveyor/deploy.bat --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/deploy.bat 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/deploy.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -REM Webcamoid, webcam capture application. -REM Copyright (C) 2017 Gonzalo Exequiel Pedone -REM -REM Webcamoid is free software: you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation, either version 3 of the License, or -REM (at your option) any later version. -REM -REM Webcamoid is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with Webcamoid. If not, see . -REM -REM Web-Site: http://webcamoid.github.io/ - -if "%PLATFORM%" == "x86" ( - set FF_ARCH=win32 - set GST_ARCH=x86 - set VC_ARGS=x86 - set PYTHON_PATH=C:\%PYTHON_VERSION% -) else ( - set FF_ARCH=win64 - set GST_ARCH=x86_64 - set VC_ARGS=amd64 - set PYTHON_PATH=C:\%PYTHON_VERSION%-x64 -) - -set MAKE_PATH=%TOOLSDIR%\bin\%MAKETOOL%.exe -set GSTREAMER_DEV_PATH=C:\gstreamer\1.0\%GST_ARCH% -set PATH=%QTDIR%\bin;%TOOLSDIR%\bin;%CD%\ffmpeg-%FFMPEG_VERSION%-%FF_ARCH%-shared\bin;%GSTREAMER_DEV_PATH%\bin;%PATH% - -%PYTHON_PATH%\python.exe ports\deploy\deploy.py diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/deploy.sh webcamoid-8.8.0+dfsg/ports/ci/appveyor/deploy.sh --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/deploy.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/deploy.sh 2021-02-15 15:25:23.000000000 +0000 @@ -18,5 +18,18 @@ # # Web-Site: http://webcamoid.github.io/ -export PATH=/mingw64/bin:$PATH +[ -f environment.sh ] && source environment.sh + +cd ports/deploy +git clone https://github.com/webcamoid/DeployTools.git +cd ../.. + +if [ "${PLATFORM}" = x86 ]; then + export PATH=/mingw32/bin:$PATH +else + export PATH=/mingw64/bin:$PATH +fi + +export PYTHONPATH="${PWD}/ports/deploy/DeployTools" + python3 ports/deploy/deploy.py diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/environment_setup.bat webcamoid-8.8.0+dfsg/ports/ci/appveyor/environment_setup.bat --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/environment_setup.bat 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/environment_setup.bat 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,32 @@ +REM Webcamoid, webcam capture application. +REM Copyright (C) 2019 Gonzalo Exequiel Pedone +REM +REM Webcamoid is free software: you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation, either version 3 of the License, or +REM (at your option) any later version. +REM +REM Webcamoid is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with Webcamoid. If not, see . +REM +REM Web-Site: http://webcamoid.github.io/ + +@echo off +set ENVIRONMENT_FILE=environment.sh +del %ENVIRONMENT_FILE% +echo export PLATFORM=%PLATFORM% >> %ENVIRONMENT_FILE% +echo export INSTALL_PREFIX=%INSTALL_PREFIX% >> %ENVIRONMENT_FILE% +echo export DAILY_BUILD=%DAILY_BUILD% >> %ENVIRONMENT_FILE% +echo export RELEASE_BUILD=%RELEASE_BUILD% >> %ENVIRONMENT_FILE% +echo export APPVEYOR_ACCOUNT_NAME=%APPVEYOR_ACCOUNT_NAME% >> %ENVIRONMENT_FILE% +echo export APPVEYOR_JOB_ID=%APPVEYOR_JOB_ID% >> %ENVIRONMENT_FILE% +echo export APPVEYOR_PROJECT_NAME=%APPVEYOR_PROJECT_NAME% >> %ENVIRONMENT_FILE% +echo export APPVEYOR_PROJECT_SLUG=%APPVEYOR_PROJECT_SLUG% >> %ENVIRONMENT_FILE% +echo export TRAVIS_BUILD_WEB_URL=%TRAVIS_BUILD_WEB_URL% >> %ENVIRONMENT_FILE% +echo export APPVEYOR_REPO_BRANCH=%APPVEYOR_REPO_BRANCH% >> %ENVIRONMENT_FILE% +echo export BT_KEY=%BT_KEY% >> %ENVIRONMENT_FILE% diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/install_deps.bat webcamoid-8.8.0+dfsg/ports/ci/appveyor/install_deps.bat --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/install_deps.bat 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/install_deps.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -REM Webcamoid, webcam capture application. -REM Copyright (C) 2017 Gonzalo Exequiel Pedone -REM -REM Webcamoid is free software: you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation, either version 3 of the License, or -REM (at your option) any later version. -REM -REM Webcamoid is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with Webcamoid. If not, see . -REM -REM Web-Site: http://webcamoid.github.io/ - -if "%PLATFORM%" == "x86" ( - set FF_ARCH=win32 - set GST_ARCH=x86 - set VC_ARGS=x86 -) else ( - set FF_ARCH=win64 - set GST_ARCH=x86_64 - set VC_ARGS=amd64 -) - -rem Installing various utilities -choco install -y jfrog-cli - -set PATH=%QTDIR%\bin;%TOOLSDIR%\bin;%PATH% - -rem Install FFmpeg development headers and libraries -set FFMPEG_DEV_FILE=ffmpeg-%FFMPEG_VERSION%-%FF_ARCH%-dev.zip - -if not exist %FFMPEG_DEV_FILE% curl --retry 10 -kLOC - https://ffmpeg.zeranoe.com/builds/%FF_ARCH%/dev/%FFMPEG_DEV_FILE% - -if exist %FFMPEG_DEV_FILE% 7z x %FFMPEG_DEV_FILE% -aoa -bb - -rem Install FFmpeg binaries -set FFMPEG_BIN_FILE=ffmpeg-%FFMPEG_VERSION%-%FF_ARCH%-shared.zip - -if not exist %FFMPEG_BIN_FILE% curl --retry 10 -kLOC - https://ffmpeg.zeranoe.com/builds/%FF_ARCH%/shared/%FFMPEG_BIN_FILE% - -if exist %FFMPEG_BIN_FILE% 7z x %FFMPEG_BIN_FILE% -aoa -bb - -rem Installing GStreamer development headers and libraries -if not "%DAILY_BUILD%" == "" goto Exit - -set GSTREAMER_DEV_FILE=gstreamer-1.0-devel-%GST_ARCH%-%GSTREAMER_VERSION%.msi - -if not exist %GSTREAMER_DEV_FILE% curl --retry 10 -kLOC - https://gstreamer.freedesktop.org/data/pkg/windows/%GSTREAMER_VERSION%/%GSTREAMER_DEV_FILE% - -if exist %GSTREAMER_DEV_FILE% ( - start /b /wait msiexec /i %CD%\%GSTREAMER_DEV_FILE% /quiet /qn /norestart - set GSTREAMER_DEV_PATH=C:\gstreamer\1.0\%GST_ARCH% -) - -rem Copy necessary libraries to an alternative path to avoid conflicts with -rem Qt's MinGW system libraries -if exist %GSTREAMER_DEV_FILE% ( - xcopy %GSTREAMER_DEV_PATH%\lib\*gobject-2.0.* %GSTREAMER_DEV_PATH%\lib2 /i /y - xcopy %GSTREAMER_DEV_PATH%\lib\*glib-2.0.* %GSTREAMER_DEV_PATH%\lib2 /i /y - xcopy %GSTREAMER_DEV_PATH%\lib\*gstreamer-1.0.* %GSTREAMER_DEV_PATH%\lib2 /i /y - xcopy %GSTREAMER_DEV_PATH%\lib\*gstapp-1.0.* %GSTREAMER_DEV_PATH%\lib2 /i /y - xcopy %GSTREAMER_DEV_PATH%\lib\*gstpbutils-1.0.* %GSTREAMER_DEV_PATH%\lib2 /i /y - xcopy %GSTREAMER_DEV_PATH%\lib\*gstaudio-1.0.* %GSTREAMER_DEV_PATH%\lib2 /i /y - xcopy %GSTREAMER_DEV_PATH%\lib\*gstvideo-1.0.* %GSTREAMER_DEV_PATH%\lib2 /i /y -) - -rem Installing GStreamer binaries - -set GSTREAMER_BIN_FILE=gstreamer-1.0-%GST_ARCH%-%GSTREAMER_VERSION%.msi - -if not exist %GSTREAMER_BIN_FILE% curl --retry 10 -kLOC - https://gstreamer.freedesktop.org/data/pkg/windows/%GSTREAMER_VERSION%/%GSTREAMER_BIN_FILE% - -if exist %GSTREAMER_BIN_FILE% ( - start /b /wait msiexec /i %CD%\%GSTREAMER_BIN_FILE% /quiet /qn /norestart -) - -:Exit diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/install_deps.sh webcamoid-8.8.0+dfsg/ports/ci/appveyor/install_deps.sh --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/install_deps.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/install_deps.sh 2021-02-15 15:25:23.000000000 +0000 @@ -18,16 +18,30 @@ # # Web-Site: http://webcamoid.github.io/ +[ -f environment.sh ] && source environment.sh + pacman -Syy pacman --noconfirm --needed -S \ git \ make \ pkg-config \ - python3 \ - mingw-w64-x86_64-pkg-config \ - mingw-w64-x86_64-qt5 \ - mingw-w64-x86_64-ffmpeg \ - mingw-w64-x86_64-gst-plugins-base \ - mingw-w64-x86_64-gst-plugins-good \ - mingw-w64-x86_64-gst-plugins-bad \ - mingw-w64-x86_64-gst-plugins-ugly + python3 + +if [ "${PLATFORM}" = x86 ]; then + packagesArch=i686 +else + packagesArch=x86_64 +fi + +pacman --noconfirm --needed -S \ + mingw-w64-${packagesArch}-pkg-config \ + mingw-w64-${packagesArch}-qt5 \ + mingw-w64-${packagesArch}-ffmpeg + +if [ -z "${DAILY_BUILD}" ] && [ -z "${RELEASE_BUILD}" ]; then + pacman --noconfirm --needed -S \ + mingw-w64-${packagesArch}-gst-plugins-base \ + mingw-w64-${packagesArch}-gst-plugins-good \ + mingw-w64-${packagesArch}-gst-plugins-bad \ + mingw-w64-${packagesArch}-gst-plugins-ugly +fi diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/push_artifacts.bat webcamoid-8.8.0+dfsg/ports/ci/appveyor/push_artifacts.bat --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/push_artifacts.bat 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/push_artifacts.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -REM Webcamoid, webcam capture application. -REM Copyright (C) 2019 Gonzalo Exequiel Pedone -REM -REM Webcamoid is free software: you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation, either version 3 of the License, or -REM (at your option) any later version. -REM -REM Webcamoid is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with Webcamoid. If not, see . -REM -REM Web-Site: http://webcamoid.github.io/ - -if not "%DAILY_BUILD%" == "" ( - for %%f in (ports\deploy\packages_auto\windows\*.exe) do ( - appveyor PushArtifact %%f - ) -) diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/push_artifacts.sh webcamoid-8.8.0+dfsg/ports/ci/appveyor/push_artifacts.sh --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/push_artifacts.sh 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/push_artifacts.sh 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,32 @@ +#!/bin/bash + +# Webcamoid, webcam capture application. +# Copyright (C) 2021 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +[ -f environment.sh ] && source environment.sh + +if [[ ! -z "$DAILY_BUILD" || ! -z "$RELEASE_BUILD" ]]; then + + path=ports/deploy/packages_auto + + for f in $(find $path -type f); do + packagePath=${f#$path/} + folder=$(dirname $packagePath) + appveyor PushArtifact $f + done +fi diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/upload.bat webcamoid-8.8.0+dfsg/ports/ci/appveyor/upload.bat --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/upload.bat 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/upload.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -REM Webcamoid, webcam capture application. -REM Copyright (C) 2019 Gonzalo Exequiel Pedone -REM -REM Webcamoid is free software: you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation, either version 3 of the License, or -REM (at your option) any later version. -REM -REM Webcamoid is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with Webcamoid. If not, see . -REM -REM Web-Site: http://webcamoid.github.io/ - -if not "%DAILY_BUILD%" == "" if "%APPVEYOR_REPO_BRANCH%" == "master" ( - jfrog bt config ^ - --user=hipersayanx ^ - --key=%BT_KEY% ^ - --licenses=GPL-3.0-or-later - - for %%f in (ports\deploy\packages_auto\windows\*.exe) do ( - jfrog bt upload ^ - --user=hipersayanx ^ - --key=%BT_KEY% ^ - --override=true ^ - --publish=true ^ - %%f ^ - webcamoid/webcamoid/webcamoid/daily ^ - windows/ - ) -) diff -Nru webcamoid-8.6.1+dfsg/ports/ci/appveyor/upload.sh webcamoid-8.8.0+dfsg/ports/ci/appveyor/upload.sh --- webcamoid-8.6.1+dfsg/ports/ci/appveyor/upload.sh 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/appveyor/upload.sh 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,64 @@ +#!/bin/bash + +# Webcamoid, webcam capture application. +# Copyright (C) 2021 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +[ -f environment.sh ] && source environment.sh + +if [ ! -z "${USE_WGET}" ]; then + export DOWNLOAD_CMD="wget -nv -c" +else + export DOWNLOAD_CMD="curl --retry 10 -sS -kLOC -" +fi + +if [[ ! -z "$DAILY_BUILD" || ! -z "$RELEASE_BUILD" ]]; then + if [ -z "$DAILY_BUILD" ]; then + VER_MAJ=$(grep -re '^VER_MAJ[[:space:]]*=[[:space:]]*' commons.pri | awk '{print $3}') + VER_MIN=$(grep -re '^VER_MIN[[:space:]]*=[[:space:]]*' commons.pri | awk '{print $3}') + VER_PAT=$(grep -re '^VER_PAT[[:space:]]*=[[:space:]]*' commons.pri | awk '{print $3}') + version=$VER_MAJ.$VER_MIN.$VER_PAT-$APPVEYOR_REPO_BRANCH + publish=false + else + version=daily-$APPVEYOR_REPO_BRANCH + publish=true + fi + + # Upload to Bintray + choco install -y jfrog-cli + + jfrog bt config \ + --user=hipersayanx \ + --key=$BT_KEY \ + --licenses=GPL-3.0-or-later + + path=ports/deploy/packages_auto + + for f in $(find $path -type f); do + packagePath=${f#$path/} + folder=$(dirname $packagePath) + + jfrog bt upload \ + --user=hipersayanx \ + --key=$BT_KEY \ + --override=true \ + --publish=$publish \ + $f \ + webcamoid/webcamoid/webcamoid/$version \ + $folder/ + done +fi diff -Nru webcamoid-8.6.1+dfsg/ports/ci/cirrus/deploy.sh webcamoid-8.8.0+dfsg/ports/ci/cirrus/deploy.sh --- webcamoid-8.6.1+dfsg/ports/ci/cirrus/deploy.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/cirrus/deploy.sh 2021-02-15 15:25:23.000000000 +0000 @@ -18,4 +18,9 @@ # # Web-Site: http://webcamoid.github.io/ +cd ports/deploy +git clone https://github.com/webcamoid/DeployTools.git +cd ../.. + +export PYTHONPATH="${PWD}/ports/deploy/DeployTools" python3 ports/deploy/deploy.py diff -Nru webcamoid-8.6.1+dfsg/ports/ci/cirrus/install_deps.sh webcamoid-8.8.0+dfsg/ports/ci/cirrus/install_deps.sh --- webcamoid-8.6.1+dfsg/ports/ci/cirrus/install_deps.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/cirrus/install_deps.sh 2021-02-15 15:25:23.000000000 +0000 @@ -26,7 +26,7 @@ qt5-qmake \ qt5-buildtools \ qt5-concurrent \ - qt5-multimedia \ + qt5-opengl \ qt5-quickcontrols \ qt5-quickcontrols2 \ qt5-svg \ diff -Nru webcamoid-8.6.1+dfsg/ports/ci/travis/build.sh webcamoid-8.8.0+dfsg/ports/ci/travis/build.sh --- webcamoid-8.6.1+dfsg/ports/ci/travis/build.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/travis/build.sh 2021-02-15 15:25:23.000000000 +0000 @@ -40,7 +40,7 @@ BUILDSCRIPT=dockerbuild.sh -if [ "${DOCKERIMG}" = ubuntu:xenial ]; then +if [ "${DOCKERIMG}" = ubuntu:bionic ]; then cat << EOF > ${BUILDSCRIPT} #!/bin/sh @@ -51,11 +51,30 @@ fi if [ "${ANDROID_BUILD}" = 1 ]; then - export PATH=$PWD/build/Qt/${QTVER}/android_${TARGET_ARCH}/bin:$PATH - export ANDROID_NDK_ROOT=$PWD/build/android-ndk-${NDKVER} - qmake -query - qmake -spec ${COMPILESPEC} Webcamoid.pro \ - CONFIG+=silent + export JAVA_HOME=$(readlink -f /usr/bin/java | sed 's:bin/java::') + export ANDROID_HOME="${PWD}/build/android-sdk" + export ANDROID_NDK="${PWD}/build/android-ndk" + export ANDROID_NDK_HOME=${ANDROID_NDK} + export ANDROID_NDK_PLATFORM=android-${ANDROID_PLATFORM} + export ANDROID_NDK_ROOT=${ANDROID_NDK} + export ANDROID_SDK_ROOT=${ANDROID_HOME} + export PATH="${JAVA_HOME}/bin/java:${PATH}" + export PATH="$PATH:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin" + export PATH="${PATH}:${ANDROID_HOME}/platform-tools" + export PATH="${PATH}:${ANDROID_HOME}/emulator" + export PATH="${PATH}:${ANDROID_NDK}" + export ORIG_PATH="${PATH}" + + for arch_ in $(echo "${TARGET_ARCH}" | tr ":" "\n"); do + export PATH="${PWD}/build/Qt/${QTVER_ANDROID}/android/bin:${ORIG_PATH}" + mkdir build-webcamoid-${arch_} + cd build-webcamoid-${arch_} + qmake -query + qmake -spec ${COMPILESPEC} ../Webcamoid.pro \ + CONFIG+=silent \ + ANDROID_ABIS=${arch_} + cd .. + done elif [ "${ARCH_ROOT_BUILD}" = 1 ]; then sudo mount --bind root.x86_64 root.x86_64 sudo mount --bind $HOME root.x86_64/$HOME @@ -94,7 +113,7 @@ export PATH=$HOME/.local/bin:$PATH if [ "${DOCKERSYS}" = debian ]; then - if [ "${DOCKERIMG}" = ubuntu:xenial ]; then + if [ "${DOCKERIMG}" = ubuntu:bionic ]; then if [ -z "${DAILY_BUILD}" ] && [ -z "${RELEASE_BUILD}" ]; then cat << EOF >> ${BUILDSCRIPT} #!/bin/sh @@ -113,6 +132,7 @@ CONFIG+=silent \ QMAKE_CXX="${COMPILER}" \ NOGSTREAMER=1 \ + NOLIBAVDEVICE=1 \ NOQTAUDIO=1 EOF fi @@ -153,7 +173,14 @@ NJOBS=4 fi -if [ "${ARCH_ROOT_BUILD}" = 1 ]; then +if [ "${ANDROID_BUILD}" = 1 ]; then + for arch_ in $(echo "${TARGET_ARCH}" | tr ":" "\n"); do + export PATH="${PWD}/build/Qt/${QTVER_ANDROID}/android/bin:${ORIG_PATH}" + cd build-webcamoid-${arch_} + make -j${NJOBS} + cd .. + done +elif [ "${ARCH_ROOT_BUILD}" = 1 ]; then cat << EOF > ${BUILDSCRIPT} #!/bin/sh @@ -180,49 +207,3 @@ else ${EXEC} make -j${NJOBS} fi - -if [ "${ARCH_ROOT_BUILD}" = 1 ] && [ ! -z "${ARCH_ROOT_MINGW}" ]; then - if [ "$ARCH_ROOT_MINGW" = x86_64 ]; then - mingw_arch=i686 - mingw_compiler=${COMPILER/x86_64/i686} - mingw_dstdir=x86 - else - mingw_arch=x86_64 - mingw_compiler=${COMPILER/i686/x86_64} - mingw_dstdir=x64 - fi - - echo - echo "Building $mingw_arch virtual camera driver" - echo - sudo mount --bind root.x86_64 root.x86_64 - sudo mount --bind $HOME root.x86_64/$HOME - - cat << EOF > ${BUILDSCRIPT} -#!/bin/sh - -export LC_ALL=C -export HOME=$HOME -mkdir -p $TRAVIS_BUILD_DIR/akvcam -cd $TRAVIS_BUILD_DIR/akvcam -/usr/${mingw_arch}-w64-mingw32/lib/qt/bin/qmake \ - -spec ${COMPILESPEC} \ - ../libAvKys/Plugins/VirtualCamera/VirtualCamera.pro \ - CONFIG+=silent \ - QMAKE_CXX="${mingw_compiler}" \ - VIRTUALCAMERAONLY=1 -make -j${NJOBS} -EOF - chmod +x ${BUILDSCRIPT} - sudo cp -vf ${BUILDSCRIPT} root.x86_64/$HOME/ - - ${EXEC} bash $HOME/${BUILDSCRIPT} - - sudo mkdir -p libAvKys/Plugins/VirtualCamera/src/dshow/VirtualCamera/AkVirtualCamera.plugin/${mingw_dstdir} - sudo cp -rvf \ - akvcam/src/dshow/VirtualCamera/AkVirtualCamera.plugin/${mingw_dstdir}/* \ - libAvKys/Plugins/VirtualCamera/src/dshow/VirtualCamera/AkVirtualCamera.plugin/${mingw_dstdir}/ - - sudo umount root.x86_64/$HOME - sudo umount root.x86_64 -fi diff -Nru webcamoid-8.6.1+dfsg/ports/ci/travis/deploy.sh webcamoid-8.8.0+dfsg/ports/ci/travis/deploy.sh --- webcamoid-8.6.1+dfsg/ports/ci/travis/deploy.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/travis/deploy.sh 2021-02-15 15:25:23.000000000 +0000 @@ -28,10 +28,68 @@ fi fi +cd ports/deploy +git clone https://github.com/webcamoid/DeployTools.git +cd ../.. + DEPLOYSCRIPT=deployscript.sh if [ "${ANDROID_BUILD}" = 1 ]; then - echo "Deploy not supported for Android" + export JAVA_HOME=$(readlink -f /usr/bin/java | sed 's:bin/java::') + export ANDROID_HOME="${PWD}/build/android-sdk" + export ANDROID_NDK="${PWD}/build/android-ndk" + export ANDROID_NDK_HOME=${ANDROID_NDK} + export ANDROID_NDK_PLATFORM=android-${ANDROID_PLATFORM} + export ANDROID_NDK_ROOT=${ANDROID_NDK} + export ANDROID_SDK_ROOT=${ANDROID_HOME} + export PATH="${JAVA_HOME}/bin/java:${PATH}" + export PATH="$PATH:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin" + export PATH="${PATH}:${ANDROID_HOME}/platform-tools" + export PATH="${PATH}:${ANDROID_HOME}/emulator" + export PATH="${PATH}:${ANDROID_NDK}" + export ORIG_PATH="${PATH}" + export KEYSTORE_PATH="${PWD}/keystores/debug.keystore" + nArchs=$(echo "${TARGET_ARCH}" | tr ':' ' ' | wc -w) + lastArch=$(echo "${TARGET_ARCH}" | awk -F: '{print $NF}') + + if [ "${nArchs}" = 1 ]; then + export PATH="${PWD}/build/Qt/${QTVER_ANDROID}/android/bin:${PWD}/.local/bin:${ORIG_PATH}" + export BUILD_PATH=${PWD}/build-webcamoid-${lastArch} + export PYTHONPATH="${PWD}/ports/deploy/DeployTools" + + python3 ports/deploy/deploy.py + else + pkgMerge= + + for arch_ in $(echo "${TARGET_ARCH}" | tr ":" "\n"); do + if [ ! -z "${pkgMerge}" ]; then + pkgMerge=${pkgMerge}: + fi + + pkgMerge=${pkgMerge}${PWD}/build-webcamoid-${arch_} + done + + for arch_ in $(echo "${TARGET_ARCH}" | tr ":" "\n"); do + export PATH="${PWD}/build/Qt/${QTVER_ANDROID}/android/bin:${PWD}/.local/bin:${ORIG_PATH}" + export BUILD_PATH=${PWD}/build-webcamoid-${arch_} + export PYTHONPATH="${PWD}/ports/deploy/DeployTools" + + if [ "${arch_}" = "${lastArch}" ]; then + export PACKAGES_PREPARE_ONLY=0 + export PACKAGES_MERGE="${pkgMerge}" + else + export PACKAGES_PREPARE_ONLY=1 + fi + + export NO_SHOW_PKG_DATA_INFO=1 + + python3 ports/deploy/deploy.py + done + fi + + mkdir -p "${PWD}/ports/deploy/packages_auto" + cp -rvf "${PWD}/build-webcamoid-${lastArch}/ports/deploy/packages_auto"/* \ + "${PWD}/ports/deploy/packages_auto" elif [ "${ARCH_ROOT_BUILD}" = 1 ]; then sudo mount --bind root.x86_64 root.x86_64 sudo mount --bind $HOME root.x86_64/$HOME @@ -41,8 +99,10 @@ export LC_ALL=C export HOME=$HOME -export PATH="\$PWD/.local/bin:\$PATH" +export PATH="$TRAVIS_BUILD_DIR/.local/bin:\$PATH" +export PYTHONPATH="$TRAVIS_BUILD_DIR/ports/deploy/DeployTools" export WINEPREFIX=/opt/.wine +export TRAVIS_BRANCH=$TRAVIS_BRANCH cd $TRAVIS_BUILD_DIR EOF @@ -66,6 +126,8 @@ #!/bin/sh export PATH="\$PWD/.local/bin:\$PATH" +export PYTHONPATH="\$PWD/ports/deploy/DeployTools" +export TRAVIS_BRANCH=$TRAVIS_BRANCH xvfb-run --auto-servernum python3 ports/deploy/deploy.py EOF @@ -73,5 +135,6 @@ ${EXEC} bash ${DEPLOYSCRIPT} elif [ "${TRAVIS_OS_NAME}" = osx ]; then - ${EXEC} python3 ports/deploy/deploy.py + export PYTHONPATH="${PWD}/ports/deploy/DeployTools" + python3 ports/deploy/deploy.py fi diff -Nru webcamoid-8.6.1+dfsg/ports/ci/travis/install_deps.sh webcamoid-8.8.0+dfsg/ports/ci/travis/install_deps.sh --- webcamoid-8.6.1+dfsg/ports/ci/travis/install_deps.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/travis/install_deps.sh 2021-02-15 15:25:23.000000000 +0000 @@ -18,86 +18,35 @@ # # Web-Site: http://webcamoid.github.io/ -readversion() { - libname=$(echo $2 | awk '{print toupper($0)}') +#qtIinstallerVerbose=-v - while read line; do - _vmajor=$(echo $line | grep "^#define LIB${libname}_VERSION_MAJOR" | awk '{print $3}') - _vminor=$(echo $line | grep "^#define LIB${libname}_VERSION_MINOR" | awk '{print $3}') - _vmicro=$(echo $line | grep "^#define LIB${libname}_VERSION_MICRO" | awk '{print $3}') - - if [ -n "$_vmajor" ]; then - vmajor=$_vmajor - fi - - if [ -n "$_vminor" ]; then - vminor=$_vminor - fi - - if [ -n "$_vmicro" ]; then - vmicro=$_vmicro - fi - - if [[ -n "$vmajor" && -n "$vminor" && -n "$vmicro" ]]; then - echo $vmajor.$vminor.$vmicro - - break - fi - done < "$1" -} - -libdescription() { - descriptions=('avcodec Encoding/Decoding Library.' - 'avdevice Special devices muxing/demuxing library.' - 'avfilter Graph-based frame editing library.' - 'avformat I/O and Muxing/Demuxing Library' - 'avutil Common code shared across all FFmpeg libraries.' - 'postproc Video postprocessing library.' - 'swresample Audio resampling, sample format conversion and mixing library.' - 'swscale Color conversion and scaling library.') - - for description in "${descriptions[@]}"; do - if [[ "$description" == $1\ * ]]; then - echo ${description#* } - - break - fi - done -} - -requires() { - deps=('avcodec libswresample, libavutil' - 'avdevice libavfilter, libswscale, libpostproc, libavresample, libavformat, libavcodec, libswresample, libavutil' - 'avfilter libswscale, libpostproc, libavresample, libavformat, libavcodec, libswresample, libavutil' - 'avformat libavcodec, libswresample, libavutil' - 'postproc libavutil' - 'swresample libavutil' - 'swscale libavutil') - - for dep in "${deps[@]}"; do - if [[ "$dep" == $1\ * ]]; then - echo ${dep#* } - - break - fi - done -} +if [ ! -z "${USE_WGET}" ]; then + export DOWNLOAD_CMD="wget -nv -c" +else + export DOWNLOAD_CMD="curl --retry 10 -sS -kLOC -" +fi if [ "${TRAVIS_OS_NAME}" = linux ] && [ "${ANDROID_BUILD}" != 1 ] && [ -z "${ARCH_ROOT_MINGW}" ] ; then + # Install missing dependenies + sudo apt-get -qq -y update + sudo apt-get -qq -y upgrade + sudo apt-get -qq -y install \ + libxkbcommon-x11-0 + mkdir -p .local/bin qtIFW=QtInstallerFramework-linux-x64.run # Install Qt Installer Framework - wget -c http://download.qt.io/official_releases/qt-installer-framework/${QTIFWVER}/${qtIFW} || true + ${DOWNLOAD_CMD} http://download.qt.io/official_releases/qt-installer-framework/${QTIFWVER}/${qtIFW} || true if [ -e ${qtIFW} ]; then chmod +x ${qtIFW} QT_QPA_PLATFORM=minimal \ ./QtInstallerFramework-linux-x64.run \ - -v \ + ${qtIinstallerVerbose} \ --script "$PWD/ports/ci/travis/qtifw_non_interactive_install.qs" \ --no-force-installations @@ -130,28 +79,76 @@ fi if [ "${ANDROID_BUILD}" = 1 ]; then - sudo apt-get -y install make + sudo apt-get -qq -y update + sudo apt-get -qq -y upgrade + + # Install dev tools + sudo apt-get -qq -y install \ + libxkbcommon-x11-0 \ + make \ + openjdk-8-jdk \ + openjdk-8-jre + sudo update-java-alternatives --set java-1.8.0-openjdk-amd64 mkdir -p build cd build + # Install Android SDK + fileName="commandlinetools-linux-${SDKVER}_latest.zip" + ${DOWNLOAD_CMD} "https://dl.google.com/android/repository/${fileName}" + + mkdir -p android-sdk + unzip -q -d android-sdk ${fileName} + # Install Android NDK - wget -c https://dl.google.com/android/repository/android-ndk-${NDKVER}-linux-x86_64.zip - unzip -q android-ndk-${NDKVER}-linux-x86_64.zip + fileName="android-ndk-${NDKVER}-linux-x86_64.zip" + ${DOWNLOAD_CMD} "https://dl.google.com/android/repository/${fileName}" + unzip -q ${fileName} + mv -vf android-ndk-${NDKVER} android-ndk # Install Qt for Android - wget -c https://download.qt.io/archive/qt/${QTVER:0:4}/${QTVER}/qt-opensource-linux-x64-${QTVER}.run - chmod +x qt-opensource-linux-x64-${QTVER}.run + fileName=qt-opensource-linux-x64-${QTVER_ANDROID}.run + ${DOWNLOAD_CMD} "https://download.qt.io/archive/qt/${QTVER_ANDROID:0:4}/${QTVER_ANDROID}/${fileName}" + chmod +x ${fileName} + + # Shutdown network connection so Qt installer does not ask for credentials. + netName=$(ifconfig -s | grep BMRU | awk '{print $1}' | sed 's/.*://g') + sudo ifconfig ${netName} down - QT_QPA_PLATFORM=minimal \ - ./qt-opensource-linux-x64-${QTVER}.run \ - -v \ + export QT_QPA_PLATFORM=minimal + + ./qt-opensource-linux-x64-${QTVER_ANDROID}.run \ + ${qtIinstallerVerbose} \ --script "$PWD/../ports/ci/travis/qt_non_interactive_install.qs" \ --no-force-installations + + # Get network connection up again. + sudo ifconfig ${netName} up + + cd .. + + # Set environment variables for Android build + export JAVA_HOME=$(readlink -f /usr/bin/java | sed 's:bin/java::') + export ANDROID_HOME="${PWD}/build/android-sdk" + export ANDROID_NDK="${PWD}/build/android-ndk" + export ANDROID_NDK_HOME=${ANDROID_NDK} + export PATH="${JAVA_HOME}/bin/java:${PATH}" + export PATH="${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin" + export PATH="${PATH}:${ANDROID_HOME}/platform-tools" + export PATH="${PATH}:${ANDROID_HOME}/emulator" + export PATH="${PATH}:${ANDROID_NDK}" + + # Install Android things + echo y | sdkmanager \ + --sdk_root=${ANDROID_HOME} \ + "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \ + "platform-tools" \ + "platforms;android-${ANDROID_PLATFORM}" \ + "tools" > /dev/null elif [ "${ARCH_ROOT_BUILD}" = 1 ]; then # Download chroot image archImage=archlinux-bootstrap-${ARCH_ROOT_DATE}-x86_64.tar.gz - wget -c ${ARCH_ROOT_URL}/iso/${ARCH_ROOT_DATE}/$archImage + ${DOWNLOAD_CMD} ${ARCH_ROOT_URL}/iso/${ARCH_ROOT_DATE}/$archImage sudo tar xzf $archImage # Configure mirrors @@ -162,7 +159,8 @@ Include = /etc/pacman.d/mirrorlist [ownstuff] -Server = http://martchus.no-ip.biz/repo/arch/ownstuff/os/\$arch +Server = https://ftp.f3l.de/~martchus/\$repo/os/\$arch +Server = http://martchus.no-ip.biz/repo/arch/\$repo/os/\$arch EOF sed -i 's/Required DatabaseOptional/Never/g' pacman.conf sed -i 's/#TotalDownload/TotalDownload/g' pacman.conf @@ -182,7 +180,10 @@ ${EXEC} pacman-key --init ${EXEC} pacman-key --populate archlinux - ${EXEC} pacman -Syy + ${EXEC} pacman -Syu \ + --noconfirm \ + --ignore linux,linux-api-headers,linux-docs,linux-firmware,linux-headers,pacman + ${EXEC} pacman --noconfirm --needed -S \ ccache \ clang \ @@ -201,7 +202,6 @@ qt5-svg \ v4l-utils \ qt5-tools \ - qt5-multimedia \ ffmpeg \ gst-plugins-base-libs \ libpulse \ @@ -209,7 +209,7 @@ jack else ${EXEC} pacman --noconfirm --needed -S \ - gst-plugins-base-libs\ + gst-plugins-base-libs \ mpg123 \ lib32-gst-plugins-base-libs \ lib32-mpg123 \ @@ -219,67 +219,13 @@ mingw-w64-qt5-quickcontrols \ mingw-w64-qt5-quickcontrols2 \ mingw-w64-qt5-svg \ - mingw-w64-qt5-tools - - for mingw_arch in i686 x86_64; do - if [ "$mingw_arch" = x86_64 ]; then - ff_arch=win64 - else - ff_arch=win32 - fi - - for pkg in dev shared; do - package=ffmpeg-${FFMPEG_VERSION}-${ff_arch}-$pkg - wget -c "https://ffmpeg.zeranoe.com/builds/${ff_arch}/$pkg/$package.zip" - unzip $package.zip - done - - # Copy binaries - sudo install -d root.x86_64/usr/${mingw_arch}-w64-mingw32/bin - sudo install -m644 \ - ffmpeg-${FFMPEG_VERSION}-${ff_arch}-shared/bin/*.dll \ - root.x86_64/usr/${mingw_arch}-w64-mingw32/bin/ - - # Copy libraries - sudo install -d root.x86_64/usr/${mingw_arch}-w64-mingw32/include - sudo install -d root.x86_64/usr/${mingw_arch}-w64-mingw32/lib - sudo cp -rf \ - ffmpeg-${FFMPEG_VERSION}-${ff_arch}-dev/include/* \ - root.x86_64/usr/${mingw_arch}-w64-mingw32/include/ - sudo install -m644 \ - ffmpeg-${FFMPEG_VERSION}-${ff_arch}-dev/lib/*.a \ - root.x86_64/usr/${mingw_arch}-w64-mingw32/lib/ - - libdir=root.x86_64/usr/${mingw_arch}-w64-mingw32/lib - pkgconfigdir="$libdir"/pkgconfig - sudo install -d "$pkgconfigdir" - - ls ffmpeg-${FFMPEG_VERSION}-${ff_arch}-dev/lib/*.a | \ - while read lib; do - libname=$(basename $lib | sed 's/.dll.a//g' | sed 's/^lib//g') - version=$(readversion ffmpeg-${FFMPEG_VERSION}-${ff_arch}-dev/include/lib$libname/version.h $libname) - description=$(libdescription $libname) - deps=$(requires $libname) - - cat << EOF > lib$libname.pc -prefix=/usr/${mingw_arch}-w64-mingw32 -exec_prefix=\${prefix} -libdir=\${prefix}/lib - -Name: lib$libname -Description: $description -Version: $version -Requires.private: $deps -Libs: -L\${libdir} -l$libname -EOF - sudo install -m644 lib$libname.pc "$pkgconfigdir/" - done - done + mingw-w64-qt5-tools \ + mingw-w64-ffmpeg qtIFW=QtInstallerFramework-win-x86.exe # Install Qt Installer Framework - wget -c http://download.qt.io/official_releases/qt-installer-framework/${QTIFWVER}/${qtIFW} || true + ${DOWNLOAD_CMD} http://download.qt.io/official_releases/qt-installer-framework/${QTIFWVER}/${qtIFW} || true if [ -e ${qtIFW} ]; then INSTALLSCRIPT=installscript.sh @@ -293,7 +239,7 @@ cd $TRAVIS_BUILD_DIR wine ./${qtIFW} \ - -v \ + ${qtIinstallerVerbose} \ --script "ports/ci/travis/qtifw_non_interactive_install.qs" \ --no-force-installations EOF @@ -310,16 +256,16 @@ elif [ "${DOCKERSYS}" = debian ]; then ${EXEC} apt-get -y update - if [ "${DOCKERIMG}" = ubuntu:xenial ]; then + if [ "${DOCKERIMG}" = ubuntu:bionic ]; then ${EXEC} apt-get -y install software-properties-common - ${EXEC} add-apt-repository ppa:beineri/opt-qt-${QTVER}-xenial + ${EXEC} add-apt-repository ppa:beineri/opt-qt-${QTVER}-bionic fi ${EXEC} apt-get -y update ${EXEC} apt-get -y upgrade # Install dev tools - ${EXEC} apt-get -y install \ + ${EXEC} bash -c "DEBIAN_FRONTEND=noninteractive apt-get -y install \ git \ xvfb \ g++ \ @@ -339,13 +285,13 @@ libavutil-dev \ libavresample-dev \ libswscale-dev \ - libswresample-dev + libswresample-dev" if [ -z "${DAILY_BUILD}" ] && [ -z "${RELEASE_BUILD}" ]; then ${EXEC} apt-get -y install \ libgstreamer-plugins-base1.0-dev - if [ "${DOCKERIMG}" != ubuntu:xenial ]; then + if [ "${DOCKERIMG}" != ubuntu:bionic ]; then ${EXEC} apt-get -y install \ libusb-dev \ libuvc-dev @@ -353,11 +299,10 @@ fi # Install Qt dev - if [ "${DOCKERIMG}" = ubuntu:xenial ]; then + if [ "${DOCKERIMG}" = ubuntu:bionic ]; then ${EXEC} apt-get -y install \ qt${PPAQTVER}tools \ qt${PPAQTVER}declarative \ - qt${PPAQTVER}multimedia \ qt${PPAQTVER}svg \ qt${PPAQTVER}quickcontrols \ qt${PPAQTVER}quickcontrols2 \ @@ -366,7 +311,6 @@ ${EXEC} apt-get -y install \ qt5-qmake \ qtdeclarative5-dev \ - qtmultimedia5-dev \ libqt5opengl5-dev \ libqt5svg5-dev \ qtquickcontrols2-5-dev \ @@ -397,7 +341,6 @@ gcc-c++ \ qt5-qttools-devel \ qt5-qtdeclarative-devel \ - qt5-qtmultimedia-devel \ qt5-qtsvg-devel \ qt5-qtquickcontrols \ qt5-qtquickcontrols2-devel \ @@ -413,6 +356,7 @@ ${EXEC} zypper -n in \ git \ which \ + gzip \ xauth \ xvfb-run \ python3 \ @@ -421,7 +365,6 @@ libqt5-linguist \ libqt5-qtbase-devel \ libqt5-qtdeclarative-devel \ - libqt5-qtmultimedia-devel \ libqt5-qtsvg-devel \ libqt5-qtquickcontrols \ libqt5-qtquickcontrols2 \ @@ -434,13 +377,17 @@ libpulse-devel \ libjack-devel elif [ "${TRAVIS_OS_NAME}" = osx ]; then + brew update + brew upgrade + brew link --overwrite numpy brew install \ p7zip \ - python3 \ + python \ ccache \ pkg-config \ qt5 \ ffmpeg + brew link --overwrite python if [ -z "${DAILY_BUILD}" ] && [ -z "${RELEASE_BUILD}" ]; then brew install \ @@ -451,10 +398,11 @@ libuvc fi + brew link python qtIFW=QtInstallerFramework-mac-x64.dmg # Install Qt Installer Framework - wget -c http://download.qt.io/official_releases/qt-installer-framework/${QTIFWVER}/${qtIFW} || true + ${DOWNLOAD_CMD} http://download.qt.io/official_releases/qt-installer-framework/${QTIFWVER}/${qtIFW} || true if [ -e "${qtIFW}" ]; then hdiutil convert ${qtIFW} -format UDZO -o qtifw @@ -463,7 +411,7 @@ chmod +x qtifw/QtInstallerFramework-mac-x64/QtInstallerFramework-mac-x64.app/Contents/MacOS/QtInstallerFramework-mac-x64 qtifw/QtInstallerFramework-mac-x64/QtInstallerFramework-mac-x64.app/Contents/MacOS/QtInstallerFramework-mac-x64 \ - -v \ + ${qtIinstallerVerbose} \ --script "$PWD/ports/ci/travis/qtifw_non_interactive_install.qs" \ --no-force-installations fi diff -Nru webcamoid-8.6.1+dfsg/ports/ci/travis/qtifw_non_interactive_install.qs webcamoid-8.8.0+dfsg/ports/ci/travis/qtifw_non_interactive_install.qs --- webcamoid-8.6.1+dfsg/ports/ci/travis/qtifw_non_interactive_install.qs 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/travis/qtifw_non_interactive_install.qs 2021-02-15 15:25:23.000000000 +0000 @@ -8,7 +8,6 @@ }) } - Controller.prototype.IntroductionPageCallback = function() { gui.clickButton(buttons.NextButton); diff -Nru webcamoid-8.6.1+dfsg/ports/ci/travis/qt_non_interactive_install.qs webcamoid-8.8.0+dfsg/ports/ci/travis/qt_non_interactive_install.qs --- webcamoid-8.6.1+dfsg/ports/ci/travis/qt_non_interactive_install.qs 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/travis/qt_non_interactive_install.qs 2021-02-15 15:25:23.000000000 +0000 @@ -35,9 +35,7 @@ var widget = gui.currentPageWidget(); widget.deselectAll(); - widget.selectComponent("qt.qt5.5120.android_arm64_v8a"); - widget.selectComponent("qt.qt5.5120.android_armv7"); - widget.selectComponent("qt.qt5.5120.android_x86"); + widget.selectComponent("qt.qt5.5141.android"); gui.clickButton(buttons.NextButton); } @@ -48,11 +46,6 @@ gui.clickButton(buttons.NextButton); } -Controller.prototype.StartMenuDirectoryPageCallback = function() -{ - gui.clickButton(buttons.NextButton); -} - Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton(buttons.NextButton); diff -Nru webcamoid-8.6.1+dfsg/ports/ci/travis/upload.sh webcamoid-8.8.0+dfsg/ports/ci/travis/upload.sh --- webcamoid-8.6.1+dfsg/ports/ci/travis/upload.sh 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/ci/travis/upload.sh 2021-02-15 15:25:23.000000000 +0000 @@ -18,27 +18,35 @@ # # Web-Site: http://webcamoid.github.io/ -if [[ ( ! -z "$DAILY_BUILD" || ! -z "$RELEASE_BUILD" ) && "$TRAVIS_BRANCH" == "master" ]]; then - curl -fL https://getcli.jfrog.io | sh - - ./jfrog bt config \ - --user=hipersayanx \ - --key=$BT_KEY \ - --licenses=GPL-3.0-or-later - - path=ports/deploy/packages_auto +if [ ! -z "${USE_WGET}" ]; then + export DOWNLOAD_CMD="wget -nv -c" +else + export DOWNLOAD_CMD="curl --retry 10 -sS -kLOC -" +fi +if [[ ! -z "$DAILY_BUILD" || ! -z "$RELEASE_BUILD" ]]; then if [ -z "$DAILY_BUILD" ]; then VER_MAJ=$(grep -re '^VER_MAJ[[:space:]]*=[[:space:]]*' commons.pri | awk '{print $3}') VER_MIN=$(grep -re '^VER_MIN[[:space:]]*=[[:space:]]*' commons.pri | awk '{print $3}') VER_PAT=$(grep -re '^VER_PAT[[:space:]]*=[[:space:]]*' commons.pri | awk '{print $3}') - version=$VER_MAJ.$VER_MIN.$VER_PAT + version=$VER_MAJ.$VER_MIN.$VER_PAT-$TRAVIS_BRANCH publish=false else - version=daily + version=daily-$TRAVIS_BRANCH publish=true fi + # Upload to Bintray + + curl -fL https://getcli.jfrog.io | sh + + ./jfrog bt config \ + --user=hipersayanx \ + --key=$BT_KEY \ + --licenses=GPL-3.0-or-later + + path=ports/deploy/packages_auto + for f in $(find $path -type f); do packagePath=${f#$path/} folder=$(dirname $packagePath) @@ -52,4 +60,41 @@ webcamoid/webcamoid/webcamoid/$version \ $folder/ done + + # Upload to Github Releases + upload=false + + if [[ ! -z "$DAILY_BUILD" && "$upload" == true ]]; then + hub='' + + if [ "${TRAVIS_OS_NAME}" = linux ]; then + hub=hub-linux-amd64-${GITHUB_HUBVER} + else + hub=hub-darwin-amd64-${GITHUB_HUBVER} + fi + + cd ${TRAVIS_BUILD_DIR} + ${DOWNLOAD_CMD} https://github.com/github/hub/releases/download/v${GITHUB_HUBVER}/${hub}.tgz || true + tar xzf ${hub}.tgz + mkdir -p .local + cp -rf ${hub}/* .local/ + + export PATH="${PWD}/.local/bin:${PATH}" + + hubTag=$(hub release -df '%T %t%n' | grep 'Daily Build' | awk '{print $1}' | sed 's/.*://') + + if [ -z "$hubTag" ]; then + hub release create -p -m 'Daily Build' daily + hubTag=$(hub release -df '%T %t%n' | grep 'Daily Build' | awk '{print $1}' | sed 's/.*://') + fi + + if [ ! -z "$hubTag" ]; then + path=ports/deploy/packages_auto + + for f in $(find $path -type f); do + hubTag=$(hub release -df '%T %t%n' | grep 'Daily Build' | awk '{print $1}' | sed 's/.*://') + hub release edit -m 'Daily Build' -a "$f" "$hubTag" + done + fi + fi fi diff -Nru webcamoid-8.6.1+dfsg/ports/contributors.py webcamoid-8.8.0+dfsg/ports/contributors.py --- webcamoid-8.6.1+dfsg/ports/contributors.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/contributors.py 2021-02-15 15:25:23.000000000 +0000 @@ -30,7 +30,8 @@ contributors_list = [] exclude = ['hipersayan.x@gmail.com', - 'noreply@weblate.org'] + 'noreply@weblate.org', + 'hosted@weblate.org'] for contributor in contributors: contributor = ' '.join(contributor.split()[1:]) diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/deploy_android.py webcamoid-8.8.0+dfsg/ports/deploy/deploy_android.py --- webcamoid-8.6.1+dfsg/ports/deploy/deploy_android.py 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/deploy_android.py 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,618 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Webcamoid, webcam capture application. +# Copyright (C) 2019 Gonzalo Exequiel Pedone +# +# Webcamoid 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. +# +# Webcamoid 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 Webcamoid. If not, see . +# +# Web-Site: http://webcamoid.github.io/ + +import json +import math +import os +import re +import shutil +import subprocess # nosec +import sys +import threading +import zipfile + +from WebcamoidDeployTools import DTDeployBase +from WebcamoidDeployTools import DTQt5 +from WebcamoidDeployTools import DTBinaryElf +from WebcamoidDeployTools import DTAndroid + + +class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools, DTAndroid.AndroidTools): + def __init__(self): + super().__init__() + self.targetSystem = 'android' + self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv') + self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto/android') + self.standAloneDir = os.path.join(self.buildDir, 'StandAlone') + self.detectQt(self.standAloneDir) + self.programName = 'webcamoid' + self.binarySolver = DTBinaryElf.ElfBinaryTools() + self.detectAndroidPlatform(self.standAloneDir) + binary = self.detectTargetBinaryFromQt5Make(self.standAloneDir) + self.targetArch = self.binarySolver.machineEMCode(binary) + self.androidArchMap = {'AARCH64': 'arm64-v8a', + 'ARM' : 'armeabi-v7a', + '386' : 'x86', + 'X86_64' : 'x86_64'} + + if self.targetArch in self.androidArchMap: + self.targetArch = self.androidArchMap[self.targetArch] + + self.binarySolver.sysBinsPath = self.detectBinPaths() + self.binarySolver.sysBinsPath + self.binarySolver.libsSeachPaths = self.detectLibPaths() + self.rootInstallDir = os.path.join(self.installDir, self.programName) + self.libInstallDir = os.path.join(self.rootInstallDir, + 'libs', + self.targetArch) + self.binaryInstallDir = self.libInstallDir + self.assetsIntallDir = os.path.join(self.rootInstallDir, + 'assets', + 'android_rcc_bundle') + self.qmlInstallDir = os.path.join(self.assetsIntallDir, 'qml') + self.pluginsInstallDir = os.path.join(self.assetsIntallDir, 'plugins') + self.qtConf = os.path.join(self.binaryInstallDir, 'qt.conf') + self.qmlRootDirs = ['StandAlone/share/qml', 'libAvKys/Plugins'] + self.mainBinary = os.path.join(self.binaryInstallDir, os.path.basename(binary)) + self.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri')) + self.detectMake() + self.binarySolver.readExcludes('posix', 'android') + self.binarySolver.libsSeachPaths += [self.qmakeQuery(var='QT_INSTALL_LIBS')] + self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf') + self.dependencies = [] + + @staticmethod + def removeUnneededFiles(path): + afiles = set() + + for root, _, files in os.walk(path): + for f in files: + if f.endswith('.jar'): + afiles.add(os.path.join(root, f)) + + for afile in afiles: + os.remove(afile) + + def prepare(self): + print('Executing make install') + params = {'INSTALL_ROOT': self.rootInstallDir} + self.makeInstall(self.buildDir, params) + self.binarySolver.detectStrip() + + if 'PACKAGES_MERGE' in os.environ \ + and len(os.environ['PACKAGES_MERGE']) > 0: + self.outPackage = \ + os.path.join(self.pkgsDir, + '{}-{}.apk'.format(self.programName, + self.programVersion)) + else: + self.outPackage = \ + os.path.join(self.pkgsDir, + '{}-{}-{}.apk'.format(self.programName, + self.programVersion, + self.targetArch)) + + print('Copying Qml modules\n') + self.solvedepsQml() + print('\nCopying required plugins\n') + self.solvedepsPlugins() + print('\nRemoving unused architectures') + self.removeInvalidArchs() + print('Fixing Android libs\n') + self.fixQtLibs() + + try: + shutil.rmtree(self.pluginsInstallDir) + except: + pass + + print('\nCopying required libs\n') + self.solvedepsLibs() + print('\nSolving Android dependencies\n') + self.solvedepsAndroid() + print('\nCopying Android build templates') + self.copyAndroidTemplates() + print('Fixing libs.xml file') + self.fixLibsXml() + print('Creating .rcc bundle file') + self.createRccBundle() + print('Stripping symbols') + self.binarySolver.stripSymbols(self.rootInstallDir) + print('Removing unnecessary files') + self.removeUnneededFiles(self.libInstallDir) + print('Writting build system information\n') + self.writeBuildInfo() + + def removeInvalidArchs(self): + suffix = '_{}.so'.format(self.targetArch) + + if not self.mainBinary.endswith(suffix): + return + + for root, dirs, files in os.walk(self.assetsIntallDir): + for f in files: + if f.endswith('.so') and not f.endswith(suffix): + os.remove(os.path.join(root, f)) + + def solvedepsLibs(self): + qtLibsPath = self.qmakeQuery(var='QT_INSTALL_LIBS') + self.binarySolver.ldLibraryPath.append(qtLibsPath) + self.qtLibs = sorted(self.binarySolver.scanDependencies(self.rootInstallDir)) + + for dep in self.qtLibs: + depPath = os.path.join(self.libInstallDir, os.path.basename(dep)) + + if dep != depPath: + print(' {} -> {}'.format(dep, depPath)) + self.copy(dep, depPath, True) + self.dependencies.append(dep) + + def searchPackageFor(self, path): + os.environ['LC_ALL'] = 'C' + pacman = self.whereBin('pacman') + + if len(pacman) > 0: + process = subprocess.Popen([pacman, '-Qo', path], # nosec + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, _ = process.communicate() + + if process.returncode != 0: + return '' + + info = stdout.decode(sys.getdefaultencoding()).split(' ') + + if len(info) < 2: + return '' + + package, version = info[-2:] + + return ' '.join([package.strip(), version.strip()]) + + dpkg = self.whereBin('dpkg') + + if len(dpkg) > 0: + process = subprocess.Popen([dpkg, '-S', path], # nosec + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, _ = process.communicate() + + if process.returncode != 0: + return '' + + package = stdout.split(b':')[0].decode(sys.getdefaultencoding()).strip() + + process = subprocess.Popen([dpkg, '-s', package], # nosec + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, _ = process.communicate() + + if process.returncode != 0: + return '' + + for line in stdout.decode(sys.getdefaultencoding()).split('\n'): + line = line.strip() + + if line.startswith('Version:'): + return ' '.join([package, line.split()[1].strip()]) + + return '' + + rpm = self.whereBin('rpm') + + if len(rpm) > 0: + process = subprocess.Popen([rpm, '-qf', path], # nosec + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, _ = process.communicate() + + if process.returncode != 0: + return '' + + return stdout.decode(sys.getdefaultencoding()).strip() + + return '' + + @staticmethod + def sysInfo(): + info = '' + + for f in os.listdir('/etc'): + if f.endswith('-release'): + with open(os.path.join('/etc' , f)) as releaseFile: + info += releaseFile.read() + + return info + + def writeBuildInfo(self): + shareDir = os.path.join(self.rootInstallDir, 'assets') + + try: + os.makedirs(self.pkgsDir) + except: + pass + + depsInfoFile = os.path.join(shareDir, 'build-info.txt') + + if not os.path.exists(shareDir): + os.makedirs(shareDir) + + # Write repository info. + + with open(depsInfoFile, 'w') as f: + commitHash = self.gitCommitHash(self.rootDir) + + if len(commitHash) < 1: + commitHash = 'Unknown' + + print(' Commit hash: ' + commitHash) + f.write('Commit hash: ' + commitHash + '\n') + + buildLogUrl = '' + + if 'TRAVIS_BUILD_WEB_URL' in os.environ: + buildLogUrl = os.environ['TRAVIS_BUILD_WEB_URL'] + elif 'APPVEYOR_ACCOUNT_NAME' in os.environ and 'APPVEYOR_PROJECT_NAME' in os.environ and 'APPVEYOR_JOB_ID' in os.environ: + buildLogUrl = 'https://ci.appveyor.com/project/{}/{}/build/job/{}'.format(os.environ['APPVEYOR_ACCOUNT_NAME'], + os.environ['APPVEYOR_PROJECT_SLUG'], + os.environ['APPVEYOR_JOB_ID']) + + if len(buildLogUrl) > 0: + print(' Build log URL: ' + buildLogUrl) + f.write('Build log URL: ' + buildLogUrl + '\n') + + print() + f.write('\n') + + # Write host info. + + info = self.sysInfo() + + with open(depsInfoFile, 'a') as f: + for line in info.split('\n'): + if len(line) > 0: + print(' ' + line) + f.write(line + '\n') + + print() + f.write('\n') + + # Write SDK and NDK info. + + sdkInfoFile = os.path.join(self.androidSDK, 'tools', 'source.properties') + ndkInfoFile = os.path.join(self.androidNDK, 'source.properties') + + with open(depsInfoFile, 'a') as f: + platform = self.androidPlatform + print(' Android Platform: {}'.format(platform)) + f.write('Android Platform: {}\n'.format(platform)) + print(' SDK Info: \n') + f.write('SDK Info: \n\n') + + with open(sdkInfoFile) as sdkf: + for line in sdkf: + if len(line) > 0: + print(' ' + line.strip()) + f.write(' ' + line) + + print('\n NDK Info: \n') + f.write('\nNDK Info: \n\n') + + with open(ndkInfoFile) as ndkf: + for line in ndkf: + if len(line) > 0: + print(' ' + line.strip()) + f.write(' ' + line) + + print() + f.write('\n') + + # Write binary dependencies info. + + packages = set() + + for dep in self.dependencies: + packageInfo = self.searchPackageFor(dep) + + if len(packageInfo) > 0: + packages.add(packageInfo) + + packages = sorted(packages) + + with open(depsInfoFile, 'a') as f: + for packge in packages: + print(' ' + packge) + f.write(packge + '\n') + + @staticmethod + def hrSize(size): + i = int(math.log(size) // math.log(1024)) + + if i < 1: + return '{} B'.format(size) + + units = ['KiB', 'MiB', 'GiB', 'TiB'] + sizeKiB = size / (1024 ** i) + + return '{:.2f} {}'.format(sizeKiB, units[i - 1]) + + def printPackageInfo(self, path): + if os.path.exists(path): + print(' ', + os.path.basename(path), + self.hrSize(os.path.getsize(path))) + print(' sha256sum:', Deploy.sha256sum(path)) + else: + print(' ', + os.path.basename(path), + 'FAILED') + + def alignPackage(self, package): + deploymentSettingsPath = '' + + for f in os.listdir(self.standAloneDir): + if re.match('^android-.+-deployment-settings.json$' , f): + deploymentSettingsPath = os.path.join(self.standAloneDir, f) + + break + + if len(deploymentSettingsPath) < 1: + return + + with open(deploymentSettingsPath) as f: + deploymentSettings = json.load(f) + + zipalign = os.path.join(self.androidSDK, + 'build-tools', + deploymentSettings['sdkBuildToolsRevision'], + 'zipalign') + + if self.system == 'windows': + zipalign += '.exe' + + alignedPackage = os.path.join(os.path.dirname(package), + 'aligned-' + os.path.basename(package)) + process = subprocess.Popen([zipalign, # nosec + '-v', + '-f', '4', + package, + alignedPackage], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + process.communicate() + + if process.returncode != 0: + return False + + self.move(alignedPackage, package) + + return True + + def apkSignPackage(self, package, keystore): + if not self.alignPackage(package): + return False + + deploymentSettingsPath = '' + + for f in os.listdir(self.standAloneDir): + if re.match('^android-.+-deployment-settings.json$' , f): + deploymentSettingsPath = os.path.join(self.standAloneDir, f) + + break + + if len(deploymentSettingsPath) < 1: + return + + with open(deploymentSettingsPath) as f: + deploymentSettings = json.load(f) + + apkSigner = os.path.join(self.androidSDK, + 'build-tools', + deploymentSettings['sdkBuildToolsRevision'], + 'apksigner') + + if self.system == 'windows': + apkSigner += '.exe' + + process = subprocess.Popen([apkSigner, # nosec + 'sign', + '-v', + '--ks', keystore, + '--ks-pass', 'pass:android', + '--ks-key-alias', 'androiddebugkey', + '--key-pass', 'pass:android', + package], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + process.communicate() + + return process.returncode == 0 + + def jarSignPackage(self, package, keystore): + jarSigner = 'jarsigner' + + if self.system == 'windows': + jarSigner += '.exe' + + jarSignerPath = '' + + if 'JAVA_HOME' in os.environ: + jarSignerPath = os.path.join(os.environ['JAVA_HOME'], + 'bin', + jarSigner) + + if len(jarSignerPath) < 1 or not os.path.exists(jarSignerPath): + jarSignerPath = self.whereBin(jarSigner) + + if len(jarSignerPath) < 1: + return False + + signedPackage = os.path.join(os.path.dirname(package), + 'signed-' + os.path.basename(package)) + process = subprocess.Popen([jarSignerPath, # nosec + '-verbose', + '-keystore', keystore, + '-storepass', 'android', + '-keypass', 'android', + '-sigalg', 'SHA1withRSA', + '-digestalg', 'SHA1', + '-sigfile', 'CERT', + '-signedjar', signedPackage, + package, + 'androiddebugkey'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + process.communicate() + + if process.returncode != 0: + return False + + self.move(signedPackage, package) + + return self.alignPackage(package) + + def signPackage(self, package): + keytool = 'keytool' + + if self.system == 'windows': + keytool += '.exe' + + keytoolPath = '' + + if 'JAVA_HOME' in os.environ: + keytoolPath = os.path.join(os.environ['JAVA_HOME'], 'bin', keytool) + + if len(keytoolPath) < 1 or not os.path.exists(keytoolPath): + keytoolPath = self.whereBin(keytool) + + if len(keytoolPath) < 1: + return False + + keystore = os.path.join(self.rootInstallDir, 'debug.keystore') + + if 'KEYSTORE_PATH' in os.environ: + keystore = os.environ['KEYSTORE_PATH'] + + if not os.path.exists(keystore): + try: + os.makedirs(os.path.dirname(keystore)) + except: + pass + + process = subprocess.Popen([keytoolPath, # nosec + '-genkey', + '-v', + '-storetype', 'pkcs12', + '-keystore', keystore, + '-storepass', 'android', + '-alias', 'androiddebugkey', + '-keypass', 'android', + '-keyalg', 'RSA', + '-keysize', '2048', + '-validity', '10000', + '-dname', 'CN=Android Debug,O=Android,C=US'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + process.communicate() + + if process.returncode != 0: + return False + + if self.apkSignPackage(package, keystore): + return True + + return self.jarSignPackage(package, keystore) + + def createApk(self, mutex): + if 'PACKAGES_MERGE' in os.environ: + print('Merging package data:\n') + + for path in os.environ['PACKAGES_MERGE'].split(':'): + path = path.strip() + + if os.path.exists(path) and os.path.isdir(path): + if path == self.buildDir: + continue + + standAlonePath = os.path.join(path, + os.path.relpath(self.standAloneDir, + self.buildDir)) + binary = self.detectTargetBinaryFromQt5Make(standAlonePath) + targetArch = self.binarySolver.machineEMCode(binary) + + if targetArch in self.androidArchMap: + targetArch = self.androidArchMap[targetArch] + + libsPath = os.path.join(path, + os.path.relpath(self.rootInstallDir, + self.buildDir), + 'libs', + targetArch) + dstLibPath = os.path.join(self.rootInstallDir, + 'libs', + targetArch) + print(' {} -> {}'.format(libsPath, dstLibPath)) + self.copy(libsPath, dstLibPath) + + print() + + if not os.path.exists(self.pkgsDir): + os.makedirs(self.pkgsDir) + + gradleSript = os.path.join(self.rootInstallDir, 'gradlew') + + if self.system == 'windows': + gradleSript += '.bat' + + os.chmod(gradleSript, 0o744) + process = subprocess.Popen([gradleSript, # nosec + '--no-daemon', + '--info', + 'assembleRelease'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=self.rootInstallDir) + process.communicate() + apk = os.path.join(self.rootInstallDir, + 'build', + 'outputs', + 'apk', + 'release', + '{}-release-unsigned.apk'.format(self.programName)) + self.signPackage(apk) + self.copy(apk, self.outPackage) + + print('Created APK package:') + self.printPackageInfo(self.outPackage) + + def package(self): + mutex = threading.Lock() + + threads = [threading.Thread(target=self.createApk, args=(mutex,))] + packagingTools = ['apk'] + + if len(packagingTools) > 0: + print('Detected packaging tools: {}\n'.format(', '.join(packagingTools))) + + for thread in threads: + thread.start() + + for thread in threads: + thread.join() diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/deploy_base.py webcamoid-8.8.0+dfsg/ports/deploy/deploy_base.py --- webcamoid-8.6.1+dfsg/ports/deploy/deploy_base.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/deploy_base.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Webcamoid, webcam capture application. -# Copyright (C) 2017 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -import os -import sys -import platform -import shutil - -import tools.utils - -class DeployBase(tools.utils.DeployToolsUtils): - def __init__(self): - super().__init__() - self.rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')) - self.buildDir = os.environ['BUILD_PATH'] if 'BUILD_PATH' in os.environ else self.rootDir - self.installDir = os.path.join(self.rootDir, 'ports/deploy/temp_priv/root') - self.rootInstallDir = '' - self.pkgsDir = os.path.join(self.rootDir, - 'ports/deploy/packages_auto', - sys.platform if os.name == 'posix' else os.name) - self.programVersion = '' - self.qmake = '' - - def __str__(self): - deployInfo = 'Python version: {}\n' \ - 'Root directory: {}\n' \ - 'Build directory: {}\n' \ - 'Install directory: {}\n' \ - 'Packages directory: {}\n' \ - 'System: {}\n' \ - 'Architecture: {}\n' \ - 'Target system: {}\n' \ - 'Target architecture: {}\n' \ - 'Number of threads: {}\n' \ - 'Program version: {}\n' \ - 'Make executable: {}\n' \ - 'Qmake executable: {}'. \ - format(platform.python_version(), - self.rootDir, - self.buildDir, - self.installDir, - self.pkgsDir, - self.system, - self.arch, - self.targetSystem, - self.targetArch, - self.njobs, - self.programVersion, - self.make, - self.qmake) - - return deployInfo - - def run(self): - print('Deploy info\n') - print(self) - print('\nPreparing for software packaging\n') - self.prepare() - print('\nPackaged data info\n') - self.printPackageDataInfo() - print('\nCreating packages\n') - self.package() - print('\nCleaning up') - self.cleanup() - print('Deploy finnished\n') - - def printPackageDataInfo(self): - packagedFiles = [] - - for root, _, files in os.walk(self.rootInstallDir): - for f in files: - packagedFiles.append(os.path.join(root, f)) - - packagedFiles = sorted(packagedFiles) - - for f in packagedFiles: - print(' ' + f) - - def prepare(self): - pass - - def package(self): - pass - - def cleanup(self): - shutil.rmtree(self.installDir, True) diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/deploy_mac.py webcamoid-8.8.0+dfsg/ports/deploy/deploy_mac.py --- webcamoid-8.6.1+dfsg/ports/deploy/deploy_mac.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/deploy_mac.py 2021-02-15 15:25:23.000000000 +0000 @@ -28,14 +28,16 @@ import threading import time -import deploy_base -import tools.binary_mach -import tools.qt5 +from WebcamoidDeployTools import DTDeployBase +from WebcamoidDeployTools import DTQt5 +from WebcamoidDeployTools import DTBinaryMach -class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt): +class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools): def __init__(self): super().__init__() + rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')) + self.setRootDir(rootDir) self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv') self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto', self.targetSystem) self.detectQt(os.path.join(self.buildDir, 'StandAlone')) @@ -52,8 +54,13 @@ self.mainBinary = os.path.join(self.binaryInstallDir, self.programName) self.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri')) self.detectMake() - self.binarySolver = tools.binary_mach.DeployToolsBinary() - self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/exclude.{}.{}.txt'.format(os.name, sys.platform))) + xspec = self.qmakeQuery(var='QMAKE_XSPEC') + + if 'android' in xspec: + self.targetSystem = 'android' + + self.binarySolver = DTBinaryMach.MachBinaryTools() + self.binarySolver.readExcludes(os.name, sys.platform) self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf') self.dependencies = [] self.installerConfig = os.path.join(self.installDir, 'installer/config') @@ -70,8 +77,10 @@ def prepare(self): print('Executing make install') - self.makeInstall(self.buildDir, self.installDir) + params = {'INSTALL_ROOT': self.installDir} + self.makeInstall(self.buildDir, params) self.detectTargetArch() + print('Copying Qml modules\n') self.solvedepsQml() print('\nCopying required plugins\n') @@ -91,15 +100,19 @@ self.fixRpaths() print('\nWritting build system information\n') self.writeBuildInfo() + print('\nSigning bundle\n') + self.signPackage(self.appBundleDir) def solvedepsLibs(self): deps = sorted(self.binarySolver.scanDependencies(self.installDir)) for dep in deps: depPath = os.path.join(self.libInstallDir, os.path.basename(dep)) - print(' {} -> {}'.format(dep, depPath)) - self.copy(dep, depPath, not dep.endswith('.framework')) - self.dependencies.append(dep) + + if dep != depPath: + print(' {} -> {}'.format(dep, depPath)) + self.copy(dep, depPath, not dep.endswith('.framework')) + self.dependencies.append(dep) @staticmethod def removeUnneededFiles(path): @@ -223,21 +236,6 @@ return ' '.join(path.replace(cellarPath + os.sep, '').split(os.sep)[0: 2]) - def commitHash(self): - try: - process = subprocess.Popen(['git', 'rev-parse', 'HEAD'], # nosec - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=self.rootDir) - stdout, _ = process.communicate() - - if process.returncode != 0: - return '' - - return stdout.decode(sys.getdefaultencoding()).strip() - except: - return '' - @staticmethod def sysInfo(): process = subprocess.Popen(['sw_vers'], # nosec @@ -255,7 +253,7 @@ # Write repository info. with open(depsInfoFile, 'w') as f: - commitHash = self.commitHash() + commitHash = self.gitCommitHash(self.rootDir) if len(commitHash) < 1: commitHash = 'Unknown' @@ -357,6 +355,16 @@ return size + def signPackage(self, package): + process = subprocess.Popen(['codesign', # nosec + '--force', + '--sign', + '-', + package], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + process.communicate() + # https://asmaloney.com/2013/07/howto/packaging-a-mac-os-x-application-using-a-dmg/ def createPortable(self, mutex): staggingDir = os.path.join(self.installDir, 'stagging') @@ -474,8 +482,15 @@ def package(self): mutex = threading.Lock() - threads = [threading.Thread(target=self.createPortable, args=(mutex,)), - threading.Thread(target=self.createAppInstaller, args=(mutex,))] + threads = [threading.Thread(target=self.createPortable, args=(mutex,))] + packagingTools = ['dmg'] + + if self.qtIFW != '': + threads.append(threading.Thread(target=self.createAppInstaller, args=(mutex,))) + packagingTools += ['Qt Installer Framework'] + + if len(packagingTools) > 0: + print('Detected packaging tools: {}\n'.format(', '.join(packagingTools))) for thread in threads: thread.start() diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/deploy_posix.py webcamoid-8.8.0+dfsg/ports/deploy/deploy_posix.py --- webcamoid-8.6.1+dfsg/ports/deploy/deploy_posix.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/deploy_posix.py 2021-02-15 15:25:23.000000000 +0000 @@ -28,14 +28,16 @@ import tarfile import threading -import deploy_base -import tools.binary_elf -import tools.qt5 +from WebcamoidDeployTools import DTDeployBase +from WebcamoidDeployTools import DTQt5 +from WebcamoidDeployTools import DTBinaryElf -class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt): +class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools): def __init__(self): super().__init__() + rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')) + self.setRootDir(rootDir) self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv') self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto', sys.platform) self.detectQt(os.path.join(self.buildDir, 'StandAlone')) @@ -59,9 +61,15 @@ self.programName = os.path.basename(self.mainBinary) self.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri')) self.detectMake() - self.targetSystem = 'posix_windows' if 'win32' in self.qmakeQuery(var='QMAKE_XSPEC') else 'posix' - self.binarySolver = tools.binary_elf.DeployToolsBinary() - self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/exclude.{}.{}.txt'.format(os.name, sys.platform))) + xspec = self.qmakeQuery(var='QMAKE_XSPEC') + + if 'win32' in xspec: + self.targetSystem = 'posix_windows' + elif 'android' in xspec: + self.targetSystem = 'android' + + self.binarySolver = DTBinaryElf.ElfBinaryTools() + self.binarySolver.readExcludes(os.name, sys.platform) self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf') self.dependencies = [] self.installerConfig = os.path.join(self.installDir, 'installer/config') @@ -100,13 +108,16 @@ for dep in deps: depPath = os.path.join(self.libInstallDir, os.path.basename(dep)) - print(' {} -> {}'.format(dep, depPath)) - self.copy(dep, depPath, True) - self.dependencies.append(dep) + + if dep != depPath: + print(' {} -> {}'.format(dep, depPath)) + self.copy(dep, depPath, True) + self.dependencies.append(dep) def prepare(self): print('Executing make install') - self.makeInstall(self.buildDir, self.installDir) + params = {'INSTALL_ROOT': self.installDir} + self.makeInstall(self.buildDir, params) self.detectTargetArch() self.appImage = self.detectAppImage() print('Copying Qml modules\n') @@ -206,21 +217,6 @@ return '' - def commitHash(self): - try: - process = subprocess.Popen(['git', 'rev-parse', 'HEAD'], # nosec - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=self.rootDir) - stdout, _ = process.communicate() - - if process.returncode != 0: - return '' - - return stdout.decode(sys.getdefaultencoding()).strip() - except: - return '' - @staticmethod def sysInfo(): info = '' @@ -237,6 +233,12 @@ def writeBuildInfo(self): shareDir = os.path.join(self.rootInstallDir, 'share') + + try: + os.makedirs(self.pkgsDir) + except: + pass + depsInfoFile = os.path.join(shareDir, 'build-info.txt') if not os.path.exists(shareDir): @@ -245,7 +247,7 @@ # Write repository info. with open(depsInfoFile, 'w') as f: - commitHash = self.commitHash() + commitHash = self.gitCommitHash(self.rootDir) if len(commitHash) < 1: commitHash = 'Unknown' @@ -463,12 +465,18 @@ mutex = threading.Lock() threads = [threading.Thread(target=self.createPortable, args=(mutex,))] + packagingTools = ['tar.xz'] if self.qtIFW != '': threads.append(threading.Thread(target=self.createAppInstaller, args=(mutex,))) + packagingTools += ['Qt Installer Framework'] if self.appImage != '': threads.append(threading.Thread(target=self.createAppImage, args=(mutex,))) + packagingTools += ['AppImage'] + + if len(packagingTools) > 0: + print('Detected packaging tools: {}\n'.format(', '.join(packagingTools))) for thread in threads: thread.start() diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/deploy_posix_windows.py webcamoid-8.8.0+dfsg/ports/deploy/deploy_posix_windows.py --- webcamoid-8.6.1+dfsg/ports/deploy/deploy_posix_windows.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/deploy_posix_windows.py 2021-02-15 15:25:23.000000000 +0000 @@ -26,14 +26,16 @@ import threading import zipfile -import deploy_base -import tools.binary_pecoff -import tools.qt5 +from WebcamoidDeployTools import DTDeployBase +from WebcamoidDeployTools import DTQt5 +from WebcamoidDeployTools import DTBinaryPecoff -class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt): +class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools): def __init__(self): super().__init__() + rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')) + self.setRootDir(rootDir) self.targetSystem = 'posix_windows' self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv') self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto/windows') @@ -59,8 +61,8 @@ self.programName = os.path.splitext(os.path.basename(self.mainBinary))[0] self.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri')) self.detectMake() - self.binarySolver = tools.binary_pecoff.DeployToolsBinary() - self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/exclude.{}.{}.txt'.format(os.name, sys.platform))) + self.binarySolver = DTBinaryPecoff.PecoffBinaryTools() + self.binarySolver.readExcludes(os.name, sys.platform) self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf') self.dependencies = [] self.installerConfig = os.path.join(self.installDir, 'installer/config') @@ -92,7 +94,8 @@ def prepare(self): print('Executing make install') - self.makeInstall(self.buildDir, self.installDir) + params = {'INSTALL_ROOT': self.installDir} + self.makeInstall(self.buildDir, params) if self.targetArch == '32bit': self.binarySolver.sysBinsPath = ['/usr/i686-w64-mingw32/bin'] @@ -158,9 +161,11 @@ for dep in deps: depPath = os.path.join(self.binaryInstallDir, os.path.basename(dep)) - print(' {} -> {}'.format(dep, depPath)) - self.copy(dep, depPath) - self.dependencies.append(dep) + + if dep != depPath: + print(' {} -> {}'.format(dep, depPath)) + self.copy(dep, depPath) + self.dependencies.append(dep) def removeDebugs(self): dbgFiles = set() @@ -243,21 +248,6 @@ return '' - def commitHash(self): - try: - process = subprocess.Popen(['git', 'rev-parse', 'HEAD'], # nosec - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=self.rootDir) - stdout, _ = process.communicate() - - if process.returncode != 0: - return '' - - return stdout.decode(sys.getdefaultencoding()).strip() - except: - return '' - @staticmethod def sysInfo(): info = '' @@ -282,7 +272,7 @@ # Write repository info. with open(depsInfoFile, 'w') as f: - commitHash = self.commitHash() + commitHash = self.gitCommitHash(self.rootDir) if len(commitHash) < 1: commitHash = 'Unknown' @@ -380,6 +370,9 @@ launcher.write('rem Default values: software | d3d12 | openvg\n') launcher.write('rem set QT_QUICK_BACKEND=""\n') launcher.write('\n') + launcher.write('rem Enable plugin debugging\n') + launcher.write('rem set QT_DEBUG_PLUGINS=1\n') + launcher.write('\n') launcher.write('start /b "" ' + '"%~dp0bin\\{}" '.format(self.programName) + '-p "%~dp0{}\\avkys" '.format(libDir) @@ -448,9 +441,14 @@ mutex = threading.Lock() threads = [threading.Thread(target=self.createPortable, args=(mutex,))] + packagingTools = ['zip'] if self.qtIFW != '': threads.append(threading.Thread(target=self.createAppInstaller, args=(mutex,))) + packagingTools += ['Qt Installer Framework'] + + if len(packagingTools) > 0: + print('Detected packaging tools: {}\n'.format(', '.join(packagingTools))) for thread in threads: thread.start() diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/deploy.py webcamoid-8.8.0+dfsg/ports/deploy/deploy.py --- webcamoid-8.6.1+dfsg/ports/deploy/deploy.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/deploy.py 2021-02-15 15:25:23.000000000 +0000 @@ -19,17 +19,17 @@ # # Web-Site: http://webcamoid.github.io/ -import tools.utils +from WebcamoidDeployTools import DTUtils if __name__ =='__main__': - system = tools.utils.DeployToolsUtils().system + system = DTUtils.Utils().system while True: try: deploy = __import__('deploy_' + system).Deploy() - except: - print('No valid deploy script found.') + except Exception as e: + print('No valid deploy script found: ', e) exit() diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/deploy_windows.py webcamoid-8.8.0+dfsg/ports/deploy/deploy_windows.py --- webcamoid-8.6.1+dfsg/ports/deploy/deploy_windows.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/deploy_windows.py 2021-02-15 15:25:23.000000000 +0000 @@ -27,14 +27,16 @@ import threading import zipfile -import deploy_base -import tools.binary_pecoff -import tools.qt5 +from WebcamoidDeployTools import DTDeployBase +from WebcamoidDeployTools import DTQt5 +from WebcamoidDeployTools import DTBinaryPecoff -class Deploy(deploy_base.DeployBase, tools.qt5.DeployToolsQt): +class Deploy(DTDeployBase.DeployBase, DTQt5.Qt5Tools): def __init__(self): super().__init__() + rootDir = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')) + self.setRootDir(rootDir) self.installDir = os.path.join(self.buildDir, 'ports/deploy/temp_priv') self.pkgsDir = os.path.join(self.buildDir, 'ports/deploy/packages_auto/windows') self.detectQt(os.path.join(self.buildDir, 'StandAlone')) @@ -58,8 +60,13 @@ self.programName = os.path.splitext(os.path.basename(self.mainBinary))[0] self.programVersion = self.detectVersion(os.path.join(self.rootDir, 'commons.pri')) self.detectMake() - self.binarySolver = tools.binary_pecoff.DeployToolsBinary() - self.binarySolver.readExcludeList(os.path.join(self.rootDir, 'ports/deploy/exclude.{}.{}.txt'.format(os.name, sys.platform))) + xspec = self.qmakeQuery(var='QMAKE_XSPEC') + + if 'android' in xspec: + self.targetSystem = 'android' + + self.binarySolver = DTBinaryPecoff.PecoffBinaryTools() + self.binarySolver.readExcludes(os.name, sys.platform) self.packageConfig = os.path.join(self.rootDir, 'ports/deploy/package_info.conf') self.dependencies = [] self.installerConfig = os.path.join(self.installDir, 'installer/config') @@ -136,9 +143,11 @@ dep = dep.replace('\\', '/') depPath = os.path.join(self.binaryInstallDir, os.path.basename(dep)) depPath = depPath.replace('\\', '/') - print(' {} -> {}'.format(dep, depPath)) - self.copy(dep, depPath) - self.dependencies.append(dep) + + if dep != depPath: + print(' {} -> {}'.format(dep, depPath)) + self.copy(dep, depPath) + self.dependencies.append(dep) def removeDebugs(self): dbgFiles = set() @@ -172,6 +181,9 @@ launcher.write('rem Default values: software | d3d12 | openvg\n') launcher.write('rem set QT_QUICK_BACKEND=""\n') launcher.write('\n') + launcher.write('rem Enable plugin debugging\n') + launcher.write('rem set QT_DEBUG_PLUGINS=1\n') + launcher.write('\n') launcher.write('start /b "" ' + '"%~dp0bin\\{}" '.format(self.programName) + '-p "%~dp0{}\\avkys" '.format(libDir) @@ -226,21 +238,6 @@ return '' - def commitHash(self): - try: - process = subprocess.Popen(['git', 'rev-parse', 'HEAD'], # nosec - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=self.rootDir) - stdout, _ = process.communicate() - - if process.returncode != 0: - return '' - - return stdout.decode(sys.getdefaultencoding()).strip() - except: - return '' - @staticmethod def sysInfo(): try: @@ -269,7 +266,7 @@ # Write repository info. with open(depsInfoFile, 'w') as f: - commitHash = self.commitHash() + commitHash = self.gitCommitHash(self.rootDir) if len(commitHash) < 1: commitHash = 'Unknown' @@ -372,9 +369,14 @@ mutex = threading.Lock() threads = [threading.Thread(target=self.createPortable, args=(mutex,))] + packagingTools = ['zip'] if self.qtIFW != '': threads.append(threading.Thread(target=self.createAppInstaller, args=(mutex,))) + packagingTools += ['Qt Installer Framework'] + + if len(packagingTools) > 0: + print('Detected packaging tools: {}\n'.format(', '.join(packagingTools))) for thread in threads: thread.start() diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/exclude.nt.win32.txt webcamoid-8.8.0+dfsg/ports/deploy/exclude.nt.win32.txt --- webcamoid-8.6.1+dfsg/ports/deploy/exclude.nt.win32.txt 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/exclude.nt.win32.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -C:/Windows/System32/.* -C:/Program Files/.* diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/exclude.posix.darwin.txt webcamoid-8.8.0+dfsg/ports/deploy/exclude.posix.darwin.txt --- webcamoid-8.6.1+dfsg/ports/deploy/exclude.posix.darwin.txt 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/exclude.posix.darwin.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -/usr/lib/.* -/System/Library/Frameworks/.* diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/exclude.posix.freebsd12.txt webcamoid-8.8.0+dfsg/ports/deploy/exclude.posix.freebsd12.txt --- webcamoid-8.6.1+dfsg/ports/deploy/exclude.posix.freebsd12.txt 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/exclude.posix.freebsd12.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -# VDSO -(.*/)*ld-linux.so.2 -(.*/)*ld-linux-x86-64.so.2 - -# Glibc -(.*/)*libc.so.[0-9]+ -(.*/)*libdl.so.[0-9]+ -(.*/)*libm.so.[0-9]+ -(.*/)*libmvec.so.[0-9]+ -(.*/)*libpthread.so.[0-9]+ -(.*/)*libresolv.so.[0-9]+ -(.*/)*librt.so.[0-9]+ - -# GCC -(.*/)*libgcc_s.so.[0-9]+ -(.*/)*libgomp.so.[0-9]+ -(.*/)*libstdc\+\+.so.[0-9]+ - -# Core libraries -(.*/)*libSM.so.6 -(.*/)*libblkid.so.1 -(.*/)*libcap.so.2 -(.*/)*libcom_err.so.2 -(.*/)*libcrypto.so.1.0.0 -(.*/)*libdb-5.3.so -(.*/)*libdbus-1.so.3 -(.*/)*libexpat.so.1 -(.*/)*libfontconfig.so.1 -(.*/)*libfreetype.so.6 -(.*/)*libgcrypt.so.20 -(.*/)*libgmp.so.10 -(.*/)*libgpg-error.so.0 -(.*/)*libgssapi_krb5.so.2 -(.*/)*libharfbuzz.so.0 -(.*/)*libk5crypto.so.3 -(.*/)*libkeyutils.so.1 -(.*/)*libkrb5.so.3 -(.*/)*libkrb5support.so.0 -(.*/)*liblz4.so.1 -(.*/)*liblzma.so.5 -(.*/)*libmount.so.1 -(.*/)*libpcre.so.[0-9]+$ -(.*/)*libpcre16.so.0 -(.*/)*libssh2.so.1 -(.*/)*libssl.so.1.0.0 -(.*/)*libtasn1.so.6 -(.*/)*libusb-1.0.so.0 -(.*/)*libuuid.so.1 -(.*/)*libz.so.1 - -# Glib2 -(.*/)*libgio-2.0.so.0 -(.*/)*libglib-2.0.so.0 -(.*/)*libgmodule-2.0.so.0 -(.*/)*libgobject-2.0.so.0 - -# X11 -(.*/)*libX11-xcb.so.[0-9]+ -(.*/)*libX11.so.[0-9]+ -(.*/)*libXau.so.[0-9]+ -(.*/)*libXcursor.so.[0-9]+ -(.*/)*libXdamage.so.[0-9]+ -(.*/)*libXdmcp.so.[0-9]+ -(.*/)*libXext.so.[0-9]+ -(.*/)*libXfixes.so.[0-9]+ -(.*/)*libXi.so.[0-9]+ -(.*/)*libXinerama.so.[0-9]+ -(.*/)*libXrandr.so.[0-9]+ -(.*/)*libXrender.so.[0-9]+ -(.*/)*libXss.so.[0-9]+ -(.*/)*libXv.so.[0-9]+ -(.*/)*libXxf86vm.so.[0-9]+ -(.*/)*libglapi.so.[0-9]+ -(.*/)*libp11-kit.so.[0-9]+ -(.*/)*libxcb-dri2.so.[0-9]+ -(.*/)*libxcb-dri3.so.[0-9]+ -(.*/)*libxcb-glx.so.[0-9]+ -(.*/)*libxcb-icccm.so.[0-9]+ -(.*/)*libxcb-image.so.[0-9]+ -(.*/)*libxcb-keysyms.so.[0-9]+ -(.*/)*libxcb-present.so.[0-9]+ -(.*/)*libxcb-randr.so.[0-9]+ -(.*/)*libxcb-render-util.so.[0-9]+ -(.*/)*libxcb-render.so.[0-9]+ -(.*/)*libxcb-shape.so.[0-9]+ -(.*/)*libxcb-shm.so.[0-9]+ -(.*/)*libxcb-sync.so.[0-9]+ -(.*/)*libxcb-util.so.[0-9]+ -(.*/)*libxcb-xfixes.so.[0-9]+ -(.*/)*libxcb-xinerama.so.[0-9]+ -(.*/)*libxcb-xkb.so.[0-9]+ -(.*/)*libxcb.so.[0-9]+ -(.*/)*libxkbcommon-x11.so.[0-9]+ -(.*/)*libxkbcommon.so.[0-9]+ -(.*/)*libxshmfence.so.[0-9]+ - -# OpenGL -(.*/)*libdrm.so.2 -(.*/)*libgbm.so.1 -(.*/)*libEGL.so.1 -(.*/)*libGL.so.1 -(.*/)*libGLX.so.0 -(.*/)*libGLdispatch.so.0 - -# Use system library instead -(.*/)*libasound.so.2 -(.*/)*libpulse.so.0 -(.*/)*libpulse-simple.so.0 -(.*/)*libjack.so.0 -(.*/)*libv4l2.so.0 diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/exclude.posix.linux.txt webcamoid-8.8.0+dfsg/ports/deploy/exclude.posix.linux.txt --- webcamoid-8.6.1+dfsg/ports/deploy/exclude.posix.linux.txt 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/exclude.posix.linux.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -# VDSO -(.*/)*ld-linux.so.2 -(.*/)*ld-linux-x86-64.so.2 - -# Glibc -(.*/)*libc.so.[0-9]+ -(.*/)*libdl.so.[0-9]+ -(.*/)*libm.so.[0-9]+ -(.*/)*libmvec.so.[0-9]+ -(.*/)*libpthread.so.[0-9]+ -(.*/)*libresolv.so.[0-9]+ -(.*/)*librt.so.[0-9]+ - -# GCC -(.*/)*libgcc_s.so.[0-9]+ -(.*/)*libgomp.so.[0-9]+ -(.*/)*libstdc\+\+.so.[0-9]+ - -# Core libraries -(.*/)*libSM.so.6 -(.*/)*libblkid.so.1 -(.*/)*libcap.so.2 -(.*/)*libcom_err.so.2 -(.*/)*libcrypto.so.1.0.0 -(.*/)*libdb-5.3.so -(.*/)*libdbus-1.so.3 -(.*/)*libexpat.so.1 -(.*/)*libfontconfig.so.1 -(.*/)*libfreetype.so.6 -(.*/)*libgcrypt.so.20 -(.*/)*libgmp.so.10 -(.*/)*libgpg-error.so.0 -(.*/)*libgssapi_krb5.so.2 -(.*/)*libharfbuzz.so.0 -(.*/)*libk5crypto.so.3 -(.*/)*libkeyutils.so.1 -(.*/)*libkrb5.so.3 -(.*/)*libkrb5support.so.0 -(.*/)*liblz4.so.1 -(.*/)*liblzma.so.5 -(.*/)*libmount.so.1 -(.*/)*libpcre.so.[0-9]+$ -(.*/)*libpcre16.so.0 -(.*/)*libssh2.so.1 -(.*/)*libssl.so.1.0.0 -(.*/)*libtasn1.so.6 -(.*/)*libusb-1.0.so.0 -(.*/)*libuuid.so.1 -(.*/)*libz.so.1 - -# Glib2 -(.*/)*libgio-2.0.so.0 -(.*/)*libglib-2.0.so.0 -(.*/)*libgmodule-2.0.so.0 -(.*/)*libgobject-2.0.so.0 - -# X11 -(.*/)*libX11-xcb.so.[0-9]+ -(.*/)*libX11.so.[0-9]+ -(.*/)*libXau.so.[0-9]+ -(.*/)*libXcursor.so.[0-9]+ -(.*/)*libXdamage.so.[0-9]+ -(.*/)*libXdmcp.so.[0-9]+ -(.*/)*libXext.so.[0-9]+ -(.*/)*libXfixes.so.[0-9]+ -(.*/)*libXi.so.[0-9]+ -(.*/)*libXinerama.so.[0-9]+ -(.*/)*libXrandr.so.[0-9]+ -(.*/)*libXrender.so.[0-9]+ -(.*/)*libXss.so.[0-9]+ -(.*/)*libXv.so.[0-9]+ -(.*/)*libXxf86vm.so.[0-9]+ -(.*/)*libglapi.so.[0-9]+ -(.*/)*libp11-kit.so.[0-9]+ -(.*/)*libxcb-dri2.so.[0-9]+ -(.*/)*libxcb-dri3.so.[0-9]+ -(.*/)*libxcb-glx.so.[0-9]+ -(.*/)*libxcb-icccm.so.[0-9]+ -(.*/)*libxcb-image.so.[0-9]+ -(.*/)*libxcb-keysyms.so.[0-9]+ -(.*/)*libxcb-present.so.[0-9]+ -(.*/)*libxcb-randr.so.[0-9]+ -(.*/)*libxcb-render-util.so.[0-9]+ -(.*/)*libxcb-render.so.[0-9]+ -(.*/)*libxcb-shape.so.[0-9]+ -(.*/)*libxcb-shm.so.[0-9]+ -(.*/)*libxcb-sync.so.[0-9]+ -(.*/)*libxcb-util.so.[0-9]+ -(.*/)*libxcb-xfixes.so.[0-9]+ -(.*/)*libxcb-xinerama.so.[0-9]+ -(.*/)*libxcb-xkb.so.[0-9]+ -(.*/)*libxcb.so.[0-9]+ -(.*/)*libxkbcommon-x11.so.[0-9]+ -(.*/)*libxkbcommon.so.[0-9]+ -(.*/)*libxshmfence.so.[0-9]+ - -# OpenGL -(.*/)*libdrm.so.2 -(.*/)*libgbm.so.1 -(.*/)*libEGL.so.1 -(.*/)*libGL.so.1 -(.*/)*libGLX.so.0 -(.*/)*libGLdispatch.so.0 - -# Use system library instead -(.*/)*libasound.so.2 -(.*/)*libpulse.so.0 -(.*/)*libpulse-simple.so.0 -(.*/)*libjack.so.0 -(.*/)*libv4l2.so.0 diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/installscript.windows.qs webcamoid-8.8.0+dfsg/ports/deploy/installscript.windows.qs --- webcamoid-8.6.1+dfsg/ports/deploy/installscript.windows.qs 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/installscript.windows.qs 2021-02-15 15:25:23.000000000 +0000 @@ -17,5 +17,5 @@ for (var dir in installDir) component.addOperation("CreateShortcut", "@TargetDir@/bin/webcamoid.exe", - installDir[dir] + "/webcamoid.lnk"); + installDir[dir] + "/Webcamoid.lnk"); } diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/package_info.conf webcamoid-8.8.0+dfsg/ports/deploy/package_info.conf --- webcamoid-8.6.1+dfsg/ports/deploy/package_info.conf 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/package_info.conf 2021-02-15 15:25:23.000000000 +0000 @@ -2,6 +2,5 @@ appName = Webcamoid description = Webcamoid, The ultimate webcam suite! url = https://webcamoid.github.io/ -titleColor = #3F1F7F runMessage = Launch Webcamoid now! licenseDescription = GNU General Public License v3.0 diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/tools/binary_elf.py webcamoid-8.8.0+dfsg/ports/deploy/tools/binary_elf.py --- webcamoid-8.6.1+dfsg/ports/deploy/tools/binary_elf.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/tools/binary_elf.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,317 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Webcamoid, webcam capture application. -# Copyright (C) 2017 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -import fnmatch -import os -import struct -import sys - -import tools.binary - - -class DeployToolsBinary(tools.binary.DeployToolsBinary): - def __init__(self): - super().__init__() - self.ldLibraryPath = os.environ['LD_LIBRARY_PATH'].split(':') if 'LD_LIBRARY_PATH' in os.environ else [] - self.libsSeachPaths = self.readLdconf() \ - + ['/usr/lib', - '/usr/lib64', - '/lib', - '/lib64', - '/usr/local/lib', - '/usr/local/lib64'] - - def readLdconf(self, ldconf='/etc/ld.so.conf'): - if not os.path.exists(ldconf): - return [] - - confDir = os.path.dirname(ldconf) - libpaths = [] - - with open(ldconf) as f: - for line in f: - i = line.find('#') - - if i == 0: - continue - - if i >= 0: - line = line[: i] - - line = line.strip() - - if len(line) < 1: - continue - - if line.startswith('include'): - conf = line.split()[1] - - if not conf.startswith('/'): - conf = os.path.join(confDir, conf) - - dirname = os.path.dirname(conf) - - if os.path.exists(dirname): - for f in os.listdir(dirname): - path = os.path.join(dirname, f) - - if fnmatch.fnmatch(path, conf): - libpaths += self.readLdconf(path) - else: - libpaths.append(line) - - return libpaths - - def isValid(self, path): - with open(path, 'rb') as f: - return f.read(4) == b'\x7fELF' - - @staticmethod - def readString(f): - s = b'' - - while True: - c = f.read(1) - - if c == b'\x00': - break - - s += c - - return s - - @staticmethod - def readNumber(f, arch): - if arch == '32bits': - return struct.unpack('I', f.read(4))[0] - - return struct.unpack('Q', f.read(8))[0] - - @staticmethod - def readDynamicEntry(f, arch): - if arch == '32bits': - return struct.unpack('iI', f.read(8)) - - return struct.unpack('qQ', f.read(16)) - - # https://refspecs.linuxfoundation.org/lsb.shtml (See Core, Generic) - # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format - def dump(self, binary): - # ELF file magic - ELFMAGIC = b'\x7fELF' - - # Sections - SHT_STRTAB = 0x3 - SHT_DYNAMIC = 0x6 - - # Dynamic section entries - DT_NULL = 0 - DT_NEEDED = 1 - DT_RPATH = 15 - DT_RUNPATH = 0x1d - - with open(binary, 'rb') as f: - # Read magic signature. - magic = f.read(4) - - if magic != ELFMAGIC: - return {} - - # Read the data structure of the file. - eiClass = '32bits' if struct.unpack('B', f.read(1))[0] == 1 else '64bits' - - # Read machine code. - f.seek(0x12, os.SEEK_SET) - machine = struct.unpack('H', f.read(2))[0] - - # Get a pointer to the sections table. - sectionHeaderTable = 0 - - if eiClass == '32bits': - f.seek(0x20, os.SEEK_SET) - sectionHeaderTable = self.readNumber(f, eiClass) - f.seek(0x30, os.SEEK_SET) - else: - f.seek(0x28, os.SEEK_SET) - sectionHeaderTable = self.readNumber(f, eiClass) - f.seek(0x3c, os.SEEK_SET) - - # Read the number of sections. - nSections = struct.unpack('H', f.read(2))[0] - - # Read the index of the string table that stores sections names. - shstrtabIndex = struct.unpack('H', f.read(2))[0] - - # Read sections. - f.seek(sectionHeaderTable, os.SEEK_SET) - neededPtr = [] - rpathsPtr = [] - runpathsPtr = [] - strtabs = [] - shstrtab = [] - - for section in range(nSections): - sectionStart = f.tell() - - # Read the a pointer to the virtual address in the string table - # that contains the name of this section. - sectionName = struct.unpack('I', f.read(4))[0] - - # Read the type of this section. - sectionType = struct.unpack('I', f.read(4))[0] - - # Read the virtual address of this section. - f.seek(sectionStart + (0x0c if eiClass == '32bits' else 0x10), os.SEEK_SET) - shAddr = self.readNumber(f, eiClass) - - # Read the offset in file to this section. - shOffset = self.readNumber(f, eiClass) - f.seek(shOffset, os.SEEK_SET) - - if sectionType == SHT_DYNAMIC: - # Read dynamic sections. - while True: - # Read dynamic entries. - dTag, dVal = self.readDynamicEntry(f, eiClass) - - if dTag == DT_NULL: - # End of dynamic sections. - break - elif dTag == DT_NEEDED: - # Dynamically imported libraries. - neededPtr.append(dVal) - elif dTag == DT_RPATH: - # RPATHs. - rpathsPtr.append(dVal) - elif dTag == DT_RUNPATH: - # RUNPATHs. - runpathsPtr.append(dVal) - elif sectionType == SHT_STRTAB: - # Read string tables. - if section == shstrtabIndex: - # We found the string table that stores sections names. - shstrtab = [shAddr, shOffset] - else: - # Save string tables for later usage. - strtabs += [[sectionName, shAddr, shOffset]] - - # Move to next section. - f.seek(sectionStart + (0x28 if eiClass == '32bits' else 0x40), os.SEEK_SET) - - # Libraries names and RUNPATHs are located in '.dynstr' table. - strtab = [] - - for tab in strtabs: - f.seek(tab[0] - shstrtab[0] + shstrtab[1], os.SEEK_SET) - - if self.readString(f) == b'.dynstr': - strtab = tab - - # Read dynamically imported libraries. - needed = set() - - for lib in neededPtr: - f.seek(lib + strtab[2], os.SEEK_SET) - needed.add(self.readString(f).decode(sys.getdefaultencoding())) - - # Read RPATHs - rpaths = set() - - for path in rpathsPtr: - f.seek(path + strtab[2], os.SEEK_SET) - rpaths.add(self.readString(f).decode(sys.getdefaultencoding())) - - # Read RUNPATHs - runpaths = set() - - for path in runpathsPtr: - f.seek(path + strtab[2], os.SEEK_SET) - runpaths.add(self.readString(f).decode(sys.getdefaultencoding())) - - return {'machine': machine, - 'imports': needed, - 'rpath': rpaths, - 'runpath': runpaths} - - return {} - - @staticmethod - def readRpaths(elfInfo, binDir): - rpaths = [] - runpaths = [] - - # http://amir.rachum.com/blog/2016/09/17/shared-libraries/ - for rpath in ['rpath', 'runpath']: - for path in elfInfo[rpath]: - if '$ORIGIN' in path: - path = path.replace('$ORIGIN', binDir) - - if not path.startswith('/'): - path = os.path.join(binDir, path) - - path = os.path.normpath(path) - - if rpath == 'rpath': - rpaths.append(path) - else: - runpaths.append(path) - - return rpaths, runpaths - - def libPath(self, lib, machine, rpaths, runpaths): - # man ld.so - searchPaths = rpaths \ - + self.ldLibraryPath \ - + runpaths \ - + self.libsSeachPaths - - for libdir in searchPaths: - path = os.path.join(libdir, lib) - - if os.path.exists(path): - depElfInfo = self.dump(path) - - if depElfInfo and depElfInfo['machine'] == machine: - return path - - return '' - - def dependencies(self, binary): - elfInfo = self.dump(binary) - - if not elfInfo: - return [] - - rpaths, runpaths = self.readRpaths(elfInfo, os.path.dirname(binary)) - libs = [] - - for lib in elfInfo['imports']: - libpath = self.libPath(lib, elfInfo['machine'], rpaths, runpaths) - - if len(libpath) > 0 and not self.isExcluded(libpath): - libs.append(libpath) - - return libs - - def name(self, binary): - dep = os.path.basename(binary)[3:] - - return dep[: dep.find('.')] diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/tools/binary_mach.py webcamoid-8.8.0+dfsg/ports/deploy/tools/binary_mach.py --- webcamoid-8.6.1+dfsg/ports/deploy/tools/binary_mach.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/tools/binary_mach.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Webcamoid, webcam capture application. -# Copyright (C) 2017 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -import os -import struct -import sys - -import tools.binary - - -class DeployToolsBinary(tools.binary.DeployToolsBinary): - def __init__(self): - super().__init__() - - # 32 bits magic number. - self.MH_MAGIC = 0xfeedface # Native endian - self.MH_CIGAM = 0xcefaedfe # Reverse endian - - # 64 bits magic number. - self.MH_MAGIC_64 = 0xfeedfacf # Native endian - self.MH_CIGAM_64 = 0xcffaedfe # Reverse endian - - def isValid(self, path): - try: - with open(path, 'rb') as f: - # Read magic number. - magic = struct.unpack('I', f.read(4))[0] - - if magic == self.MH_MAGIC \ - or magic == self.MH_CIGAM \ - or magic == self.MH_MAGIC_64 \ - or magic == self.MH_CIGAM_64: - return True - except: - pass - - return False - - # https://github.com/aidansteele/osx-abi-macho-file-format-reference - def dump(self, binary): - # Commands definitions - LC_REQ_DYLD = 0x80000000 - LC_LOAD_DYLIB = 0xc - LC_RPATH = 0x1c | LC_REQ_DYLD - LC_ID_DYLIB = 0xd - - dylibImports = [] - rpaths = [] - dylibId = '' - - with open(binary, 'rb') as f: - # Read magic number. - magic = struct.unpack('I', f.read(4))[0] - - if magic == self.MH_MAGIC or magic == self.MH_CIGAM: - is32bits = True - elif magic == self.MH_MAGIC_64 or magic == self.MH_CIGAM_64: - is32bits = False - else: - return {} - - # Read number of commands. - f.seek(12, os.SEEK_CUR) - ncmds = struct.unpack('I', f.read(4))[0] - - # Move to load commands - f.seek(8 if is32bits else 12, os.SEEK_CUR) - - for _ in range(ncmds): - # Read a load command and store it's position in the file. - loadCommandStart = f.tell() - loadCommand = struct.unpack('II', f.read(8)) - - # If the command list a library - if loadCommand[0] in [LC_LOAD_DYLIB, LC_RPATH, LC_ID_DYLIB]: - # Save the position of the next command. - nextCommand = f.tell() + loadCommand[1] - 8 - - # Move to the string - f.seek(loadCommandStart + struct.unpack('I', f.read(4))[0], os.SEEK_SET) - dylib = b'' - - # Read string until null character. - while True: - c = f.read(1) - - if c == b'\x00': - break - - dylib += c - s = dylib.decode(sys.getdefaultencoding()) - - if loadCommand[0] == LC_LOAD_DYLIB: - dylibImports.append(s) - elif loadCommand[0] == LC_RPATH: - rpaths.append(s) - elif loadCommand[0] == LC_ID_DYLIB: - dylibId = s - - f.seek(nextCommand, os.SEEK_SET) - else: - f.seek(loadCommand[1] - 8, os.SEEK_CUR) - - return {'imports': dylibImports, 'rpaths': rpaths, 'id': dylibId} - - @staticmethod - def solveRefpath(path): - if not path.startswith('@'): - return path - - searchPaths = [] - - if 'DYLD_LIBRARY_PATH' in os.environ: - searchPaths += os.environ['DYLD_LIBRARY_PATH'].split(':') - - if 'DYLD_FRAMEWORK_PATH' in os.environ: - searchPaths += os.environ['DYLD_FRAMEWORK_PATH'].split(':') - - if path.endswith('.dylib'): - dep = os.path.basename(path) - else: - i = path.rfind(os.sep, 0, path.rfind('.framework')) - dep = path[i + 1:] - - for fpath in searchPaths: - realPath = os.path.join(fpath, dep) - - if os.path.exists(realPath): - return realPath - - return '' - - def dependencies(self, binary): - machInfo = self.dump(binary) - - if not machInfo: - return [] - - libs = [] - - for mach in machInfo['imports']: - mach = self.solveRefpath(mach) - - if mach == '' or self.isExcluded(mach) or not os.path.exists(mach): - continue - - dirName = os.path.dirname(mach) - dirName = os.path.realpath(dirName) - baseName = os.path.basename(mach) - libs.append(os.path.join(dirName, baseName)) - - return libs - - def name(self, binary): - dep = os.path.basename(binary) - i = dep.find('.') - - if i >= 0: - dep = dep[: dep.find('.')] - - if 'Qt' in dep and not 'Qt5' in dep: - dep = dep.replace('Qt', 'Qt5') - - return dep diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/tools/binary_pecoff.py webcamoid-8.8.0+dfsg/ports/deploy/tools/binary_pecoff.py --- webcamoid-8.6.1+dfsg/ports/deploy/tools/binary_pecoff.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/tools/binary_pecoff.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,179 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Webcamoid, webcam capture application. -# Copyright (C) 2017 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -import mimetypes -import os -import struct -import sys - -import tools.binary - - -class DeployToolsBinary(tools.binary.DeployToolsBinary): - def __init__(self): - super().__init__() - - def isValid(self, path): - mimetype, _ = mimetypes.guess_type(path) - - if mimetype == 'application/x-msdownload': - return True - - if mimetype != 'application/octet-stream': - return False - - with open(path, 'rb') as f: - if f.read(2) != b'MZ': - return [] - - f.seek(0x3c, os.SEEK_SET) - peHeaderOffset = struct.unpack('I', f.read(4)) - f.seek(peHeaderOffset[0], os.SEEK_SET) - peSignatue = f.read(4) - - if peSignatue != b'PE\x00\x00': - return False - - return True - - # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680547(v=vs.85).aspx - # https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg - def dump(self, binary): - dllImports = set() - - if not os.path.exists(binary) or not os.path.isfile(binary): - return dllImports - - with open(binary, 'rb') as f: - # Check DOS header signature. - if f.read(2) != b'MZ': - return [] - - # Move to COFF header. - f.seek(0x3c, os.SEEK_SET) - peHeaderOffset = struct.unpack('I', f.read(4)) - f.seek(peHeaderOffset[0], os.SEEK_SET) - peSignatue = f.read(4) - - # Check COFF header signature. - if peSignatue != b'PE\x00\x00': - return [] - - # Read COFF header. - coffHeader = struct.unpack('HHIIIHH', f.read(20)) - nSections = coffHeader[1] - sectionTablePos = coffHeader[5] + f.tell() - - # Read magic signature in standard COFF fields. - peType = 'PE32' if f.read(2) == b'\x0b\x01' else 'PE32+' - - # Move to data directories. - f.seek(102 if peType == 'PE32' else 118, os.SEEK_CUR) - - # Read the import table. - importTablePos, importTableSize = struct.unpack('II', f.read(8)) - - # Move to Sections table. - f.seek(sectionTablePos, os.SEEK_SET) - sections = [] - idataTablePhysical = -1 - - # Search for 'idata' section. - for _ in range(nSections): - # Read section. - section = struct.unpack('8pIIIIIIHHI', f.read(40)) - sectionName = section[0].replace(b'\x00', b'') - - # Save a reference to the sections. - sections += [section] - - if sectionName == b'idata' or sectionName == b'rdata': - idataTablePhysical = section[4] - - # If import table was defined calculate it's position in - # the file in relation to the address given by 'idata'. - if importTableSize > 0: - idataTablePhysical += importTablePos - section[2] - - if idataTablePhysical < 0: - return [] - - # Move to 'idata' section. - f.seek(idataTablePhysical, os.SEEK_SET) - dllList = set() - - # Read 'idata' directory table. - while True: - # Read DLL entries. - try: - dllImport = struct.unpack('IIIII', f.read(20)) - except: - break - - # Null directory entry. - if dllImport[0] | dllImport[1] | dllImport[2] | dllImport[3] | dllImport[4] == 0: - break - - # Locate where is located the DLL name in relation to the - # sections. - for section in sections: - if dllImport[3] >= section[2] \ - and dllImport[3] < section[1] + section[2]: - dllList.add(dllImport[3] - section[2] + section[4]) - - break - - for dll in dllList: - # Move to DLL name. - f.seek(dll, os.SEEK_SET) - dllName = b'' - - # Read string until null character. - while True: - c = f.read(1) - - if c == b'\x00': - break - - dllName += c - - try: - dllImports.add(dllName.decode(sys.getdefaultencoding())) - except: - pass - - return dllImports - - def dependencies(self, binary): - deps = [] - - for dep in self.dump(binary): - depPath = self.whereBin(dep) - - if len(depPath) > 0 and not self.isExcluded(depPath): - deps.append(depPath) - - return deps - - def name(self, binary): - dep = os.path.basename(binary) - - return dep[: dep.find('.')] diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/tools/binary.py webcamoid-8.8.0+dfsg/ports/deploy/tools/binary.py --- webcamoid-8.6.1+dfsg/ports/deploy/tools/binary.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/tools/binary.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Webcamoid, webcam capture application. -# Copyright (C) 2017 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -import os -import re -import subprocess # nosec -import threading -import time - -import tools - - -class DeployToolsBinary(tools.utils.DeployToolsUtils): - def __init__(self): - super().__init__() - self.detectStrip() - self.excludes = [] - - def isValid(self, path): - return False - - def find(self, path): - binaries = [] - - for root, _, files in os.walk(path): - for f in files: - binaryPath = os.path.join(root, f) - - if not os.path.islink(binaryPath) and self.isValid(binaryPath): - binaries.append(binaryPath) - - return binaries - - def dump(self, binary): - return {} - - def dependencies(self, binary): - return [] - - def allDependencies(self, binary): - deps = self.dependencies(binary) - solved = set() - - while len(deps) > 0: - dep = deps.pop() - - for binDep in self.dependencies(dep): - if binDep != dep and not binDep in solved: - deps.append(binDep) - - if self.system == 'mac': - i = dep.rfind('.framework/') - - if i >= 0: - dep = dep[: i] + '.framework' - - solved.add(dep) - - return solved - - def scanDependencies(self, path): - deps = set() - - for binPath in self.find(path): - for dep in self.allDependencies(binPath): - deps.add(dep) - - return sorted(deps) - - def name(self, binary): - return '' - - def detectStrip(self): - self.stripBin = self.whereBin('strip.exe' if self.system == 'windows' else 'strip') - - def strip(self, binary): - if self.stripBin == '': - return - - process = subprocess.Popen([self.stripBin, binary], # nosec - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - process.communicate() - - def stripSymbols(self, path): - threads = [] - - for binary in self.find(path): - thread = threading.Thread(target=self.strip, args=(binary,)) - threads.append(thread) - - while threading.active_count() >= self.njobs: - time.sleep(0.25) - - thread.start() - - for thread in threads: - thread.join() - - def readExcludeList(self, excludeList): - self.excludes = [] - - if os.path.exists(excludeList): - with open(excludeList) as f: - for line in f: - line = line.strip() - - if len(line) > 0 and line[0] != '#': - i = line.find('#') - - if i >= 0: - line = line[: i] - - line = line.strip() - - if len(line) > 0: - self.excludes.append(line) - - def isExcluded(self, path): - for exclude in self.excludes: - if self.targetSystem == 'windows' or self.targetSystem == 'posix_windows': - path = path.lower().replace('\\', '/') - exclude = exclude.lower() - - if re.fullmatch(exclude, path): - return True - - return False - - def resetFilePermissions(self, rootPath, binariesPath): - for root, dirs, files in os.walk(rootPath): - for d in dirs: - permissions = 0o755 - path = os.path.join(root, d) - - if self.system == 'mac': - os.chmod(path, permissions, follow_symlinks=False) - else: - os.chmod(path, permissions) - - for f in files: - permissions = 0o644 - path = os.path.join(root, f) - - if root == binariesPath and self.isValid(path): - permissions = 0o744 - - if self.system == 'mac': - os.chmod(path, permissions, follow_symlinks=False) - else: - os.chmod(path, permissions) diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/tools/qt5.py webcamoid-8.8.0+dfsg/ports/deploy/tools/qt5.py --- webcamoid-8.6.1+dfsg/ports/deploy/tools/qt5.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/tools/qt5.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,500 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Webcamoid, webcam capture application. -# Copyright (C) 2017 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -import configparser -import fnmatch -import os -import re -import subprocess # nosec -import sys -import time - -import tools.utils - -class DeployToolsQt(tools.utils.DeployToolsUtils): - def __init__(self): - super().__init__() - self.qmake = '' - self.qtIFW = '' - self.qtIFWVersion = '' - self.qtInstallBins = '' - self.qtInstallQml = '' - self.qtInstallPlugins = '' - self.qmlRootDirs = [] - self.qmlInstallDir = '' - self.dependencies = [] - self.binarySolver = None - self.installerConfig = '' - - @staticmethod - def detectMakeFiles(makePath): - makeFiles = [] - - try: - for f in os.listdir(makePath): - path = os.path.join(makePath, f) - - if os.path.isfile(path) and fnmatch.fnmatch(f.lower(), 'makefile*'): - makeFiles += [path] - except: - pass - - return makeFiles - - def detectQt(self, path=''): - self.detectQmake(path) - self.qtInstallBins = self.qmakeQuery(var='QT_INSTALL_BINS') - self.qtInstallQml = self.qmakeQuery(var='QT_INSTALL_QML') - self.qtInstallPlugins = self.qmakeQuery(var='QT_INSTALL_PLUGINS') - self.detectQtIFW() - self.detectQtIFWVersion() - - def detectQmake(self, path=''): - for makeFile in self.detectMakeFiles(path): - with open(makeFile) as f: - for line in f: - if line.startswith('QMAKE') and '=' in line: - self.qmake = line.split('=')[1].strip() - - return - - if 'QMAKE_PATH' in os.environ: - self.qmake = os.environ['QMAKE_PATH'] - - def qmakeQuery(self, qmake='', var=''): - if qmake == '': - if 'QMAKE_PATH' in os.environ: - qmake = os.environ['QMAKE_PATH'] - else: - qmake = self.qmake - - try: - args = [qmake, '-query'] - - if var != '': - args += [var] - - process = subprocess.Popen(args, # nosec - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, _ = process.communicate() - - return stdout.strip().decode(sys.getdefaultencoding()) - except: - pass - - return '' - - @staticmethod - def detectVersion(proFile): - if 'DAILY_BUILD' in os.environ: - return 'daily' - - verMaj = '0' - verMin = '0' - verPat = '0' - - try: - with open(proFile) as f: - for line in f: - if line.startswith('VER_MAJ') and '=' in line: - verMaj = line.split('=')[1].strip() - elif line.startswith('VER_MIN') and '=' in line: - verMin = line.split('=')[1].strip() - elif line.startswith('VER_PAT') and '=' in line: - verPat = line.split('=')[1].strip() - except: - pass - - return verMaj + '.' + verMin + '.' + verPat - - def detectQtIFW(self): - if 'BINARYCREATOR' in os.environ: - self.qtIFW = os.environ['BINARYCREATOR'] - - return - - # Try official Qt binarycreator first because it is statically linked. - - if self.targetSystem == 'windows': - homeQt = 'C:\\Qt' - elif self.targetSystem == 'posix_windows': - if 'WINEPREFIX' in os.environ: - homeQt = os.path.expanduser(os.path.join(os.environ['WINEPREFIX'], - 'drive_c/Qt')) - else: - homeQt = os.path.expanduser('~/.wine/drive_c/Qt') - else: - homeQt = os.path.expanduser('~/Qt') - - binCreator = 'binarycreator' - - if self.targetSystem == 'windows' or self.targetSystem == 'posix_windows': - binCreator += '.exe' - - for root, _, files in os.walk(homeQt): - for f in files: - if f == binCreator: - self.qtIFW = os.path.join(root, f) - - return - - # binarycreator offered by the system is most probably dynamically - # linked, so it's useful for test purposes only, but not recommended - # for distribution. - self.qtIFW = self.whereBin(binCreator) - - def detectQtIFWVersion(self): - self.qtIFWVersion = '' - - if self.qtIFW == '': - return - - installerBase = os.path.join(os.path.dirname(self.qtIFW), - 'installerbase') - - if self.targetSystem == 'windows' or self.targetSystem == 'posix_windows': - installerBase += '.exe' - - self.qtIFWVersion = '2.0.0' - - if not os.path.exists(installerBase): - return - - if self.targetSystem == 'posix_windows': - installerBase = 'Z:' + installerBase.replace('/', '\\') - process = subprocess.Popen(['wine', # nosec - installerBase, - '--version'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, _ = process.communicate(input=b'\n') - else: - process = subprocess.Popen([installerBase, # nosec - '--version'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, _ = process.communicate() - - for line in stdout.split(b'\n'): - if b'IFW Version:' in line: - self.qtIFWVersion = line.split(b' ')[2].replace(b'"', b'').replace(b',', b'').decode(sys.getdefaultencoding()) - - return - - @staticmethod - def listQmlFiles(path): - qmlFiles = set() - - if os.path.isfile(path): - baseName = os.path.basename(path) - - if baseName == 'qmldir' or path.endswith('.qml'): - qmlFiles.add(path) - else: - for root, _, files in os.walk(path): - for f in files: - if f == 'qmldir' or f.endswith('.qml'): - qmlFiles.add(os.path.join(root, f)) - - return list(qmlFiles) - - @staticmethod - def modulePath(importLine): - imp = importLine.strip().split() - path = imp[1].replace('.', '/') - majorVersion = imp[2].split('.')[0] - - if int(majorVersion) > 1: - path += '.{}'.format(majorVersion) - - return path - - def scanImports(self, path): - if not os.path.isfile(path): - return [] - - fileName = os.path.basename(path) - imports = set() - - if fileName.endswith('.qml'): - with open(path, 'rb') as f: - for line in f: - if re.match(b'^import \\w+' , line): - imports.add(self.modulePath(line.strip().decode(sys.getdefaultencoding()))) - elif fileName == 'qmldir': - with open(path, 'rb') as f: - for line in f: - if re.match(b'^depends ' , line): - imports.add(self.modulePath(line.strip().decode(sys.getdefaultencoding()))) - - return list(imports) - - def solvedepsQml(self): - qmlFiles = set() - - for path in self.qmlRootDirs: - path = os.path.join(self.rootDir, path) - - for f in self.listQmlFiles(path): - qmlFiles.add(f) - - solved = set() - solvedImports = set() - - while len(qmlFiles) > 0: - qmlFile = qmlFiles.pop() - - for imp in self.scanImports(qmlFile): - if imp in solvedImports: - continue - - sysModulePath = os.path.join(self.qtInstallQml, imp) - installModulePath = os.path.join(self.qmlInstallDir, imp) - - if os.path.exists(sysModulePath): - print(' {} -> {}'.format(sysModulePath, installModulePath)) - self.copy(sysModulePath, installModulePath) - solvedImports.add(imp) - self.dependencies.append(os.path.join(sysModulePath, 'qmldir')) - - for f in self.listQmlFiles(sysModulePath): - if not f in solved: - qmlFiles.add(f) - - solved.add(qmlFile) - - def solvedepsPlugins(self): - pluginsMap = { - 'Qt53DRenderer': ['sceneparsers', 'geometryloaders'], - 'Qt53DQuickRenderer': ['renderplugins'], - 'Qt5Declarative': ['qml1tooling'], - 'Qt5EglFSDeviceIntegration': ['egldeviceintegrations'], - 'Qt5Gui': ['accessible', - 'generic', - 'iconengines', - 'imageformats', - 'platforms', - 'platforminputcontexts', - 'styles'], - 'Qt5Location': ['geoservices'], - 'Qt5Multimedia': ['audio', 'mediaservice', 'playlistformats'], - 'Qt5Network': ['bearer'], - 'Qt5Positioning': ['position'], - 'Qt5PrintSupport': ['printsupport'], - 'Qt5QmlTooling': ['qmltooling'], - 'Qt5Quick': ['scenegraph', 'qmltooling'], - 'Qt5Sensors': ['sensors', 'sensorgestures'], - 'Qt5SerialBus': ['canbus'], - 'Qt5Sql': ['sqldrivers'], - 'Qt5TextToSpeech': ['texttospeech'], - 'Qt5WebEngine': ['qtwebengine'], - 'Qt5WebEngineCore': ['qtwebengine'], - 'Qt5WebEngineWidgets': ['qtwebengine'], - 'Qt5WebView': ['webview'], - 'Qt5XcbQpa': ['xcbglintegrations'] - } - - pluginsMap.update({lib + 'd': pluginsMap[lib] for lib in pluginsMap}) - plugins = [] - - for dep in self.binarySolver.scanDependencies(self.installDir): - libName = self.binarySolver.name(dep) - - if not libName in pluginsMap: - continue - - for plugin in pluginsMap[libName]: - if not plugin in plugins: - sysPluginPath = os.path.join(self.qtInstallPlugins, plugin) - pluginPath = os.path.join(self.pluginsInstallDir, plugin) - - if not os.path.exists(sysPluginPath): - continue - - print(' {} -> {}'.format(sysPluginPath, pluginPath)) - self.copy(sysPluginPath, pluginPath) - plugins.append(plugin) - self.dependencies.append(sysPluginPath) - - def writeQtConf(self): - paths = {'Plugins': os.path.relpath(self.pluginsInstallDir, self.binaryInstallDir), - 'Imports': os.path.relpath(self.qmlInstallDir, self.binaryInstallDir), - 'Qml2Imports': os.path.relpath(self.qmlInstallDir, self.binaryInstallDir)} - confPath = os.path.dirname(self.qtConf) - - if not os.path.exists(confPath): - os.makedirs(confPath) - - with open(self.qtConf, 'w') as qtconf: - qtconf.write('[Paths]\n') - - for path in paths: - qtconf.write('{} = {}\n'.format(path, paths[path])) - - @staticmethod - def readChangeLog(changeLog, appName, version): - if os.path.exists(changeLog): - with open(changeLog) as f: - for line in f: - if not line.startswith('{0} {1}:'.format(appName, version)): - continue - - # Skip first line. - f.readline() - changeLogText = '' - - for line_ in f: - if re.match('{} \d+\.\d+\.\d+:'.format(appName), line): - # Remove last line. - i = changeLogText.rfind('\n') - - if i >= 0: - changeLogText = changeLogText[: i] - - return changeLogText - - changeLogText += line_ - - return '' - - def createInstaller(self): - if not os.path.exists(self.qtIFW): - return False - - # Read package config - packageConf = configparser.ConfigParser() - packageConf.optionxform=str - packageConf.read(self.packageConfig, 'utf-8') - - # Create layout - componentName = 'com.{0}prj.{0}'.format(self.programName) - packageDir = os.path.join(self.installerPackages, componentName) - - if not os.path.exists(self.installerConfig): - os.makedirs(self.installerConfig) - - dataDir = os.path.join(packageDir, 'data') - metaDir = os.path.join(packageDir, 'meta') - - if not os.path.exists(dataDir): - os.makedirs(dataDir) - - if not os.path.exists(metaDir): - os.makedirs(metaDir) - - self.copy(self.appIcon, self.installerConfig) - iconName = os.path.splitext(os.path.basename(self.appIcon))[0] - licenseOutFile = os.path.basename(self.licenseFile) - - if not '.' in licenseOutFile and \ - (self.targetSystem == 'windows' or \ - self.targetSystem == 'posix_windows'): - licenseOutFile += '.txt' - - self.copy(self.licenseFile, os.path.join(metaDir, licenseOutFile)) - self.copy(self.rootInstallDir, dataDir) - - configXml = os.path.join(self.installerConfig, 'config.xml') - appName = packageConf['Package']['appName'].strip() - - with open(configXml, 'w') as config: - config.write('\n') - config.write('\n') - config.write(' {}\n'.format(appName)) - - if 'DAILY_BUILD' in os.environ: - config.write(' 0.0.0\n') - else: - config.write(' {}\n'.format(self.programVersion)) - - config.write(' {}\n'.format(packageConf['Package']['description'].strip())) - config.write(' {}\n'.format(appName)) - config.write(' {}\n'.format(packageConf['Package']['url'].strip())) - config.write(' {}\n'.format(iconName)) - config.write(' {}\n'.format(iconName)) - config.write(' {}\n'.format(iconName)) - config.write(' {}\n'.format(packageConf['Package']['titleColor'].strip())) - config.write(' {}\n'.format(self.installerRunProgram)) - config.write(' {}\n'.format(packageConf['Package']['runMessage'].strip())) - config.write(' {}\n'.format(appName)) - config.write(' {}MaintenanceTool\n'.format(appName)) - config.write(' true\n') - config.write(' {}\n'.format(self.installerTargetDir)) - config.write('\n') - - self.copy(self.installerScript, - os.path.join(metaDir, 'installscript.qs')) - - with open(os.path.join(metaDir, 'package.xml'), 'w') as f: - f.write('\n') - f.write('\n') - f.write(' {}\n'.format(appName)) - f.write(' {}\n'.format(packageConf['Package']['description'].strip())) - - if 'DAILY_BUILD' in os.environ: - f.write(' 0.0.0\n') - else: - f.write(' {}\n'.format(self.programVersion)) - - f.write(' {}\n'.format(time.strftime('%Y-%m-%d'))) - f.write(' {}\n'.format(componentName)) - f.write(' \n') - f.write(' \n'.format(packageConf['Package']['licenseDescription'].strip(), - licenseOutFile)) - f.write(' \n') - f.write(' \n') - f.write(' \n') - - if not 'DAILY_BUILD' in os.environ: - f.write(self.readChangeLog(self.changeLog, - appName, - self.programVersion)) - - f.write(' \n') - f.write(' true\n') - f.write(' true\n') - f.write(' false\n') - f.write('\n') - - # Remove old file - if not os.path.exists(self.pkgsDir): - os.makedirs(self.pkgsDir) - - if os.path.exists(self.outPackage): - os.remove(self.outPackage) - - params = [] - - if self.targetSystem == 'posix_windows': - params = ['wine'] - - params += [self.qtIFW, - '-c', configXml, - '-p', self.installerPackages, - self.outPackage] - process = subprocess.Popen(params, # nosec - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - process.communicate() - - return True diff -Nru webcamoid-8.6.1+dfsg/ports/deploy/tools/utils.py webcamoid-8.8.0+dfsg/ports/deploy/tools/utils.py --- webcamoid-8.6.1+dfsg/ports/deploy/tools/utils.py 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/ports/deploy/tools/utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,179 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Webcamoid, webcam capture application. -# Copyright (C) 2017 Gonzalo Exequiel Pedone -# -# Webcamoid 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. -# -# Webcamoid 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 Webcamoid. If not, see . -# -# Web-Site: http://webcamoid.github.io/ - -import hashlib -import multiprocessing -import os -import platform -import shutil -import subprocess # nosec -import sys - -class DeployToolsUtils: - def __init__(self): - self.make = '' - - if os.name == 'posix' and sys.platform.startswith('darwin'): - self.system = 'mac' - elif os.name == 'nt' and sys.platform.startswith('win32'): - self.system = 'windows' - elif os.name == 'posix': - self.system = 'posix' - else: - self.system = '' - - self.arch = platform.architecture()[0] - self.targetArch = self.arch - self.targetSystem = self.system - pathSep = ';' if self.system == 'windows' else ':' - self.sysBinsPath = [] - - if 'PATH' in os.environ: - self.sysBinsPath += \ - [path.strip() for path in os.environ['PATH'].split(pathSep)] - - self.njobs = multiprocessing.cpu_count() - - if self.njobs < 4: - self.njobs = 4 - - def detectTargetArch(self, binary=''): - if binary == '': - binary = self.mainBinary - - self.targetArch = platform.architecture(binary)[0] - - def whereBin(self, binary): - for path in self.sysBinsPath: - path = os.path.join(path, binary) - - if os.path.exists(path): - return path - - return '' - - def copy(self, src, dst='.', copyReals=False): - if not os.path.exists(src): - return False - - if os.path.isdir(src): - if os.path.isfile(dst): - return False - - for root, dirs, files in os.walk(src): - for f in files: - fromF = os.path.join(root, f) - toF = os.path.relpath(fromF, src) - toF = os.path.join(dst, toF) - toF = os.path.normpath(toF) - self.copy(fromF, toF) - - for d in dirs: - fromD = os.path.join(root, d) - toD = os.path.relpath(fromD, src) - toD = os.path.join(dst, toD) - - try: - os.makedirs(os.path.normpath(toD)) - except: - pass - elif os.path.isfile(src): - if os.path.isdir(dst): - dst = os.path.realpath(dst) - dst = os.path.join(dst, os.path.basename(src)) - - dirname = os.path.dirname(dst) - - if not os.path.exists(dirname): - try: - os.makedirs(dirname) - except: - return False - - if os.path.exists(dst): - try: - os.remove(dst) - except: - return False - - if copyReals and os.path.islink(src): - realpath = os.path.realpath(src) - basename = os.path.basename(realpath) - os.symlink(os.path.join('.', basename), dst) - self.copy(realpath, os.path.join(dirname, basename)) - else: - try: - if self.system == 'windows': - shutil.copy(src, dst) - else: - shutil.copy(src, dst, follow_symlinks=False) - except: - return False - - return True - - def detectMake(self): - if 'MAKE_PATH' in os.environ: - self.make = os.environ['MAKE_PATH'] - - return - - makes = ['mingw32-make', 'make'] if self.system == 'windows' else ['make'] - ext = '.exe' if self.system == 'windows' else '' - - for make in makes: - makePath = self.whereBin(make + ext) - - if makePath != '': - self.make = makePath - - break - - def makeInstall(self, buildDir, installRoot=''): - previousDir = os.getcwd() - os.chdir(buildDir) - - if installRoot == '': - process = subprocess.Popen([self.make, 'install'], # nosec - stdout=subprocess.PIPE) - else: - process = subprocess.Popen([self.make, 'INSTALL_ROOT=' + installRoot, 'install'], # nosec - stdout=subprocess.PIPE) - - process.communicate() - os.chdir(previousDir) - - return process.returncode - - @staticmethod - def sha256sum(fileName): - sha = hashlib.sha256() - - with open(fileName, 'rb') as f: - while True: - data = f.read(1024) - - if not data: - break - - sha.update(data) - - return sha.hexdigest() diff -Nru webcamoid-8.6.1+dfsg/README.md webcamoid-8.8.0+dfsg/README.md --- webcamoid-8.6.1+dfsg/README.md 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/README.md 2021-02-15 15:25:23.000000000 +0000 @@ -12,7 +12,7 @@ * Written in C++ and Qt. * Custom controls for each webcam. * Add funny effects to the webcam. -* +60 effects available. +* 60+ effects available. * Translated to many languages. * Use custom network and local files as capture devices. * Capture from desktop. @@ -23,20 +23,29 @@ Visit the [wiki](https://github.com/webcamoid/webcamoid/wiki) for a comprehensive compile and install instructions. +## Downloads ## + +[![Download](https://img.shields.io/badge/Download-Releases-3f2a7e.svg)](https://github.com/webcamoid/webcamoid/releases) +[![Daily Build](https://img.shields.io/badge/Download-Daily%20Build-3f2a7e.svg)](https://bintray.com/webcamoid/webcamoid/webcamoid/daily) +[![Total Downloads](https://img.shields.io/github/downloads/webcamoid/webcamoid/total.svg?label=Total%20Downloads&color=3f2a7e)](https://tooomm.github.io/github-release-stats/?username=webcamoid&repository=webcamoid) + +## Donations ## + +I'm accepting donations in crypto currencies, any donation amount is welcome and very appreciated. + +[![Bitcoin donation](https://img.shields.io/badge/Donation-Bitcoin-bf8c00.svg)](mailto:hipersayan%2Ex%40gmail%2Ecom?subject=%5BDonation%5D%20Donation%20for%20Webcamoid&body=Hi%2C%20I%20want%20to%20make%20a%20donation%20for%20Webcamoid%2C%20please%20send%20me%20the%20address.) +[![Monero donation](https://img.shields.io/badge/Donation-Monero-bf8c00.svg)](https://gist.github.com/hipersayanX/0d575fc7b9b36a2e9817027fb50258bd) + ## Status ## [![Build Status](https://travis-ci.org/webcamoid/webcamoid.svg?branch=master)](https://travis-ci.org/webcamoid/webcamoid) -[![Build status](https://ci.appveyor.com/api/projects/status/hrgbf3qe52ysr8gl?svg=true)](https://ci.appveyor.com/project/hipersayanX/webcamoid) +[![Build status](https://ci.appveyor.com/api/projects/status/1ecp839l0nnnya9l?svg=true)](https://ci.appveyor.com/project/hipersayanX/webcamoid) [![Build status](https://api.cirrus-ci.com/github/webcamoid/webcamoid.svg)](https://cirrus-ci.com/github/webcamoid/webcamoid) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/fd3ca6ed8bea43e992b1d329c3dc916f)](https://www.codacy.com/app/webcamoid/webcamoid?utm_source=github.com&utm_medium=referral&utm_content=webcamoid/webcamoid&utm_campaign=Badge_Grade) [![Translation status](https://hosted.weblate.org/widgets/webcamoid/-/svg-badge.svg)](https://hosted.weblate.org/engage/webcamoid/?utm_source=widget) [![Project Stats](https://www.openhub.net/p/Webcamoid/widgets/project_thin_badge.gif)](https://www.openhub.net/p/Webcamoid) -[![Total Downloads](https://img.shields.io/github/downloads/webcamoid/webcamoid/total.svg)](https://github.com/webcamoid/webcamoid/releases) -[![Daily Build](https://api.bintray.com/packages/webcamoid/webcamoid/webcamoid/images/download.svg?version=daily)](https://bintray.com/webcamoid/webcamoid/webcamoid/daily/link) [![Gitlab mirror](https://img.shields.io/badge/mirror-Gitlab-007fff.svg)](https://gitlab.com/hipersayanX/webcamoid/) [![SourceForge mirror](https://img.shields.io/badge/mirror-SourceForge-007fff.svg)](https://sourceforge.net/p/webcamoid/) -[![Softpedia reviews](https://img.shields.io/badge/review-Softpedia-ff69b4.svg)](http://www.softpedia.com/get/Internet/WebCam/Webcamoid.shtml) -[![alternativeTo reviews](https://img.shields.io/badge/review-alternativeTo-ff69b4.svg)](https://alternativeto.net/software/webcamoid/) [![Packaging status](https://repology.org/badge/vertical-allrepos/webcamoid.svg)](https://repology.org/metapackage/webcamoid) diff -Nru webcamoid-8.6.1+dfsg/SECURITY.md webcamoid-8.8.0+dfsg/SECURITY.md --- webcamoid-8.6.1+dfsg/SECURITY.md 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/SECURITY.md 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,10 @@ +# Security Policy + +## Supported Versions + +Only report vulnerabilities in the [latest stable](https://github.com/webcamoid/webcamoid/releases) version and the [master repository](https://github.com/webcamoid/webcamoid) (that includes [daily build](https://bintray.com/webcamoid/webcamoid/webcamoid/daily/link)). + +## Reporting a Vulnerability + +Report all vulnerabilities at the [issues section](https://github.com/webcamoid/webcamoid/issues). +​ \ No newline at end of file diff -Nru webcamoid-8.6.1+dfsg/StandAlone/Info.plist webcamoid-8.8.0+dfsg/StandAlone/Info.plist --- webcamoid-8.6.1+dfsg/StandAlone/Info.plist 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/Info.plist 2021-02-15 15:25:23.000000000 +0000 @@ -20,5 +20,7 @@ NSApplication NSSupportsAutomaticGraphicsSwitching + NSCameraUsageDescription + Webcamoid needs permissions for camera capture diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/openclipart.txt webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/openclipart.txt --- webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/openclipart.txt 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/openclipart.txt 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/OpenCV.txt webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/OpenCV.txt --- webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/OpenCV.txt 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/OpenCV.txt 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,36 @@ + IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + + By downloading, copying, installing or using the software you agree to this license. + If you do not agree to this license, do not download, install, + copy or use the software. + + + Intel License Agreement + For Open Source Computer Vision Library + +Copyright (C) 2000, Intel Corporation, all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistribution's of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistribution's 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. + + * The name of Intel Corporation may not be used to endorse or promote products + derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall the Intel Corporation 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. diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/README.txt webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/README.txt --- webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/README.txt 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/README.txt 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,2 @@ +This folder contains licences for 3rd-party work incorporated into Webcamoid. +These licences DOES NOT applies to Webcamoid itself. diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/TemperatureAlgorithm.txt webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/TemperatureAlgorithm.txt --- webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/TemperatureAlgorithm.txt 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/TemperatureAlgorithm.txt 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,23 @@ +Copyright (c) 2012, Tanner Helland +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/UsbIds.txt webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/UsbIds.txt --- webcamoid-8.6.1+dfsg/StandAlone/share/3rd-party/licenses/UsbIds.txt 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/3rd-party/licenses/UsbIds.txt 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,27 @@ +usb.ids file, and ONLY usb.ids file is licensed under the 3-Clause BSD License, +following is a copy of the license: + + +3-clause BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL 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. diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/android/AndroidManifest.xml webcamoid-8.8.0+dfsg/StandAlone/share/android/AndroidManifest.xml --- webcamoid-8.6.1+dfsg/StandAlone/share/android/AndroidManifest.xml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/android/AndroidManifest.xml 2021-02-15 15:25:23.000000000 +0000 @@ -1,12 +1,13 @@ - + + + + + @@ -26,44 +31,67 @@ - - - + - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - + @@ -75,4 +103,17 @@ + + + + + + + + + + + + Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/android/res/drawable-hdpi/icon.png and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/android/res/drawable-hdpi/icon.png differ Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/android/res/drawable-ldpi/icon.png and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/android/res/drawable-ldpi/icon.png differ Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/android/res/drawable-mdpi/icon.png and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/android/res/drawable-mdpi/icon.png differ Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/android/res/drawable-xhdpi/icon.png and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/android/res/drawable-xhdpi/icon.png differ Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/android/res/drawable-xxhdpi/icon.png and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/android/res/drawable-xxhdpi/icon.png differ Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/android/res/drawable-xxxhdpi/icon.png and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/android/res/drawable-xxxhdpi/icon.png differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/contributors.txt webcamoid-8.8.0+dfsg/StandAlone/share/contributors.txt --- webcamoid-8.6.1+dfsg/StandAlone/share/contributors.txt 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/contributors.txt 2021-02-15 15:25:23.000000000 +0000 @@ -1,9 +1,11 @@ Adam Magnier Ale-Ma Allan Nordhøy +Antonino Murabito Ascaf0 Edoardo Rosa Edwar Tikhonov +Elizabeth Sherrock Ettore Atalan ezjerry liao Gruni Lala @@ -13,6 +15,7 @@ John Vandenberg josep constanti Knusper +Kozioł Marcin Kristjan Räts Livia Andriana Lohanda LL @@ -28,6 +31,8 @@ Rui Mendes Sebastian Freiman ssantos +Swann Martinet +TheSimplyOwl WaldiS Yaron Shahrabani YFdyh000 @@ -36,5 +41,6 @@ Володимир Бриняк Максим Якимчук Марс Ямбар +Роман Хрущ 吴绮 이피시소리 diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/man/webcamoid.1 webcamoid-8.8.0+dfsg/StandAlone/share/man/webcamoid.1 --- webcamoid-8.6.1+dfsg/StandAlone/share/man/webcamoid.1 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/man/webcamoid.1 2021-02-15 15:25:23.000000000 +0000 @@ -1,4 +1,5 @@ .\" Manpage for Webcamoid. +.\" .\" Contact https://github.com/webcamoid/webcamoid/issues to correct errors or .\" typos. .\" @@ -6,7 +7,7 @@ .\" Distributed under GPLv3+ .\" %%%LICENSE_END .\" -.TH WEBCAMOID 1 "26 Mar 2019" "Version 8.6.1" "Webcamoid Users's Manual" +.TH WEBCAMOID 1 "16 Feb 2021" "Version 8.8.0" "Webcamoid Users's Manual" .SH NAME Webcamoid \- full featured webcam capture application .SH SYNOPSIS diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/qml/AudioInfo.qml webcamoid-8.8.0+dfsg/StandAlone/share/qml/AudioInfo.qml --- webcamoid-8.6.1+dfsg/StandAlone/share/qml/AudioInfo.qml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/qml/AudioInfo.qml 2021-02-15 15:25:23.000000000 +0000 @@ -21,6 +21,7 @@ import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import AkQml 1.0 +import AkQmlControls 1.0 Rectangle { id: recAudioConfig @@ -48,25 +49,21 @@ iDescription = AudioLayer.description(iDevice); var audioCaps = Ak.newAudioCaps(); - var supportedFormats = AudioLayer.supportedFormats(iDevice); + var supportedFormats = + Ak.newList(AudioLayer.supportedFormats(iDevice)); iSampleFormats.clear(); for (var format in supportedFormats) - iSampleFormats.append({format: audioCaps.sampleFormatFromString(supportedFormats[format]), - description: supportedFormats[format]}); + iSampleFormats.append({format: supportedFormats[format], + description: audioCaps.sampleFormatToString(supportedFormats[format])}); - var supportedChannels = AudioLayer.supportedChannels(iDevice); - iChannels.clear(); - - for (var channels in supportedChannels) { - var description = - supportedChannels[channels] - + " - " - + audioCaps.defaultChannelLayoutString(supportedChannels[channels]); - - iChannels.append({channels: supportedChannels[channels], - description: description}); - } + var supportedChannelLayouts = + Ak.newList(AudioLayer.supportedChannelLayouts(iDevice)); + iChannelLayouts.clear(); + + for (var layout in supportedChannelLayouts) + iChannelLayouts.append({layout: supportedChannelLayouts[layout], + description: audioCaps.channelLayoutToString(supportedChannelLayouts[layout])}); var supportedSampleRates = AudioLayer.supportedSampleRates(iDevice); iSampleRates.clear(); @@ -79,12 +76,12 @@ cbxISampleFormats.currentIndex = bound(0, - supportedFormats.indexOf(audioCaps.sampleFormatToString(preferredFormat.format)), + supportedFormats.indexOf(preferredFormat.format), cbxISampleFormats.model.count - 1); - cbxIChannels.currentIndex = + cbxIChannelLayouts.currentIndex = bound(0, - supportedChannels.indexOf(preferredFormat.channels), - cbxIChannels.model.count - 1); + supportedChannelLayouts.indexOf(preferredFormat.layouts), + cbxIChannelLayouts.model.count - 1); cbxISampleRates.currentIndex = bound(0, supportedSampleRates.indexOf(preferredFormat.rate), @@ -100,27 +97,24 @@ oDescription = AudioLayer.description(AudioLayer.audioOutput); var audioCaps = Ak.newAudioCaps(); - var supportedFormats = AudioLayer.supportedFormats(AudioLayer.audioOutput); + var supportedFormats = + Ak.newList(AudioLayer.supportedFormats(AudioLayer.audioOutput)); oSampleFormats.clear(); for (var format in supportedFormats) - oSampleFormats.append({format: audioCaps.sampleFormatFromString(supportedFormats[format]), - description: supportedFormats[format]}); + oSampleFormats.append({format: supportedFormats[format], + description: audioCaps.sampleFormatToString(supportedFormats[format])}); - var supportedChannels = AudioLayer.supportedChannels(AudioLayer.audioOutput); - oChannels.clear(); + var supportedChannelLayouts = + Ak.newList(AudioLayer.supportedChannelLayouts(AudioLayer.audioOutput)); + oChannelLayouts.clear(); + + for (var layout in supportedChannelLayouts) + oChannelLayouts.append({layout: supportedChannelLayouts[layout], + description: audioCaps.channelLayoutToString(supportedChannelLayouts[layout])}); - for (var channels in supportedChannels) { - var description = - supportedChannels[channels] - + " - " - + audioCaps.defaultChannelLayoutString(supportedChannels[channels]); - - oChannels.append({channels: supportedChannels[channels], - description: description}); - } - - var supportedSampleRates = AudioLayer.supportedSampleRates(AudioLayer.audioOutput); + var supportedSampleRates = + AudioLayer.supportedSampleRates(AudioLayer.audioOutput); oSampleRates.clear(); for (var rate in supportedSampleRates) @@ -131,12 +125,12 @@ cbxOSampleFormats.currentIndex = bound(0, - supportedFormats.indexOf(audioCaps.sampleFormatToString(preferredFormat.format)), + supportedFormats.indexOf(preferredFormat.format), cbxOSampleFormats.model.count - 1); - cbxOChannels.currentIndex = + cbxOChannelLayouts.currentIndex = bound(0, - supportedChannels.indexOf(preferredFormat.channels), - cbxOChannels.model.count - 1); + supportedChannelLayouts.indexOf(preferredFormat.layout), + cbxOChannelLayouts.model.count - 1); cbxOSampleRates.currentIndex = bound(0, supportedSampleRates.indexOf(preferredFormat.rate), @@ -151,33 +145,33 @@ return; var cbxSampleFormats = isInput? cbxISampleFormats: cbxOSampleFormats; - var cbxChannels = isInput? cbxIChannels: cbxOChannels; + var cbxChannelLayouts = isInput? cbxIChannelLayouts: cbxOChannelLayouts; var cbxSampleRates = isInput? cbxISampleRates: cbxOSampleRates; var audioCaps = Ak.newAudioCaps() if (cbxSampleFormats.model.count > 0 - && cbxChannels.model.count > 0 + && cbxChannelLayouts.model.count > 0 && cbxSampleRates.model.count > 0) { var sampleFormatsCI = bound(0, cbxSampleFormats.currentIndex, cbxSampleFormats.model.count - 1); - var channelsCI = bound(0, cbxChannels.currentIndex, cbxChannels.model.count - 1); + var channelLayoutsCI = bound(0, cbxChannelLayouts.currentIndex, cbxChannelLayouts.model.count - 1); var sampleRatesCI = bound(0, cbxSampleRates.currentIndex, cbxSampleRates.model.count - 1); audioCaps = Ak.newAudioCaps(cbxSampleFormats.model.get(sampleFormatsCI).format, - cbxChannels.model.get(channelsCI).channels, + cbxChannelLayouts.model.get(channelLayoutsCI).layout, cbxSampleRates.model.get(sampleRatesCI).sampleRate); } if (isInput) { var state = AudioLayer.inputState; AudioLayer.inputState = AkElement.ElementStateNull; - AudioLayer.inputDeviceCaps = audioCaps.toCaps(); + AudioLayer.inputDeviceCaps = Ak.varAudioCaps(audioCaps); AudioLayer.inputState = state; } else { var state = AudioLayer.outputState; AudioLayer.outputState = AkElement.ElementStateNull; - AudioLayer.outputDeviceCaps = audioCaps.toCaps(); + AudioLayer.outputDeviceCaps = Ak.varAudioCaps(audioCaps); AudioLayer.outputState = state; } } @@ -293,9 +287,9 @@ } ColumnLayout { ComboBox { - id: cbxOChannels + id: cbxOChannelLayouts model: ListModel { - id: oChannels + id: oChannelLayouts } textRole: "description" Layout.fillWidth: true @@ -303,9 +297,9 @@ onCurrentIndexChanged: updateCaps(false) } ComboBox { - id: cbxIChannels + id: cbxIChannelLayouts model: ListModel { - id: iChannels + id: iChannelLayouts } textRole: "description" Layout.fillWidth: true @@ -341,6 +335,53 @@ } } Label { + text: qsTr("Latency (ms)") + } + RowLayout { + Slider { + id: sldOLatency + value: AudioLayer.outputLatency + stepSize: 1 + from: 1 + to: 2048 + Layout.fillWidth: true + visible: true + + onValueChanged: AudioLayer.outputLatency = value + } + SpinBox { + id: spbOLatency + value: AudioLayer.outputLatency + from: sldOLatency.from + to: sldOLatency.to + stepSize: sldOLatency.stepSize + visible: true + + onValueChanged: AudioLayer.outputLatency = value + } + Slider { + id: sldILatency + value: AudioLayer.inputLatency + stepSize: 1 + from: 1 + to: 2048 + Layout.fillWidth: true + visible: false + + onValueChanged: AudioLayer.inputLatency = value + } + SpinBox { + id: spbILatency + value: AudioLayer.inputLatency + from: sldILatency.from + to: sldILatency.to + stepSize: sldILatency.stepSize + visible: false + + onValueChanged: AudioLayer.inputLatency = value + } + } + Label { Layout.fillHeight: true } } @@ -374,11 +415,11 @@ visible: true } PropertyChanges { - target: cbxOChannels + target: cbxOChannelLayouts visible: false } PropertyChanges { - target: cbxIChannels + target: cbxIChannelLayouts visible: true } PropertyChanges { @@ -389,6 +430,22 @@ target: cbxISampleRates visible: true } + PropertyChanges { + target: sldOLatency + visible: false + } + PropertyChanges { + target: spbOLatency + visible: false + } + PropertyChanges { + target: sldILatency + visible: true + } + PropertyChanges { + target: spbILatency + visible: true + } } ] } diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/qml/GeneralConfig.qml webcamoid-8.8.0+dfsg/StandAlone/share/qml/GeneralConfig.qml --- webcamoid-8.6.1+dfsg/StandAlone/share/qml/GeneralConfig.qml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/qml/GeneralConfig.qml 2021-02-15 15:25:23.000000000 +0000 @@ -28,13 +28,19 @@ clip: true contentHeight: generalConfigs.height - property variant videoCapture: Ak.newElement("VideoCapture") - property variant desktopCapture: Ak.newElement("DesktopCapture") - property variant audioDevice: Ak.newElement("AudioDevice") - property variant audioConvert: Ak.newElement("ACapsConvert") + property variant videoCapture: Ak.newElement("VideoCapture", + "Ak.Element.Settings") + property variant desktopCapture: Ak.newElement("DesktopCapture", + "Ak.Element.Settings") + property variant audioDevice: Ak.newElement("AudioDevice", + "Ak.Element.Settings") + property variant audioConvert: Ak.newElement("ACapsConvert", + "Ak.Element.Settings") property variant virtualCamera: Ak.newElement("VirtualCamera") - property variant multiSrc: Ak.newElement("MultiSrc") - property variant multiSink: Ak.newElement("MultiSink") + property variant multiSrc: Ak.newElement("MultiSrc", + "Ak.Element.Settings") + property variant multiSink: Ak.newElement("MultiSink", + "Ak.Element.Settings") ColumnLayout { id: generalConfigs @@ -69,7 +75,7 @@ } ComboBox { Layout.fillWidth: true - model: videoCapture.listSubModules(["capture"]) + model: videoCapture.captureSubModules currentIndex: model.indexOf(videoCapture.captureLib) onCurrentIndexChanged: videoCapture.captureLib = model[currentIndex] @@ -79,7 +85,7 @@ } ComboBox { Layout.fillWidth: true - model: desktopCapture.listSubModules() + model: desktopCapture.subModules currentIndex: model.indexOf(desktopCapture.captureLib) onCurrentIndexChanged: desktopCapture.captureLib = model[currentIndex] @@ -89,7 +95,7 @@ } ComboBox { Layout.fillWidth: true - model: audioDevice.listSubModules() + model: audioDevice.subModules currentIndex: model.indexOf(audioDevice.audioLib) onCurrentIndexChanged: audioDevice.audioLib = model[currentIndex] @@ -99,7 +105,7 @@ } ComboBox { Layout.fillWidth: true - model: videoCapture.listSubModules(["convert"]) + model: videoCapture.codecSubModules currentIndex: model.indexOf(videoCapture.codecLib) onCurrentIndexChanged: videoCapture.codecLib = model[currentIndex] @@ -109,7 +115,7 @@ } ComboBox { Layout.fillWidth: true - model: audioConvert.listSubModules() + model: audioConvert.subModules currentIndex: model.indexOf(audioConvert.convertLib) onCurrentIndexChanged: audioConvert.convertLib = model[currentIndex] @@ -119,7 +125,7 @@ } ComboBox { Layout.fillWidth: true - model: multiSrc.listSubModules() + model: multiSrc.subModules currentIndex: model.indexOf(multiSrc.codecLib) onCurrentIndexChanged: multiSrc.codecLib = model[currentIndex] @@ -129,7 +135,7 @@ } ComboBox { Layout.fillWidth: true - model: multiSink.listSubModules() + model: multiSink.subModules currentIndex: model.indexOf(multiSink.codecLib) onCurrentIndexChanged: multiSink.codecLib = model[currentIndex] Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/ca.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/ca.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/ca.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/ca.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/ca.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/ca.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description Descripció - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search Recerca @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ Cancel·la - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/de.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/de.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/de.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/de.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/de.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/de.ts 2021-02-15 15:25:23.000000000 +0000 @@ -6,57 +6,58 @@ About %1 - + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + Über %1 Information - + Information Thanks! - + Danke! License - + Lizenz Version %1 - + Version %1 Using Qt %1 - + Verwendet Qt %1 Website - + Website Webcam capture application. - Webcam-Aufnahmeanwendung. + Webcam-Aufnahmeanwendung. A simple webcam application for picture and video capture. - + Eine einfache Webcam-Anwendung für die Bild- und Videoaufzeichnung. Thanks to all these cool people that helped contributing to Webcamoid all these years. - + Vielen Dank an all diese coolen Leute, die all die Jahre dazu beigetragen haben, Webcamoid zu unterstützen. Close - + Schließen @@ -139,38 +140,43 @@ AudioInfo - + Description Beschreibung - - + + Device description Gerätebeschreibung - - - + + + Device id Gerätekennung - + Sample Format Abtastformat - + Channels Kanäle - + Sample Rate Abtastrate + + + Latency (ms) + Latenz (ms) + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start Webcam beim Start wiedergeben - + Enable advanced effects mode Erweiterten Effektmodus aktivieren - + Frameworks & libraries Programmiergerüste & Bibliotheken - + Video capture Videoaufnahme - + Desktop capture Desktop-Aufnahme - + Audio capture/play Audioaufnahme/-wiedergabe - + Video convert Videokonvertierung - + Audio convert Audio-Konvertierung - + Virtual camera driver - + Virtueller Kameratreiber - + Video playback Videowiedergabe - + Video record Videoaufnahme - + Root method Wurzelverfahren @@ -372,9 +378,9 @@ MediaTools - + Daily Build - + Täglicher Build @@ -481,7 +487,7 @@ PATH - + PFAD @@ -494,7 +500,7 @@ PATH1;PATH2;PATH3;... - + PFAD1;PFAD2;PFAD3;... @@ -562,35 +568,35 @@ Recording - + Audio Audio - + Video Video - + Subtitle Untertitel - - + + audio Audio - - + + video Video - - + + subtitle Untertitel @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures GOP @@ -841,7 +848,8 @@ - + + Scan block Scan-Block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix Transformationsmatrix @@ -892,7 +901,7 @@ - + Search Suchen @@ -933,6 +942,7 @@ Style + Different font rendering strategies Stil @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications Basis @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map Hitze @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) Sepia @@ -1148,7 +1161,7 @@ - + Custom Benutzerdefiniert @@ -1160,7 +1173,7 @@ - + Please choose an image file Bitte wählen Sie eine Bilddatei aus @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) Convolve-Matrix @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Mu Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) Sigma @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector Canny-Modus @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization Egalisieren @@ -1298,404 +1316,414 @@ Invertieren - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature Haar-Datei - + Eye Auge - + Eye glasses Augengläser - + Frontal face alternative 1 Stirnfläche Alternative 1 - + Frontal face alternative 2 Stirnseite Alternative 2 - + Frontal face alternative 3 Stirnfläche Alternative 3 - + Frontal face default Standard Stirnfläche - + Full body Ganzkörper - + Left Eye 1 Linkes Auge 1 - + Lower body Unterkörper - + Eye pair big Augenpaar groß - + Eye pair small Augenpaar klein - + Left ear Linkes Ohr - + Left eye 2 Linkes Auge 2 - + Mouth Mund - + Nose Nase - + Right ear Rechtes Ohr - + Right Eye 1 Rechtes Auge 1 - + Upper body 1 Oberkörper 1 - + Profile face Profilfläche - + Right eye 2 Rechtes Auge 2 - + Smile Lächeln - + Upper body Oberkörper - + Marker type Marker-Typ - + Rectangle Rechteck - + Ellipse Ellipse - + Image Bild - + Pixelate Verpixeln - + Blur Unschärfe - + + Blur Outer + + + + Marker style Marker-Stil - + Solid Fest - + Dash Strich - + Dot Punkt - + Dash dot Strich-Punkt - + Dash dot dot Strich-Punkt-Punkt - + Marker color Markerfarbe - + + Marker width Markerbreite - + Masks Masken - + Angel Engel - + Bear Bär - + Beaver Biber - + Cat Katze - + Chicken Huhn - + Cow Kuh - + Devil Teufel - + Dog Hund - + Dalmatian dog Dalmatinerhund - + Happy dog Fröhlicher Hund - + Dragon Drache - + Elephant 1 Elefant 1 - + Elephant 2 Elefant 2 - + Elk Elch - + Frog Frosch - + Ghost Geist - + Giraffe Giraffe - + Gnu Gnu - + Goat Ziege - + Hippo Nilpferd - + Horse Pferd - + Gray horse Schimmel - + Koala Koala - + Monkey Affe - + Gray mouse Graue Maus - + White mouse Weiße Maus - + Panda Panda - + Penguin Pinguin - + Pumpkin 1 Kürbis 1 - + Pumpkin 2 Kürbis 2 - + Raccoon Waschbär - + Rhino Nashorn - + Sheep Schaf - + Skull 1 Schädel 1 - + Skull 2 Schädel 2 - + Triceratops Triceratops - + Zebra Zebra - + Marker picture Markerbild - - Replace face with this picture. - Gesicht mit diesem Bild ersetzen. + + Replace face with this picture + - + + Pixel grid size Pixelrastergröße - + + Blur radius Unschärferadius - + Select marker color Wählen Sie die Markerfarbe @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Luma-Schwellenwert Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha diff Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image Alpha-Variation @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Luma-Schwellenwert Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton Wählen Sie die Farbe der Automata aus @@ -1917,22 +1950,22 @@ Cursor anzeigen - + Output format Ausgabeformat - + File extensions Dateiendungen - + This output format has not specific extensions Dieses Ausgabeformat hat keine spezifischen Endungen - + Advanced Format Options Erweiterte Formatoptionen @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image Alpha-Differenzial @@ -2057,17 +2091,17 @@ Temperatur - + Video format Videoformat - + Resolution Auflösung - + FPS BPS @@ -2132,8 +2166,8 @@ Kameraname (optional) - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ Abbrechen - + This system is not supported yet Dieses System wird noch nicht unterstützt Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/el.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/el.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/el.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/el.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/el.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/el.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/es.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/es.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/es.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/es.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/es.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/es.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description Descripción - - + + Device description Descripción del dispositivo - - - + + + Device id Identificación del dispositivo - + Sample Format Formato de la muestra - + Channels Canales - + Sample Rate Frequencia de muestreo + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start Reproducir webcam al inicio - + Enable advanced effects mode Habilitar el modo de efectos avanzados - + Frameworks & libraries Frameworks y librerías - + Video capture Captura de vídeo - + Desktop capture Captura del escritorio - + Audio capture/play Capturar/Reproducir audio - + Video convert Convertir vídeo - + Audio convert Convertir audio - + Virtual camera driver - + Video playback Reproducción de vídeo - + Video record Grabación de vídeo - + Root method Método inicial @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio Audio - + Video Vídeo - + Subtitle Subtítulo - - + + audio audio - - + + video vídeo - - + + subtitle subtítulo @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures GOP @@ -841,7 +848,8 @@ - + + Scan block Analizar bloque @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix Matriz de transformación @@ -892,7 +901,7 @@ - + Search Buscar @@ -933,6 +942,7 @@ Style + Different font rendering strategies Estilo @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications Base @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map Intensidad @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) Sepia @@ -1148,7 +1161,7 @@ - + Custom Personalizado @@ -1160,7 +1173,7 @@ - + Please choose an image file Por favor elija un archivo de imagen @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) Matriz de implicación @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Mu Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) Sigma @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector Modo Canny @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization Igualar @@ -1298,404 +1316,414 @@ Invertir - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature Archivo Haar - + Eye Vista - + Eye glasses Anteojos - + Frontal face alternative 1 Alternativa de cara frontal 1 - + Frontal face alternative 2 Alternativa de cara frontal 2 - + Frontal face alternative 3 Alternativa de cara frontal 3 - + Frontal face default Cara frontal predeterminada - + Full body Cuerpo completo - + Left Eye 1 Ojo izquierdo 1 - + Lower body Cuerpo inferior - + Eye pair big Par de ojos grandes - + Eye pair small Par de ojos pequeños - + Left ear Oreja izquierda - + Left eye 2 Ojo izquierdo 2 - + Mouth Boca - + Nose Nariz - + Right ear Oreja derecha - + Right Eye 1 Ojo derecho 1 - + Upper body 1 Parte superior del cuerpo 1 - + Profile face Cara de perfil - + Right eye 2 Ojo derecho 2 - + Smile Sonrisa - + Upper body Parte superior del cuerpo - + Marker type Tipo de marcador - + Rectangle Rectángulo - + Ellipse Elipse - + Image Imagen - + Pixelate Pixelado - + Blur Difuminar - + + Blur Outer + + + + Marker style Estilo de marcador - + Solid Sólido - + Dash Guión - + Dot Punto - + Dash dot Punto y guión - + Dash dot dot Punto, guión y guión - + Marker color Marcador de color - + + Marker width Ancho del marcador - + Masks Máscaras - + Angel Ángel - + Bear Oso - + Beaver Castor - + Cat Gato - + Chicken Pollo - + Cow Vaca - + Devil Diablo - + Dog Perro - + Dalmatian dog Perro dálmata - + Happy dog Perro feliz - + Dragon Dragón - + Elephant 1 Elefante 1 - + Elephant 2 Elefante 2 - + Elk Alce - + Frog Rana - + Ghost Fantasma - + Giraffe Jirafa - + Gnu Ñu - + Goat Cabra - + Hippo Hipopótamo - + Horse Caballo - + Gray horse Caballo gris - + Koala Coala - + Monkey Mono - + Gray mouse Ratón gris - + White mouse Ratón blanco - + Panda Panda - + Penguin Pingüino - + Pumpkin 1 Calabaza 1 - + Pumpkin 2 Calabaza 2 - + Raccoon Mapache - + Rhino Rinoceronte - + Sheep Oveja - + Skull 1 Cráneo 1 - + Skull 2 Cráneo 2 - + Triceratops Triceratops - + Zebra Cebra - + Marker picture Imagen de marcador - - Replace face with this picture. - Reemplazar la cara con esta imagen. + + Replace face with this picture + - + + Pixel grid size Tamaño de cuadrícula de píxel - + + Blur radius Ratio de desenfoque - + Select marker color Seleccionar el color del marcador @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Umbral de luz Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Diferencia alfa Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image Variación alfa @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Umbral de luma Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton Elija el color del autómata @@ -1917,22 +1950,22 @@ Mostrar cursor - + Output format Formato de salida - + File extensions Extensiones de archivo - + This output format has not specific extensions Este formato de salida no tiene extensiones específicas - + Advanced Format Options Opciones avanzadas de formato @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image Diferencial alfa @@ -2057,17 +2091,17 @@ Temperatura - + Video format Formato de vídeo - + Resolution Resolución - + FPS FPS @@ -2132,8 +2166,8 @@ Nombre de la cámara (opcional) - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ Cancelar - + This system is not supported yet Este sistema aún no es compatible Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/et.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/et.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/et.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/et.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/et.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/et.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description Kirjeldus - - + + Device description Seadme kirjeldus - - - + + + Device id Seadme id - + Sample Format Diskreetimisvorming - + Channels Kanalid - + Sample Rate Diskreetimissagedus + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start Käivita veebikaamera käivitamisel - + Enable advanced effects mode Luba täiustatud efektide režiim - + Frameworks & libraries Raamistikud ja teegid - + Video capture Videohõive - + Desktop capture Töölaua hõive - + Audio capture/play Audio hõive/esitamine - + Video convert Video teisendamine - + Audio convert Audio teisendamine - + Virtual camera driver - + Video playback Video taasesitus - + Video record Video salvestamine - + Root method Põhimeetod @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio Heli - + Video Video - + Subtitle Subtiitrid - - + + audio heli - - + + video video - - + + subtitle subtiitrid @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures GOP @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search Otsi @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ Loobu - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/fr.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/fr.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/fr.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/fr.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/fr.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/fr.ts 2021-02-15 15:25:23.000000000 +0000 @@ -46,7 +46,7 @@ A simple webcam application for picture and video capture. - + Une application webcam simple pour la capture d’images et de vidéos. @@ -139,37 +139,43 @@ AudioInfo - + Description - Description + Description - - + + Device description - + Description de l’appareil - - - + + + Device id - + Identifiant de l’appareil - + Sample Format - + Format d’échantillon - + Channels - + Chaînes - + Sample Rate - + Débit d’échantillonnage + + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + @@ -177,27 +183,27 @@ Configure %1 - + Configurer %1 Search option - + Option de recherche Reset - + Réinitialiser Cancel - Annuler + Annuler OK - + OK @@ -215,12 +221,12 @@ Plugins Configs - + Configurations des greffons Updates - + Mises à jour @@ -268,64 +274,64 @@ GeneralConfig - + Play webcam on start - + Allumer la webacm au démarrage - + Enable advanced effects mode Activer le mode effets avancés - + Frameworks & libraries - + Cadres logiciels & bibliothèques - + Video capture - + Capture vidéo - + Desktop capture - + Capture du bureau - + Audio capture/play - + Lire/capturer l’audio - + Video convert - + Conversion vidéo - + Audio convert - + Conversion audio - + Virtual camera driver - + Pilote virtuel de la caméra - + Video playback - + Lecture vidéo - + Video record - + Enregistrement vidéo - + Root method - + Méthode racine @@ -333,7 +339,7 @@ No webcams found - + Aucune webcam détectée @@ -351,7 +357,7 @@ Media UID - + Média UID @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -390,27 +396,27 @@ %1 seconds - + %1 secondes Now - + Maintenant Cancel - Annuler + Annuler Shot! - + Prendre un cliché ! Use flash - + Utiliser le flash @@ -423,42 +429,42 @@ Extra search paths - + Chemins de recherche supplémentaires Search plugins in subfolders. - + Rechercher des greffons dans les sous-dossiers. Add - Ajouter + Ajouter Remove - Supprimer + Enlever Plugins list - + Liste des greffons Refresh - + Rafraîchir Disable - + Désactiver Enable - + Activer @@ -471,7 +477,7 @@ Webcam capture application. - Application de capture de webcam. + Application de capture de webcam. @@ -481,7 +487,7 @@ PATH - + CHEMIN @@ -522,7 +528,7 @@ Search format... - + Rechercher le format… @@ -535,13 +541,13 @@ Stop recording video - Arrêter l'enregistrement vidéo + Arrêter l’enregistrement vidéo Start recording video - Démarrer l'enregistrement vidéo + Démarrer l’enregistrement vidéo @@ -562,37 +568,37 @@ Recording - + Audio - + Audio - + Video - + Vidéo - + Subtitle - + Sous-titre - - + + audio - + audio - - + + video - + vidéo - - + + subtitle - + sous-titre @@ -615,12 +621,13 @@ Bitrate - + Débit GOP - + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures + Groupe d’images (GOP) @@ -648,57 +655,57 @@ Notify about new versions - + Notifier les nouvelles versions Check new versions - + Vérifier les nouvelles versions Daily - + Quotidiennement Every two days - + Tous les deux jours Weekly - + Hebdomadairement Every two weeks - + Toutes les deux semaines Monthly - + Mensuellement Never - + Jamais Last updated - + Dernière mise à jour Your version of %1 is outdated. Latest version is <b>%2</b>. - + Votre version de %1 est périmée. La dernière version est <b>%2</b>. Upgrade Now! - + Mettez-vous à niveau ! @@ -708,7 +715,7 @@ Report a Bug - + Signaler une erreur @@ -737,32 +744,32 @@ New version available! - + Nouvelle version disponible ! Download %1 %2 NOW! - + Téléchargez %1 %2 maintenant ! Stop - + Arrêter Go back - + Retour Configure sources - + Configurer les sources Configure audio - + Configurer l’audio @@ -797,7 +804,7 @@ Add dust - + Ajouter de la poussière @@ -806,42 +813,43 @@ Radius - + Rayon N° of colors - + Nombre de couleurs Color difference - + Différence des couleurs Show edges - + Montrer les bordures Threshold low - + Seuil bas Threshold high - + Seuil élevé Line color - + Couleur de ligne - + + Scan block @@ -849,14 +857,15 @@ Choose a color - + Choisir une couleur Transform matrix - + https://en.wikipedia.org/wiki/Transformation_matrix + Matrice d’application linéaire @@ -865,37 +874,37 @@ Mode - + Mode Natural - + Naturel Fixed - + Fixe Symbols - + Symboles Font - + Police de caractères - + Search - Rechercher + Rechercher @@ -933,7 +942,8 @@ Style - + Different font rendering strategies + Style @@ -969,19 +979,19 @@ Quality - + Qualité Antialias - + Antialias No antialias - + Pas d’antialias @@ -1048,7 +1058,7 @@ Size - + Taille @@ -1056,7 +1066,7 @@ Color - + Couleur @@ -1078,96 +1088,99 @@ Old color - + Ancienne couleur New color - + Nouvelle couleur Select the color to replace - + Sélectionner la couleur à remplacer Select the new color - + Sélectionner la nouvelle couleur Color table - + Table des couleurs Base - + Base Metal - + Métal Heat - + https://en.wikipedia.org/wiki/Heat_map + Chaleur Old Photo - + Ancienne photo Red & Green - + Rouge & vert Sepia - + https://en.wikipedia.org/wiki/Sepia_(color) + Sépia X-Pro - + X-Pro X-Ray - + Rayon X Yellow & Blue - + Jaune & bleu - + Custom - + Personnalisé 16x16 bitmap... - + Topogramme binaire 16×16… - + Please choose an image file - + Veuillez choisir un fichier d’image Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1222,16 +1235,18 @@ N° of frames - + Nombre d’images Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1250,7 +1265,7 @@ Frequency - + Fréquence @@ -1275,6 +1290,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1306,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1315,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Œil - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1761,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1894,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1949,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2021,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,24 +2090,24 @@ - + Video format - + Resolution - + FPS Reset - + Réinitialiser @@ -2132,8 +2165,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2180,7 @@ Annuler - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/gl.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/gl.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/gl.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/gl.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/gl.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/gl.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/he.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/he.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/he.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/he.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/he.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/he.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description תיאור - - + + Device description תיאור התקן - - - + + + Device id מזהה התקן - + Sample Format תבנית לדוגמה - + Channels ערוצים - + Sample Rate קצב דגימה + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + השהיה (מילישניות) + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start להפעיל את המצלמה עם ההפעלה - + Enable advanced effects mode הפעלת מצב אפקטים מתקדם - + Frameworks & libraries סביבות הרצה וספריות - + Video capture לכידת וידאו - + Desktop capture לכידת שולחן עבודה - + Audio capture/play לכידה/נגינה של שמע - + Video convert המרת וידאו - + Audio convert המרת שמע - + Virtual camera driver מנהל התקן וירטואלי למצלמה - + Video playback נגינת וידאו - + Video record הקלטת וידאו - + Root method שיטת שורש @@ -372,7 +378,7 @@ MediaTools - + Daily Build מהדורה יומית @@ -562,35 +568,35 @@ Recording - + Audio שמע - + Video וידאו - + Subtitle כתובית - - + + audio שמע - - + + video וידאו - - + + subtitle כתובית @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block סריקת מקטע @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix טבלת התמרה @@ -892,7 +901,7 @@ - + Search חיפוש @@ -933,6 +942,7 @@ Style + Different font rendering strategies סגנון @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications בסיס @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map חום @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) ספיה @@ -1148,7 +1161,7 @@ - + Custom התאמה אישית @@ -1160,7 +1173,7 @@ - + Please choose an image file נא לבחור קובץ תמונה @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) טבלת פיתול @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) מו Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) סיגמא @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector מצב קני @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization השוואה @@ -1298,404 +1316,414 @@ היפוך - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature קובץ Haar - + Eye עין - + Eye glasses משקפיים - + Frontal face alternative 1 פנים מקדימה חלופה 1 - + Frontal face alternative 2 פנים מקדימה חלופה 2 - + Frontal face alternative 3 פנים מקדימה חלופה 3 - + Frontal face default פנים מקדימה כבררת מחדל - + Full body כל הגוף - + Left Eye 1 עין שמאל 1 - + Lower body פלג הגוף התחתון - + Eye pair big זוג עיניים גדול - + Eye pair small זוג עיניים קטן - + Left ear אוזן שמאל - + Left eye 2 עין שמאל 2 - + Mouth פה - + Nose אף - + Right ear אוזן ימין - + Right Eye 1 עין ימין 1 - + Upper body 1 פלג גוף עליון 1 - + Profile face פנים מהצד - + Right eye 2 עין ימין 2 - + Smile חיוך - + Upper body פלג גוף עליון - + Marker type סוג סמן - + Rectangle מרובע - + Ellipse אליפסה - + Image תמונה - + Pixelate טשטוש בפיקסלים - + Blur טשטוש - + + Blur Outer + + + + Marker style סוג סמן - + Solid אחיד - + Dash מקווקוו - + Dot מנוקד - + Dash dot קו נקודה - + Dash dot dot קו נקודה נקודה - + Marker color צבע סמן - + + Marker width עובי סמן - + Masks מסכות - + Angel מלאך - + Bear דוב - + Beaver בונה - + Cat חתול - + Chicken תרנגולת - + Cow פרה - + Devil שטן - + Dog כלב - + Dalmatian dog כלב דלמטי - + Happy dog כלב שמח - + Dragon דרקון - + Elephant 1 פיל 1 - + Elephant 2 פיל 2 - + Elk אייל - + Frog צפרדע - + Ghost רוח רפאים - + Giraffe ג׳ירפה - + Gnu גנו - + Goat עז - + Hippo היפופוטם - + Horse סוס - + Gray horse סוס אפור - + Koala קואלה - + Monkey קוף - + Gray mouse עכבר אפור - + White mouse עכבר לבן - + Panda פנדה - + Penguin פינגווין - + Pumpkin 1 דלעת 1 - + Pumpkin 2 דלעת 2 - + Raccoon דביבון - + Rhino קרנף - + Sheep כבשה - + Skull 1 גולגולת 1 - + Skull 2 גולגולת 2 - + Triceratops טריצרטופס - + Zebra זברה - + Marker picture תמונת סמן - - Replace face with this picture. - החלפת הפנים בתמונה זו. + + Replace face with this picture + - + + Pixel grid size גודל רשת פיקסלים - + + Blur radius רדיוס טשטוש - + Select marker color בחירת צבע סמן @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) סף תאורה Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image הפרשי שקיפות Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image הגוון שקיפות @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) סף תאורה Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton בחירת צבע האוטומטה @@ -1917,22 +1950,22 @@ הצגת מצביע - + Output format תסדיר פלט - + File extensions סיומות קבצים - + This output format has not specific extensions לתסדיר פלט זה אין סיומות קבצים מסוימות - + Advanced Format Options אפשרויות תסדיר מתקדמות @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image שקיפות יחסית @@ -2057,17 +2091,17 @@ חום - + Video format תסדיר וידאו - + Resolution רזולוציה - + FPS שקופיות לשנייה @@ -2132,9 +2166,9 @@ שם המצלמה (רשות) - - Error creating camera - שגיאה ביצירת המצלמה + + Error creating camera: + שגיאה ביצירת המצלמה: @@ -2147,7 +2181,7 @@ ביטול - + This system is not supported yet אין עדיין תמיכה במערכת הזו Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/it.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/it.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/it.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/it.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/it.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/it.ts 2021-02-15 15:25:23.000000000 +0000 @@ -6,27 +6,27 @@ About %1 - + Informazioni su %1 Information - + Informazioni Thanks! - + Ringraziamenti! License - + Licenza Version %1 - + Versione %1 @@ -36,27 +36,27 @@ Website - + Sito WEB Webcam capture application. - Applicazione per la cattura video da Webcam. + Applicazione per la cattura video da Webcam. A simple webcam application for picture and video capture. - + Una semplice applicazione per la cattura di foto e video da webcam. Thanks to all these cool people that helped contributing to Webcamoid all these years. - + Grazie a tutti coloro che hanno contribuito a Webcamoid in tutti questi anni. Close - + Chiudi @@ -112,7 +112,7 @@ Outputs - + Outputs @@ -122,7 +122,7 @@ Inputs - + Sorgenti @@ -133,71 +133,77 @@ Silence - + Silenzio AudioInfo - + Description - Descrizione + Descrizione - - + + Device description - + Descrizione dispositivo - - - + + + Device id - + id dispositivo - + Sample Format - + Formato del campione - + Channels - + Canali - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs Configure %1 - + Configura %1 Search option - + Ricerca Reset - + Resetta Cancel - Cancella + Annulla OK - + OK @@ -215,12 +221,12 @@ Plugins Configs - + Configurazioni Plugins Updates - + Aggiornamenti @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Avvia webcam all'apertura - + Enable advanced effects mode - + Abilita mdalità effetti avanzati - + Frameworks & libraries - + Frameworks e librerie - + Video capture - + Cattura video - + Desktop capture - + Cattura desktop - + Audio capture/play - + Audio cattura/riproduci - + Video convert - + Conversione video - + Audio convert - + Conversione audio - + Virtual camera driver - + Driver videocamera virtuale - + Video playback - + Riproduzione video - + Video record - + Registrazione video - + Root method @@ -333,7 +339,7 @@ No webcams found - + Webcam non trovata @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -382,7 +388,7 @@ Virtual camera - + Videocamera virtuale @@ -390,27 +396,27 @@ %1 seconds - + %1 secondi Now - + Adesso Cancel - Cancella + Annulla Shot! - + Scatta! Use flash - + Usa il flash @@ -418,17 +424,17 @@ Use this page for configuring the plugins search paths.<br /><b>Don't touch nothing unless you know what you are doing</b>. - + Usa questa pagina per configurare il percorso di ricerca dei plugins.<br /><b>Non modificare nulla a meno di non essere sicuro di ciò che fai</b>. Extra search paths - + Percorsi di ricerca aggiuntivi Search plugins in subfolders. - + Cerca i plugins nelle sottocartelle. @@ -443,27 +449,27 @@ Plugins list - + Lista di plugins Refresh - + Aggiorna Disable - + Disabilita Enable - + Abilita Add plugins search path - + Aggiugi percorso di ricerca dei plugins @@ -476,17 +482,17 @@ Load settings from PATH. If PATH is empty, load configs from application directory. - + Carica impostazioni dal Percorso. Se il Percorso è vuoto, carica le configurazioni dalla directory dell'applicazione. PATH - + PERCORSO Semi-colon separated list of paths to search the Qml interface. - + Lista separata da punto evirgola dei percorsi in cui cercare l'interfaccia Qml. @@ -494,27 +500,27 @@ PATH1;PATH2;PATH3;... - + PERCORSO1;PERCORSO2;... Search in the specified plugins paths recursively. - + Cerca ricorsivamente nei percorsi per i plugins ricorsivamente. Semi-colon separated list of paths to search for plugins. - + Lista separata da punto evirgola dei percorsi in cui cercare i plugins. Semi-colon separated list of paths to avoid loading. - + Lista separata da punto evirgola dei percorsi da cui non caricare. Semi-colon separated list of paths to search for virtual camera driver - + Lista separata da punto evirgola dei percorsi in cui cercare driver della webcam virtuale @@ -522,7 +528,7 @@ Search format... - + Cerca formato... @@ -562,37 +568,37 @@ Recording - + Audio - + Audio - + Video - + Video - + Subtitle - + Sottotitolo - - + + audio - + audio - - + + video - + video - - + + subtitle - + sottotitolo @@ -620,27 +626,28 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures Separation between keyframes - + Separazione tra keyframes Advanced Codec Options - + Opzioni avanzate Codec Size of the audio (bits) / duration (seconds) - + Dimensione dell'audio (bits) / durata (secondi) Size of the video (bits) / duration (seconds) - + Dimensione del video (bits) / durata (secondi) @@ -648,67 +655,67 @@ Notify about new versions - + Notifica per nuove versioni Check new versions - + Ricerca nuove versioni Daily - + Giornalmente Every two days - + Ogni due giorni Weekly - + Settimanalmente Every two weeks - + Ogni due settimane Monthly - + Mensilmente Never - + Mai Last updated - + Ultimo aggiornamento Your version of %1 is outdated. Latest version is <b>%2</b>. - + La tua versione di %1 è obsoleta. Ultima versione <b>%2</b>. Upgrade Now! - + Aggiorna ora! Thanks for using a <b>development version</b>!<br />It will be very helpful if you can report any bug and suggestions you have. - + Grazie per l'uso di una <b>versione di sviluppo</b><br />Sarebbe molto utile se riportassi tutti i bug ed i tuoi suggerimenti. Report a Bug - + Segnala un Bug @@ -737,7 +744,7 @@ New version available! - + Nuova versione disponibile! @@ -747,22 +754,22 @@ Stop - + Ferma Go back - + Indietro Configure sources - + Configura sorgenti Configure audio - + Caonfigura audio @@ -812,7 +819,7 @@ N° of colors - + Numero di colori @@ -841,7 +848,8 @@ - + + Scan block @@ -849,13 +857,14 @@ Choose a color - + Scegli un colore Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -865,23 +874,23 @@ Mode - + Modo Natural - + Naturale Fixed - + Fisso Symbols - + Simboli @@ -892,7 +901,7 @@ - + Search Cerca @@ -933,7 +942,8 @@ Style - + Different font rendering strategies + Stile @@ -945,7 +955,7 @@ Device - + Dispositivo @@ -969,7 +979,7 @@ Quality - + Qualità @@ -987,7 +997,7 @@ Compatible with OpenGL - + Compatibile con OpenGL @@ -1018,7 +1028,7 @@ Background color - + Colore sfondo @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1222,16 +1236,18 @@ N° of frames - + N° di frames Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1255,12 +1271,12 @@ Grid size - + Dimensione griglia Speed - + Velocità @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1914,57 +1947,57 @@ Show cursor - + Mostra cursore - + Output format - + Formato Uscita - + File extensions - + Estensioni file - + This output format has not specific extensions - + Questo formato non ha estensioni specifiche - + Advanced Format Options - + Opzioni Avanzate Formato Video track - + Traccia video Audio track - + Traccia audio Subtitles track - + Traccia sottotitoli Simple - + Semplice Brightness - + Luminosità Contrast - + Contrasto @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -1999,7 +2033,7 @@ Motion detect - + Rileva movimento @@ -2054,37 +2088,37 @@ Temperature - + Temperatura - + Video format - + Formato video - + Resolution - + Risoluzione - + FPS - + FPS Reset - + Resetta Aspect - + Aspetto Scale - + Scala @@ -2099,7 +2133,7 @@ Devices - + Dispositivi @@ -2119,7 +2153,7 @@ Remove All - + Rimuovi Tutto @@ -2129,11 +2163,11 @@ Camera name (optional) - + Nome videocamera (opzionale) - - Error creating camera + + Error creating camera: @@ -2147,9 +2181,9 @@ Cancella - + This system is not supported yet - + Questo sistema non è ancora supportato Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/ja.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/ja.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/ja.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/ja.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/ja.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/ja.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description 説明 - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search サーチ @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ キャンセル - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/kab.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/kab.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/kab.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/kab.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/kab.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/kab.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/ko.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/ko.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/ko.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/ko.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/ko.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/ko.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description 설명 - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search 검색 @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ 취소 - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/nb_NO.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/nb_NO.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/nb_NO.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/nb_NO.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/nb_NO.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/nb_NO.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + Latens (ms) + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver Virtuell kameradriver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build Dagsbygg @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,7 +626,8 @@ GOP - + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures + Bildegruppe @@ -841,7 +848,8 @@ - + + Scan block Skann blokk @@ -856,7 +864,8 @@ Transform matrix - + https://en.wikipedia.org/wiki/Transformation_matrix + Transformasjonsmatrise @@ -892,7 +901,7 @@ - + Search Søk @@ -933,6 +942,7 @@ Style + Different font rendering strategies Stil @@ -1104,7 +1114,8 @@ Base - + Base color, show the image without modifications + Grunnfarge @@ -1114,7 +1125,8 @@ Heat - + https://en.wikipedia.org/wiki/Heat_map + Fargediagram @@ -1129,7 +1141,8 @@ Sepia - + https://en.wikipedia.org/wiki/Sepia_(color) + Sepia @@ -1139,7 +1152,7 @@ X-Ray - + Røntgen @@ -1148,7 +1161,7 @@ - + Custom Egendefinert @@ -1160,7 +1173,7 @@ - + Please choose an image file Velg ei bildefil @@ -1168,7 +1181,8 @@ Convolve matrix - + https://en.wikipedia.org/wiki/Kernel_(image_processing) + Foldingsmatrise @@ -1227,12 +1241,14 @@ Mu - + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) + Aritmetisk gjennomsnitt (Mu) Sigma - + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) + Standardavvik (Sigma) @@ -1275,21 +1291,23 @@ Canny mode - + https://en.wikipedia.org/wiki/Canny_edge_detector + Canny-modus Lower Canny threshold - + Nedre Canny-terskel Higger Canny threshold - + Øvre Canny-terskel Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,406 +1316,416 @@ Inverter - + Haar file - + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature + Haar-fil - + Eye - + Øye - + Eye glasses Briller - + Frontal face alternative 1 Frontalfjes-alternativ 1 - + Frontal face alternative 2 Frontalfjes-alternativ 2 - + Frontal face alternative 3 Frontalfjes-alternativ 3 - + Frontal face default Frontalfjes-forvalg - + Full body Full kropp - + Left Eye 1 Venstre øye - + Lower body Underkropp - + Eye pair big Øyepar store - + Eye pair small Øyepar små - + Left ear Venstre øre - + Left eye 2 Venstre øye 2 - + Mouth Munn - + Nose Nese - + Right ear Høyre øye - + Right Eye 1 Høyre øye 1 - + Upper body 1 Overkropp 1 - + Profile face Ansikt i profil - + Right eye 2 Høyre øye 2 - + Smile Smil - + Upper body Overkropp - + Marker type - + Markørtype - + Rectangle Rektangel - + Ellipse Ellipse - + Image Bilde - + Pixelate Pikseler - + Blur + Tilsløring + + + + Blur Outer - + Marker style - + Markørstil - + Solid - + Dash - + Bindestrek - + Dot - + Punktum - + Dash dot - + Bindestrek og punktum - + Dash dot dot - + Bindestrek punktum punktum - + Marker color - + Markørfarge - + + Marker width - + Masks - + Masker - + Angel Engel - + Bear Bjørn - + Beaver Bever - + Cat Katt - + Chicken Kylling - + Cow Ku - + Devil Djevel - + Dog Hund - + Dalmatian dog Dalmatiner - + Happy dog Glad hund - + Dragon Drage - + Elephant 1 Elefant 1 - + Elephant 2 Elefant 2 - + Elk Elg - + Frog Frosk - + Ghost Spøkelse - + Giraffe Giraff - + Gnu Gnu - + Goat Gjeit - + Hippo Flodhest - + Horse Hest - + Gray horse Grå hest - + Koala Koalabjørn - + Monkey Apekatt - + Gray mouse Grå mus - + White mouse Hvit mus - + Panda Panda - + Penguin Pingvin - + Pumpkin 1 Gresskar 1 - + Pumpkin 2 Gresskar 2 - + Raccoon Vaskebjørn - + Rhino Neshorn - + Sheep Sau - + Skull 1 Hodeskalle 1 - + Skull 2 Hodeskalle 2 - + Triceratops - + Zebra Sebra - + Marker picture - + Markørbilde - - Replace face with this picture. - Erstatt ansikt med dette bildet. + + Replace face with this picture + - + + Pixel grid size - + Pikselrutenettsstørrelse - + + Blur radius - + Tilsløringsradius - + Select marker color - + Velg markørfarge @@ -1712,7 +1740,7 @@ Dissolve - + Oppløs @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ Vis peker - + Output format Utdataformat - + File extensions Filutvidelser - + This output format has not specific extensions - + Advanced Format Options Avanserte formateringsvalg @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,19 +2091,19 @@ Temperatur - + Video format Videoformat - + Resolution Oppløsning - + FPS - + BPS @@ -2132,8 +2166,8 @@ Kameranavn (valgfritt) - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ Avbryt - + This system is not supported yet Dette systemet støttes ikke enda Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/nl.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/nl.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/nl.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/nl.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/nl.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/nl.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description Omschrijving - - + + Device description Apparaatomschrijving - - - + + + Device id Apparaat-ID - + Sample Format Sampleformaat - + Channels Kanalen - + Sample Rate Samplesnelheid + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + Vertraging (ms) + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start Webcam afspelen bij opstarten - + Enable advanced effects mode Geavanceerde effectenmodus inschakelen - + Frameworks & libraries Frameworks en bibliotheken - + Video capture Videovastlegging - + Desktop capture Bureaubladvastlegging - + Audio capture/play Audiovastlegging/afspelen - + Video convert Videoconvertering - + Audio convert Audioconvertering - + Virtual camera driver Virtueel camerastuurprogramma - + Video playback Video afspelen - + Video record Video opnemen - + Root method Rootmethode @@ -372,7 +378,7 @@ MediaTools - + Daily Build Dagelijkse ontwikkelingsversie @@ -562,35 +568,35 @@ Recording - + Audio Audio - + Video Video - + Subtitle Ondertiteling - - + + audio audio - - + + video video - - + + subtitle ondertiteling @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures GOP @@ -841,7 +848,8 @@ - + + Scan block Blok scannen @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix Matrix transformeren @@ -892,7 +901,7 @@ - + Search Zoeken @@ -933,6 +942,7 @@ Style + Different font rendering strategies Stijl @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications Basis @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map Hitte @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) Sepia @@ -1148,7 +1161,7 @@ - + Custom Aangepast @@ -1160,7 +1173,7 @@ - + Please choose an image file Kies een afbeeldingsbestand @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) Matrix samenspannen @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Mu Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) Sigma @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector Canny-modus @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization Egaliseren @@ -1298,404 +1316,414 @@ Omkeren - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature Haar-bestand - + Eye Oog - + Eye glasses Bril - + Frontal face alternative 1 Voorkant van gezicht - alternatief 1 - + Frontal face alternative 2 Voorkant van gezicht - alternatief 2 - + Frontal face alternative 3 Voorkant van gezicht - alternatief 3 - + Frontal face default Voorkant van gezicht - standaard - + Full body Gehele lichaam - + Left Eye 1 Linkeroog 1 - + Lower body Romp - + Eye pair big Ogen - groot - + Eye pair small Ogen - klein - + Left ear Linkeroor - + Left eye 2 Linkeroog 2 - + Mouth Mond - + Nose Neus - + Right ear Rechteroor - + Right Eye 1 Rechteroog 1 - + Upper body 1 Torso 1 - + Profile face Gezichtsprofiel - + Right eye 2 Rechteroog 2 - + Smile Lach - + Upper body Torso - + Marker type Soort markering - + Rectangle Rechthoek - + Ellipse Ovaal - + Image Afbeelding - + Pixelate Pixelachtig - + Blur Vervagen - + + Blur Outer + + + + Marker style Markeerstijl - + Solid Vast - + Dash Streepjes - + Dot Puntjes - + Dash dot Streepjes en puntjes - + Dash dot dot Streepje-punt-punt - + Marker color Markeerkleur - + + Marker width Markeerbreedte - + Masks Verhullingen - + Angel Engel - + Bear Beer - + Beaver Bever - + Cat Kat - + Chicken Kip - + Cow Koe - + Devil Duivel - + Dog Hond - + Dalmatian dog Dalmatiër - + Happy dog Blije hond - + Dragon Draak - + Elephant 1 Olifant 1 - + Elephant 2 Olifant 2 - + Elk Eland - + Frog Kikker - + Ghost Spook - + Giraffe Giraffe - + Gnu Gnoe - + Goat Geit - + Hippo Nijlpaard - + Horse Paard - + Gray horse Grijs paard - + Koala Koalabeer - + Monkey Aap - + Gray mouse Grijze muis - + White mouse Witte muis - + Panda Pandabeer - + Penguin Pinguïn - + Pumpkin 1 Pompoen 1 - + Pumpkin 2 Pompoen 2 - + Raccoon Wasbeer - + Rhino Neushoorn - + Sheep Schaap - + Skull 1 Schedel 1 - + Skull 2 Schedel 2 - + Triceratops Triceratops - + Zebra Zebra - + Marker picture Markeerafbeelding - - Replace face with this picture. - Vervang gezichten door deze afbeelding. + + Replace face with this picture + - + + Pixel grid size Grootte van pixelraster - + + Blur radius Vervaagstraal - + Select marker color Kies markeerkleur @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Luma-drempelwaarde Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alfa-verschil Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image Alfa-variatie @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Luma-drempelwaarde Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton Kies de automata-kleur @@ -1917,22 +1950,22 @@ Cursor tonen - + Output format Uitvoerformaat - + File extensions Bestandsextensies - + This output format has not specific extensions Dit uitvoerformaat kent geen specifieke extensies - + Advanced Format Options Geavanceerde formaatopties @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image Alfa-verschil @@ -2057,17 +2091,17 @@ Temperatuur - + Video format Videoformaat - + Resolution Resolutie - + FPS FPS @@ -2132,9 +2166,9 @@ Cameranaam (optioneel) - - Error creating camera - Fout bij creëren van camera + + Error creating camera: + Fout bij openen van camera: @@ -2147,7 +2181,7 @@ Annuleren - + This system is not supported yet Dit systeem wordt nog niet ondersteund Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/pl.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/pl.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/pl.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/pl.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/pl.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/pl.ts 2021-02-15 15:25:23.000000000 +0000 @@ -6,37 +6,37 @@ About %1 - + O %1 Information - + Informacja Thanks! - + Dziękuję! License - + Licencja Version %1 - + Wersja %1 Using Qt %1 - + Używane Qt %1 Website - + Strona Domowa @@ -46,17 +46,17 @@ A simple webcam application for picture and video capture. - + Prosta aplikacja do przechwytywania zdjęć i filmów. Thanks to all these cool people that helped contributing to Webcamoid all these years. - + Dzięki tym wszystkim fajnym ludziom, którzy przyczynili się do powstania Webcamoid przez te wszystkie lata. Close - + Zamknij @@ -139,38 +139,44 @@ AudioInfo - + Description - - + + Device description Opis urządzenia - - - + + + Device id Identyfikator urzadzenia - + Sample Format Przykładowy format - + Channels Kanały - + Sample Rate Częstotliwość próbkowania + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + Opóźnienie (ms) + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start Uruchom kamerę internetową przy starcie - + Enable advanced effects mode Włącz zaawansowany tryb efektów - + Frameworks & libraries Struktura i biblioteki - + Video capture Przechwytywanie wideo - + Desktop capture Przechwytywanie pulpitu - + Audio capture/play Przechwytywanie/odtwarzanie dźwięku - + Video convert Konwersja wideo - + Audio convert Konwersja audio - + Virtual camera driver - + Sterownik kamery wirtualnej - + Video playback Odtwarzanie wideo - + Video record Nagrywanie wideo - + Root method Metoda korzeniowa @@ -372,9 +378,9 @@ MediaTools - + Daily Build - + Codzienna kompilacja @@ -481,7 +487,7 @@ PATH - + ŚCIEŻKA @@ -494,7 +500,7 @@ PATH1;PATH2;PATH3;... - + ŚCIEŻKA1;ŚCIEŻKA2;ŚCIEŻKA3;... @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle Napisy - - + + audio - - + + video - - + + subtitle napisy @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block Skanuj blok @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix Przekształcenie macierzy @@ -892,7 +901,7 @@ - + Search Szukaj @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications Podstawy @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map Ciepły @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom Niestandardowe @@ -1160,7 +1173,7 @@ - + Please choose an image file Wybierz plik obrazu @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) Rozmywanie/Wyostrzanie matrix @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector Tryb Canny @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization Wyrównanie @@ -1298,404 +1316,414 @@ Odwróć - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature Jej plik - + Eye Oko - + Eye glasses Okulary do oczu - + Frontal face alternative 1 Portrety twarzy alternatywnych 1 - + Frontal face alternative 2 Portrety twarzy 2 alternatywne - + Frontal face alternative 3 Portrety twarzy 3 alternatywne - + Frontal face default Domyślne portrety twarzy - + Full body Całe ciało - + Left Eye 1 Lewe oko 1 - + Lower body Dolne części ciała - + Eye pair big Duża para oczu - + Eye pair small Mała para oczu - + Left ear Lewe ucho - + Left eye 2 Lewe oko 2 - + Mouth Usta - + Nose Nos - + Right ear Prawe ucho - + Right Eye 1 Prawe Oko 1 - + Upper body 1 Górna część ciała 1 - + Profile face Profil twarzy - + Right eye 2 Prawe oko 2 - + Smile Uśmiech - + Upper body Górna część ciała - + Marker type Typ znacznika - + Rectangle Prostokąt - + Ellipse Elipsa - + Image - + Pixelate Pikslowanie - + Blur Rozmycie - + + Blur Outer + + + + Marker style Styl znacznika - + Solid Pełny - + Dash Kreska - + Dot Kropka - + Dash dot Kreska kropka - + Dash dot dot Kreska kropka kropka - + Marker color Kolor znacznika - + + Marker width Szerokość znacznika - + Masks Maska - + Angel Anioł - + Bear Niedźwiedź - + Beaver Bóbr - + Cat Kot - + Chicken Kurczak - + Cow Krowa - + Devil Diabeł - + Dog Pies - + Dalmatian dog Pies dalmatyńczyk - + Happy dog Szczęśliwy pies - + Dragon Smok - + Elephant 1 Słoń 1 - + Elephant 2 Słoń 2 - + Elk Każdy - + Frog Żaba - + Ghost Duch - + Giraffe Żyrafa - + Gnu - + Goat Koziorożec - + Hippo Hipopotam - + Horse Koń - + Gray horse Szary koń - + Koala - + Monkey Małpa - + Gray mouse Szara myszka - + White mouse Biała myszka - + Panda - + Penguin Pingwin - + Pumpkin 1 Dynia 1 - + Pumpkin 2 Dynia 2 - + Raccoon Szop - + Rhino Nosorożec - + Sheep Owca - + Skull 1 Czaszka 1 - + Skull 2 Czaszka 2 - + Triceratops - + Zebra - + Marker picture Zdjęcie znacznika - - Replace face with this picture. - Zastąp twarz tym obrazem. + + Replace face with this picture + - + + Pixel grid size Rozmiar siatki pikseli - + + Blur radius Promień rozmycia - + Select marker color Wybierz kolor znacznika @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Próg Luma Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image Odmiana alfa @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Próg Luma Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton Wybierz kolor automatów @@ -1917,22 +1950,22 @@ Pokaż kursor - + Output format - + File extensions Rozszerzenia plików - + This output format has not specific extensions Ten format wyjściowy nie ma określonych rozszerzeń - + Advanced Format Options Zaawansowane opcje formatu @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image Różnica alfa @@ -2057,17 +2091,17 @@ Temperatura - + Video format - + Resolution Rozdzielczość - + FPS @@ -2132,9 +2166,9 @@ Nazwa kamery (opcjonalnie) - - Error creating camera - + + Error creating camera: + Błąd tworzenia kamery: @@ -2147,7 +2181,7 @@ Anuluj - + This system is not supported yet Ten system nie jest jeszcze obsługiwany Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/pt_BR.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/pt_BR.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/pt_BR.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/pt_BR.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/pt_BR.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/pt_BR.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/pt.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/pt.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/pt.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/pt.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/pt.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/pt.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description Descrição - - + + Device description Descrição do dispositivo - - - + + + Device id Identificador do dispositivo - + Sample Format Formato de amostra - + Channels Canais - + Sample Rate Rácio da amostra + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + Latência (ms) + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start Ligar a câmara web ao iniciar - + Enable advanced effects mode Ativar modo de efeitos avançados - + Frameworks & libraries Frameworks e bibliotecas - + Video capture Captura de vídeo - + Desktop capture Captura do ambiente de trabalho - + Audio capture/play Captura / reprodução do áudio - + Video convert Conversão do vídeo - + Audio convert Conversão do áudio - + Virtual camera driver Controlador da câmara virtual - + Video playback Reprodução do vídeo - + Video record Gravação de vídeo - + Root method Método de root @@ -351,7 +357,7 @@ Media UID - + UID de media @@ -372,7 +378,7 @@ MediaTools - + Daily Build Compilação diária @@ -562,35 +568,35 @@ Recording - + Audio Áudio - + Video Vídeo - + Subtitle Legenda - - + + audio áudio - - + + video vídeo - - + + subtitle legenda @@ -620,7 +626,8 @@ GOP - + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures + GOP @@ -841,9 +848,10 @@ - + + Scan block - + Bloco de digitalização @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix Matriz de transformação @@ -892,7 +901,7 @@ - + Search Pesquisar @@ -901,7 +910,7 @@ Hinting - + Sugestão @@ -915,24 +924,25 @@ No hinting - + Sem sugestão Vertical hinting - + Sugestão vertical Full hinting - + Sugestão completa Style + Different font rendering strategies Estilo @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications Base @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map Calor @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) Sépia @@ -1148,7 +1161,7 @@ - + Custom Personalizado @@ -1160,7 +1173,7 @@ - + Please choose an image file Por favor escolha um ficheiro de imagem @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) Matriz de convolver @@ -1197,17 +1211,17 @@ Vertical increase - + Aumento vertical Horizontal increase - + Aumento horizontal Rings increase - + Aumento de anéis @@ -1227,12 +1241,14 @@ Mu - + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) + Mu Sigma - + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) + Sigma @@ -1275,21 +1291,23 @@ Canny mode - + https://en.wikipedia.org/wiki/Canny_edge_detector + Modo Canny Lower Canny threshold - + Limiar inferior do Canny Higger Canny threshold - + Limiar superior do Canny Equalize + https://en.wikipedia.org/wiki/Histogram_equalization Equalizar @@ -1298,404 +1316,414 @@ Inverter - + Haar file - + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature + Ficheiro Haar - + Eye Olho - + Eye glasses - + Óculos dos olhos - + Frontal face alternative 1 Face frontal alternativa 1 - + Frontal face alternative 2 Face frontal alternativa 2 - + Frontal face alternative 3 Face frontal alternativa 3 - + Frontal face default Face frontal padrão - + Full body Corpo inteiro - + Left Eye 1 Olho esquerdo 1 - + Lower body Parte de baixo do corpo - + Eye pair big Par de olhos grande - + Eye pair small Par de olhos pequeno - + Left ear Orelha esquerda - + Left eye 2 Olho esquerdo 2 - + Mouth Boca - + Nose Nariz - + Right ear Orelha direira - + Right Eye 1 Olho direito 1 - + Upper body 1 Parte de cima do corpo 1 - + Profile face Face de perfil - + Right eye 2 Olho direito 2 - + Smile Sorriso - + Upper body Parte de cima do corpo - + Marker type Tipo de marcador - + Rectangle Retângulo - + Ellipse Elipse - + Image Imagem - + Pixelate Pixelizar - + Blur Desfocar - + + Blur Outer + + + + Marker style Estilo de marcador - + Solid Sólido - + Dash Traço - + Dot Ponto - + Dash dot Traço ponto - + Dash dot dot Traço ponto ponto - + Marker color Cor do marcador - + + Marker width Espessura do marcador - + Masks Máscaras - + Angel Anjo - + Bear Urso - + Beaver Castor - + Cat Gato - + Chicken Galinha - + Cow Vaca - + Devil Diabo - + Dog Cão - + Dalmatian dog Cão dálmata - + Happy dog Cão feliz - + Dragon Dragão - + Elephant 1 Elefante 1 - + Elephant 2 Elefante 2 - + Elk Alce - + Frog - + Ghost Fantasma - + Giraffe Girafa - + Gnu Gnu - + Goat Cabra - + Hippo Hipopótamo - + Horse Cavalo - + Gray horse Cavalo cinzento - + Koala Coala - + Monkey Macaco - + Gray mouse Rato cinzento - + White mouse Rato branco - + Panda Panda - + Penguin Pinguim - + Pumpkin 1 Abóbora 1 - + Pumpkin 2 Abóbora 2 - + Raccoon Guaxinim - + Rhino Rinoceronte - + Sheep Ovelha - + Skull 1 Caveira 1 - + Skull 2 Caveira 2 - + Triceratops Tricerátops - + Zebra Zebra - + Marker picture Marcador de imagem - - Replace face with this picture. - Substituir face por esta imagem. + + Replace face with this picture + - + + Pixel grid size Tamanho da grelha do píxel - + + Blur radius Raio da desfocagem - + Select marker color Selecionar cor do marcador @@ -1734,22 +1762,25 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Limiar de luminância Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Diferença de alfa Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image Variação de alfa Stride - + Passo @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Limiar de luminância Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton Escolher a cor do autómata @@ -1917,22 +1950,22 @@ Mostrar cursor - + Output format Formato de saída - + File extensions Extensões de ficheiros - + This output format has not specific extensions Este formato de saída não tem extensões específicas - + Advanced Format Options Opções de formato avançado @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image Diferencial alfa @@ -2057,17 +2091,17 @@ Temperatura - + Video format Formato do vídeo - + Resolution Resolução - + FPS FPS @@ -2132,9 +2166,9 @@ Nome da câmara (opcional) - - Error creating camera - Erro ao criar a câmara + + Error creating camera: + Erro ao criar a câmera: @@ -2147,7 +2181,7 @@ Cancelar - + This system is not supported yet Este sistema ainda não é suportado Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/ru.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/ru.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/ru.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/ru.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/ru.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/ru.ts 2021-02-15 15:25:23.000000000 +0000 @@ -11,17 +11,17 @@ Information - + Информация Thanks! - + Спасибо! License - + Лицензия @@ -36,7 +36,7 @@ Website - + Сайт @@ -56,7 +56,7 @@ Close - + Закрыть @@ -64,37 +64,37 @@ Add new media - + Добавить медиа Description - + Описание Insert media description - + Добавить описание "медиа" Media file - + Медиа файл Select media file - + Выбрать медиа файл Search - + Поиск Ok - + Потвердить @@ -139,38 +139,44 @@ AudioInfo - + Description - + Описание - - + + Device description - - - + + + Device id - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -247,7 +253,7 @@ Description - + Описание @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -341,12 +347,12 @@ Description - + Описание Insert media description - + Добавить описание "медиа" @@ -356,7 +362,7 @@ Select media file - + Выбрать медиа файл @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -546,7 +552,7 @@ Description - + Описание @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,10 +901,10 @@ - + Search - + Поиск @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2124,7 +2158,7 @@ Description - + Описание @@ -2132,14 +2166,14 @@ - - Error creating camera + + Error creating camera: Ok - + Потвердить @@ -2147,7 +2181,7 @@ - + This system is not supported yet Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/tr.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/tr.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/tr.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/tr.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/tr.ts 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/tr.ts 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,2199 @@ + + + + + About + + + About %1 + + + + + Information + + + + + Thanks! + + + + + License + + + + + Version %1 + + + + + Using Qt %1 + + + + + Website + + + + + Webcam capture application. + + + + + A simple webcam application for picture and video capture. + + + + + Thanks to all these cool people that helped contributing to Webcamoid all these years. + + + + + Close + + + + + AddMedia + + + Add new media + + + + + Description + + + + + Insert media description + + + + + Media file + + + + + Select media file + + + + + Search + + + + + Ok + + + + + Cancel + + + + + Choose the file to add as media + + + + + AudioConfig + + + Outputs + + + + + Select the output device for audio playing + + + + + Inputs + + + + + Select the device for audio capturing + + + + + + Silence + + + + + AudioInfo + + + Description + + + + + + Device description + + + + + + + Device id + + + + + Sample Format + + + + + Channels + + + + + Sample Rate + + + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + + + + CodecConfigs + + + Configure %1 + + + + + Search option + + + + + Reset + + + + + Cancel + + + + + OK + + + + + ConfigBar + + + Output + + + + + General Options + + + + + Plugins Configs + + + + + Updates + + + + + EffectBar + + + Search effect... + + + + + None + + + + + EffectConfig + + + + Plugin id + + + + + Description + + + + + Plugin description + + + + + Remove + + + + + Add + + + + + GeneralConfig + + + Play webcam on start + + + + + Enable advanced effects mode + + + + + Frameworks & libraries + + + + + Video capture + + + + + Desktop capture + + + + + Audio capture/play + + + + + Video convert + + + + + Audio convert + + + + + Virtual camera driver + + + + + Video playback + + + + + Video record + + + + + Root method + + + + + MediaBar + + + No webcams found + + + + + MediaConfig + + + Description + + + + + Insert media description + + + + + Media UID + + + + + Select media file + + + + + Edit + + + + + Remove + + + + + MediaTools + + + Daily Build + + + + + OutputConfig + + + Virtual camera + + + + + PhotoWidget + + + %1 seconds + + + + + Now + + + + + Cancel + + + + + Shot! + + + + + Use flash + + + + + PluginConfig + + + Use this page for configuring the plugins search paths.<br /><b>Don't touch nothing unless you know what you are doing</b>. + + + + + Extra search paths + + + + + Search plugins in subfolders. + + + + + Add + + + + + Remove + + + + + Plugins list + + + + + Refresh + + + + + Disable + + + + + Enable + + + + + Add plugins search path + + + + + QObject + + + Webcam capture application. + + + + + Load settings from PATH. If PATH is empty, load configs from application directory. + + + + + PATH + + + + + Semi-colon separated list of paths to search the Qml interface. + + + + + + + + PATH1;PATH2;PATH3;... + + + + + Search in the specified plugins paths recursively. + + + + + Semi-colon separated list of paths to search for plugins. + + + + + Semi-colon separated list of paths to avoid loading. + + + + + Semi-colon separated list of paths to search for virtual camera driver + + + + + RecordBar + + + Search format... + + + + + RecordConfig + + + Video %1.%2 + + + + + Stop recording video + + + + + + Start recording video + + + + + Description + + + + + Insert format description + + + + + Save video as... + + + + + Recording + + + Audio + + + + + Video + + + + + Subtitle + + + + + + audio + + + + + + video + + + + + + subtitle + + + + + StreamOptions + + + Stream #%1 (%2) + + + + + Stream #%1 + + + + + Codec + + + + + Bitrate + + + + + GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures + + + + + Separation between keyframes + + + + + Advanced Codec Options + + + + + Size of the audio (bits) / duration (seconds) + + + + + Size of the video (bits) / duration (seconds) + + + + + UpdatesConfig + + + Notify about new versions + + + + + Check new versions + + + + + Daily + + + + + Every two days + + + + + Weekly + + + + + Every two weeks + + + + + Monthly + + + + + Never + + + + + Last updated + + + + + Your version of %1 is outdated. Latest version is <b>%2</b>. + + + + + Upgrade Now! + + + + + Thanks for using a <b>development version</b>!<br />It will be very helpful if you can report any bug and suggestions you have. + + + + + Report a Bug + + + + + main + + + Recording + + + + + + Play + + + + + Take a photo + + + + + Picture %1.%2 + + + + + New version available! + + + + + Download %1 %2 NOW! + + + + + Stop + + + + + Go back + + + + + Configure sources + + + + + Configure audio + + + + + Record video + + + + + Configure Effects + + + + + Preferences + + + + + About + + + + + Save photo as... + + + + + Number of scratches + + + + + Add dust + + + + + + + + + Radius + + + + + + N° of colors + + + + + Color difference + + + + + Show edges + + + + + Threshold low + + + + + Threshold high + + + + + Line color + + + + + + + Scan block + + + + + + Choose a color + + + + + + + Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix + + + + + + + + + Mode + + + + + Natural + + + + + Fixed + + + + + + Symbols + + + + + + Font + + + + + + + + Search + + + + + + Hinting + + + + + + + + Default + + + + + + No hinting + + + + + + Vertical hinting + + + + + + Full hinting + + + + + + Style + Different font rendering strategies + + + + + + Bitmap + + + + + + Device + + + + + + Outline + + + + + + Force outline + + + + + + Match + + + + + + Quality + + + + + + Antialias + + + + + + No antialias + + + + + + Compatible with OpenGL + + + + + + Force integer metrics + + + + + + No subpixel antialias + + + + + + No font merging + + + + + + Foreground color + + + + + + + Background color + + + + + Reversed + + + + + + Please choose a font + + + + + + Choose the foreground color + + + + + + + Choose the background color + + + + + + Size + + + + + + + + Color + + + + + Choose the strips color + + + + + + + Soft + + + + + Select the color to filter + + + + + Old color + + + + + New color + + + + + Select the color to replace + + + + + Select the new color + + + + + + Color table + + + + + Base + Base color, show the image without modifications + + + + + Metal + + + + + Heat + https://en.wikipedia.org/wiki/Heat_map + + + + + Old Photo + + + + + Red & Green + + + + + Sepia + https://en.wikipedia.org/wiki/Sepia_(color) + + + + + X-Pro + + + + + X-Ray + + + + + Yellow & Blue + + + + + + + Custom + + + + + 16x16 bitmap... + + + + + + + Please choose an image file + + + + + Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) + + + + + + + + Factor + + + + + + Bias + + + + + Grab mode + + + + + Random square + + + + + Vertical increase + + + + + Horizontal increase + + + + + Rings increase + + + + + + Block size + + + + + + + + + N° of frames + + + + + Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) + + + + + Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) + + + + + Frame rate + + + + + + + Amplitude + + + + + + Frequency + + + + + Grid size + + + + + Speed + + + + + Zoom rate + + + + + Strength + + + + + Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector + + + + + Lower Canny threshold + + + + + Higger Canny threshold + + + + + Equalize + https://en.wikipedia.org/wiki/Histogram_equalization + + + + + Invert + + + + + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature + + + + + Eye + + + + + Eye glasses + + + + + Frontal face alternative 1 + + + + + Frontal face alternative 2 + + + + + Frontal face alternative 3 + + + + + Frontal face default + + + + + Full body + + + + + Left Eye 1 + + + + + Lower body + + + + + Eye pair big + + + + + Eye pair small + + + + + Left ear + + + + + Left eye 2 + + + + + Mouth + + + + + Nose + + + + + Right ear + + + + + Right Eye 1 + + + + + Upper body 1 + + + + + Profile face + + + + + Right eye 2 + + + + + Smile + + + + + Upper body + + + + + Marker type + + + + + Rectangle + + + + + Ellipse + + + + + Image + + + + + Pixelate + + + + + + + Blur + + + + + Blur Outer + + + + + Marker style + + + + + Solid + + + + + Dash + + + + + Dot + + + + + Dash dot + + + + + Dash dot dot + + + + + Marker color + + + + + + Marker width + + + + + Masks + + + + + Angel + + + + + Bear + + + + + Beaver + + + + + Cat + + + + + Chicken + + + + + Cow + + + + + Devil + + + + + Dog + + + + + Dalmatian dog + + + + + Happy dog + + + + + Dragon + + + + + Elephant 1 + + + + + Elephant 2 + + + + + Elk + + + + + Frog + + + + + Ghost + + + + + Giraffe + + + + + Gnu + + + + + Goat + + + + + Hippo + + + + + Horse + + + + + Gray horse + + + + + Koala + + + + + Monkey + + + + + Gray mouse + + + + + White mouse + + + + + Panda + + + + + Penguin + + + + + Pumpkin 1 + + + + + Pumpkin 2 + + + + + Raccoon + + + + + Rhino + + + + + Sheep + + + + + Skull 1 + + + + + Skull 2 + + + + + Triceratops + + + + + Zebra + + + + + Marker picture + + + + + Replace face with this picture + + + + + + Pixel grid size + + + + + + Blur radius + + + + + Select marker color + + + + + Hard + + + + + Cooling + + + + + Dissolve + + + + + + Zoom + + + + + + + + + Threshold + + + + + + + Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) + + + + + Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image + + + + + Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image + + + + + Stride + + + + + Pattern + + + + + 90° Halftone 6x6 + + + + + Cluster 3 + + + + + Cluster 4 + + + + + Cluster 8 + + + + + Lines 4x4 + + + + + Magic 2x2 + + + + + Magic 4x4 + + + + + Ordered 4x4 + + + + + Ordered 6x6 + + + + + Ordered 8x8 + + + + + pattern bitmap... + + + + + Pattern size + + + + + Lightness + + + + + Slope + + + + + Intercept + + + + + Spiral 1 + + + + + Spiral 2 + + + + + Parabola + + + + + Horizontal stripe + + + + + Speed increment + + + + + Amount + + + + + Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) + + + + + Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton + + + + + N° of drops + + + + + Select + + + + + Cursor color + + + + + Choose the cursor color + + + + + Min. drop length + + + + + Max. drop length + + + + + Min. speed + + + + + Max. speed + + + + + Show cursor + + + + + Output format + + + + + File extensions + + + + + This output format has not specific extensions + + + + + Advanced Format Options + + + + + Video track + + + + + Audio track + + + + + Subtitles track + + + + + Simple + + + + + Brightness + + + + + Contrast + + + + + Soft normal + + + + + Hard normal + + + + + Soft color + + + + + Hard color + + + + + Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image + + + + + Radiation color + + + + + Motion detect + + + + + Rain + + + + + Decay + + + + + Show lines + + + + + Hide lines + + + + + Hide color + + + + + Choose the hide color + + + + + Vertical Sync + + + + + Noise + + + + + Mask + + + + + Degrees + + + + + Temperature + + + + + Video format + + + + + Resolution + + + + + FPS + + + + + Reset + + + + + Aspect + + + + + Scale + + + + + Softness + + + + + Choose the vignette color + + + + + Devices + + + + + Add + + + + + Edit + + + + + Remove + + + + + Remove All + + + + + Description + + + + + Camera name (optional) + + + + + Error creating camera: + + + + + Ok + + + + + Cancel + + + + + This system is not supported yet + + + + + Ripples + + + + + Phase + + + + Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/uk.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/uk.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/uk.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/uk.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/uk.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/uk.ts 2021-02-15 15:25:23.000000000 +0000 @@ -6,57 +6,57 @@ About %1 - + Про %1 Information - + Інформація Thanks! - + Подяки! License - + Ліценція Version %1 - + Версія %1 Using Qt %1 - + Використати Qt %1 Website - + Сайт Webcam capture application. - Програма захоплення веб-камери. + Програма захоплення веб-камери. A simple webcam application for picture and video capture. - + Проста програма для захоплення фото та відео з вебкамери. Thanks to all these cool people that helped contributing to Webcamoid all these years. - + Подяка всім цим хорошим людям, які допомагали Webcamoid всі ці роки. Close - + Закрити @@ -139,38 +139,44 @@ AudioInfo - + Description Опис - - + + Device description Опис пристрою - - - + + + Device id ID пристрою - + Sample Format Зразок формату - + Channels Канали - + Sample Rate Частота зразка + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start Запускати веб-камеру на старті - + Enable advanced effects mode Увімкнути режим додаткових ефектів - + Frameworks & libraries Фреймворки та бібліотеки - + Video capture Захоплення відео - + Desktop capture Захоплення робочого столу - + Audio capture/play Аудіо захоплення/відтворення - + Video convert Конвертувати відео - + Audio convert Конвертувати аудіо - + Virtual camera driver - + Драйвер віртуальної камери - + Video playback Відтворення відео - + Video record Відеозапис - + Root method Кореневий метод @@ -372,9 +378,9 @@ MediaTools - + Daily Build - + Денна збірка @@ -481,12 +487,12 @@ PATH - + Шлях(PATH) Semi-colon separated list of paths to search the Qml interface. - + Список шляхів для пошуку інтерфейсу Qml розділені двокрапкою. @@ -494,7 +500,7 @@ PATH1;PATH2;PATH3;... - + шлях1;шлях2;шлях3;... @@ -514,7 +520,7 @@ Semi-colon separated list of paths to search for virtual camera driver - + Список шляхів для пошуку драйверів віртуальної камери, через двокрапку @@ -562,35 +568,35 @@ Recording - + Audio Аудіо - + Video Відео - + Subtitle Субтитри - - + + audio аудіо - - + + video відео - - + + subtitle субтитри @@ -605,7 +611,7 @@ Stream #%1 - + Потік #%1 @@ -620,27 +626,28 @@ GOP - + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures + GOP Separation between keyframes - + Поділ між ключовими кадрами Advanced Codec Options - + Розширені параметри кодека Size of the audio (bits) / duration (seconds) - + Розмір аудіо (біт)/ тривалість (сек) Size of the video (bits) / duration (seconds) - + Розмір відео (біт)/ тривалість (сек) @@ -812,38 +819,39 @@ N° of colors - + N° колоьрів Color difference - + різниця кольорів Show edges - + Показати краї Threshold low - + Низький поріг Threshold high - + Високий поріг Line color - + Лінії кольорів - + + Scan block - + Блок сканування @@ -856,7 +864,8 @@ Transform matrix - + https://en.wikipedia.org/wiki/Transformation_matrix + Матриця трансформації @@ -870,12 +879,12 @@ Natural - + Натурально Fixed - + Зафіксовано @@ -887,12 +896,12 @@ Font - + Шрифт - + Search Пошук @@ -901,7 +910,7 @@ Hinting - + Хінтінг @@ -909,37 +918,38 @@ Default - + По замовчуванню No hinting - + Без хінтингу Vertical hinting - + Вертикальний хінтинг Full hinting - + Повний хінтинг Style + Different font rendering strategies Стиль Bitmap - + Зображення(растрове) @@ -951,19 +961,19 @@ Outline - + Контур Force outline - + Підсилити контур Match - + Співставити @@ -975,80 +985,80 @@ Antialias - + Згладжування No antialias - + Без згладжування Compatible with OpenGL - + Сумісно з OpenGL Force integer metrics - + Підсилити цільові метрики No subpixel antialias - + Не згладжувати субпікселі No font merging - + Не об'єднувати шрифти Foreground color - + Колір переднього плану Background color - + Колір фону Reversed - + Назад Please choose a font - + Будь ласка оберіть шрифт Choose the foreground color - + Оберіть колір переднього плану Choose the background color - + Оберіть колір фону Size - + Розмір @@ -1061,24 +1071,24 @@ Choose the strips color - + Виберіть смуги кольору Soft - + Пом'якшення Select the color to filter - + Оберіть колір фільтру Old color - + Попередній колір @@ -1088,7 +1098,7 @@ Select the color to replace - + Оберіть колір для заміни @@ -1099,76 +1109,80 @@ Color table - + Палітра кольорів Base - + Base color, show the image without modifications + Базовий Metal - + Металік Heat - + https://en.wikipedia.org/wiki/Heat_map + Тепло Old Photo - + Старе фото Red & Green - + Червонозелений Sepia - + https://en.wikipedia.org/wiki/Sepia_(color) + Сепія X-Pro - + Рентген про X-Ray - + Просто рентген Yellow & Blue - + Жовтоблакитний - + Custom - + Власна комбінація 16x16 bitmap... - + картинка 16x16... - + Please choose an image file - + Будь ласка оберіть зображення Convolve matrix - + https://en.wikipedia.org/wiki/Kernel_(image_processing) + Згорнути матрицю @@ -1176,44 +1190,44 @@ Factor - + Фактори Bias - + Упередження Grab mode - + Режим захоплення Random square - + Випадковий квадрат Vertical increase - + Вертикальне збільшення Horizontal increase - + Горизонтальне збільшення Rings increase - + Кільцеве збільшення Block size - + Розмір блоку @@ -1222,503 +1236,517 @@ N° of frames - + N° кадру Mu - + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) + Му Sigma - + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) + Сігма Frame rate - + Частота кадрів Amplitude - + Амплітуда Frequency - + Частота Grid size - + Розмір сітки Speed - + Швидкість Zoom rate - + Розмір зуму Strength - + Сила Canny mode - + https://en.wikipedia.org/wiki/Canny_edge_detector + Режим Canny Lower Canny threshold - + Низький поріг Canny Higger Canny threshold - + Високий поріг Canny Equalize - + https://en.wikipedia.org/wiki/Histogram_equalization + Вирівнювання Invert - + Інвертувати - + Haar file - + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature + Файл Хаара - + Eye Око - + Eye glasses - + Окуляри - + Frontal face alternative 1 - + Зміна обличчя 1 - + Frontal face alternative 2 - + Зміна обличчя 2 - + Frontal face alternative 3 - + Зміна обличчя 3 - + Frontal face default - + Звичайне обличчя - + Full body - + Все тіло - + Left Eye 1 - + Ліве око 1 - + Lower body - + Нижня частина тіла - + Eye pair big - + Обидва ока великі - + Eye pair small - + Обидва ока зменшенні - + Left ear Ліве вухо - + Left eye 2 - + ліве око 2 - + Mouth Рот - + Nose Ніс - + Right ear Праве вухо - + Right Eye 1 - + Праве око 1 - + Upper body 1 - + Верхня частина тіла 1 - + Profile face - + Профіль обличчя - + Right eye 2 - + Праве око 2 - + Smile Усмішка - + Upper body - + Верхня частина тіла - + Marker type - + Тип маркера - + Rectangle - + Прямокутник - + Ellipse - + Еліпс - + Image - + Картинка - + Pixelate - + Піхселізація - + Blur + Розмиття + + + + Blur Outer - + Marker style - + Стиль маркера - + Solid - + Твердий - + Dash - + Тире - + Dot - + Крапки - + Dash dot - + Крапки і тире - + Dash dot dot - + Тире і двокрапки - + Marker color - + Колір маркера - + + Marker width - + Ширина маркера - + Masks - + Маски - + Angel Ангел - + Bear Ведмідь - + Beaver Бобер - + Cat Кіт - + Chicken Курка - + Cow Корова - + Devil Диявол - + Dog Собака - + Dalmatian dog - + Далматинець - + Happy dog Щасливий собака - + Dragon Дракон - + Elephant 1 Слон 1 - + Elephant 2 Слон 2 - + Elk Лось - + Frog Жаба - + Ghost Привид - + Giraffe Жирафа - + Gnu - + Антилопа гну - + Goat Коза - + Hippo - + Гіпопотам - + Horse Кінь - + Gray horse Сірий кінь - + Koala Коала - + Monkey Мавпа - + Gray mouse Сіра миша - + White mouse Біла миша - + Panda Панда - + Penguin Пінгвін - + Pumpkin 1 - + Гарбуз 1 - + Pumpkin 2 - + Гарбуз 2 - + Raccoon - + Єнот - + Rhino Носоріг - + Sheep - + Вівці - + Skull 1 - + Череп 1 - + Skull 2 - + Череп 2 - + Triceratops - + Трицерапторс - + Zebra Зебра - + Marker picture - + Зображення маркера - - Replace face with this picture. - Замініть обличчя цим зображенням. + + Replace face with this picture + - + + Pixel grid size - + Розмір піксельної сітки - + + Blur radius - + Радіус розмиття - + Select marker color - + Виберіть колір маркера Hard - + Важкий Cooling - + Охолодження Dissolve - + Розчинити Zoom - + Збільшення @@ -1727,154 +1755,159 @@ Threshold - + Поріг Luma threshold - + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) + Поріг світла Alpha diff - + Alpha channel, also known as the transparency component of a pixel in an image + Альфа-різниця Alpha variation - + Alpha channel, also known as the transparency component of a pixel in an image + Альфа-варіація Stride - + Крок Pattern - + Візерунок 90° Halftone 6x6 - + 90° Півтон 6x6 Cluster 3 - + Кластерезація 3 Cluster 4 - + Кластерезація 4 Cluster 8 - + Кластерезація 8 Lines 4x4 - + Лінії 4x4 Magic 2x2 - + Магія 2x2 Magic 4x4 - + Магія 4x4 Ordered 4x4 - + Замовлено 4x4 Ordered 6x6 - + Замовлено 6x6 Ordered 8x8 - + Замовлено 8x8 pattern bitmap... - + растровий візерунок... Pattern size - + Розмір візерунку Lightness - Освітленість + Освітленість Slope - + Схил Intercept - + Перехоплення Spiral 1 - + Спіраль 1 Spiral 2 - + Спіраль 2 Parabola - + Парабола Horizontal stripe - + Горизонтальна смуга Speed increment - + Приріст швидкості Amount - + Кількість Luma Threshold - + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) + Поріг світла Choose the automata color - + https://en.wikipedia.org/wiki/Life-like_cellular_automaton + Оберіть колір автомата N° of drops - + N° з капель @@ -1889,17 +1922,17 @@ Choose the cursor color - + Оберіть колір курсора Min. drop length - + Мінімальна довжина краплі Max. drop length - + Максимальна довжина краплі @@ -1914,32 +1947,32 @@ Show cursor - + Показати курсор - + Output format - + Вихідний формат - + File extensions - + Розширення файлу - + This output format has not specific extensions - + Цей формат виводу не має конкретних розширень - + Advanced Format Options - + Розширені налаштування формату Video track - + Відео доріжка @@ -1954,7 +1987,7 @@ Simple - + Просто @@ -1969,12 +2002,12 @@ Soft normal - + М'яка нормалізація Hard normal - + Сильна нормалізація @@ -1989,12 +2022,13 @@ Alpha differential - + Alpha channel, also known as the transparency component of a pixel in an image + Різниця Альфа каналу Radiation color - + Колір радіації @@ -2009,27 +2043,27 @@ Decay - + Розпад Show lines - + Показати лінії Hide lines - + Сховати лінії Hide color - + Сховати кольори Choose the hide color - + Оберіть прихований колір @@ -2044,12 +2078,12 @@ Mask - + Маска Degrees - + Ступені @@ -2057,19 +2091,19 @@ Температура - + Video format Формат відео - + Resolution Роздільна здатність - + FPS - + Частота кадрів @@ -2079,7 +2113,7 @@ Aspect - + Пропорція @@ -2094,7 +2128,7 @@ Choose the vignette color - + Оберіть колір він'єтки @@ -2132,8 +2166,8 @@ Назва камери (необов'язково) - - Error creating camera + + Error creating camera: @@ -2147,14 +2181,14 @@ Скасувати - + This system is not supported yet Ця система ще не підтримується Ripples - + Пульсації Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/zh_CN.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/zh_CN.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/zh_CN.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/zh_CN.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/zh_CN.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/zh_CN.ts 2021-02-15 15:25:23.000000000 +0000 @@ -16,7 +16,7 @@ Thanks! - + 谢谢! @@ -36,7 +36,7 @@ Website - + 网站 @@ -139,38 +139,44 @@ AudioInfo - + Description 描述 - - + + Device description - - - + + + Device id 驱动(硬件)地址 - + Sample Format - + Channels - + Sample Rate + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -192,7 +198,7 @@ Cancel - 取消 + 取消 @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start - + Enable advanced effects mode 启用高级效果模式 - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -390,17 +396,17 @@ %1 seconds - + %1秒 Now - + 现在 Cancel - 取消 + 取消 @@ -562,35 +568,35 @@ Recording - + Audio 音频 - + Video 视频 - + Subtitle - - + + audio 音频 - - + + video 视频 - - + + subtitle @@ -620,7 +626,8 @@ GOP - + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures + 图像群组(Group of pictures,GOP) @@ -742,7 +749,7 @@ Download %1 %2 NOW! - + 现在下载%1 %2吧! @@ -841,7 +848,8 @@ - + + Scan block @@ -856,7 +864,8 @@ Transform matrix - + https://en.wikipedia.org/wiki/Transformation_matrix + 变换矩阵 @@ -892,7 +901,7 @@ - + Search 搜索 @@ -933,6 +942,7 @@ Style + Different font rendering strategies 风格(样式) @@ -1056,7 +1066,7 @@ Color - + 颜色 @@ -1083,7 +1093,7 @@ New color - + 新颜色 @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,21 +1125,23 @@ Heat + https://en.wikipedia.org/wiki/Heat_map Old Photo - + 老照片 Red & Green - + 红色和绿色 Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1144,11 +1157,11 @@ Yellow & Blue - + 黄色和蓝色 - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + 眼睛 - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + 左眼睛1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + 左耳朵 - + Left eye 2 - + 左眼睛2 - + Mouth - + Nose - + 鼻子 - + Right ear - + 右耳朵 - + Right Eye 1 - + 右眼睛1 - + Upper body 1 - + Profile face - + Right eye 2 - + 右眼睛2 - + Smile - + 笑眯眯 - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + - + Beaver - + Cat - + - + Chicken - + - + Cow - + - + Devil - + Dog - + - + Dalmatian dog - + Happy dog - + 高兴的狗 - + Dragon - + - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + - + Gray horse - + 灰色的马 - + Koala - + Monkey - + - + Gray mouse - + White mouse - + Panda - + 熊猫 - + Penguin - + Pumpkin 1 - + 南瓜1 - + Pumpkin 2 - + 南瓜2 - + Raccoon - + Rhino - + Sheep - + - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2004,7 +2038,7 @@ Rain - + @@ -2054,22 +2088,22 @@ Temperature - + 温度 - + Video format - + Resolution - + FPS - + FPS @@ -2132,8 +2166,8 @@ 摄像头名字(可选) - - Error creating camera + + Error creating camera: @@ -2144,10 +2178,10 @@ Cancel - 取消 + 取消 - + This system is not supported yet 您所使用的系统并不在支持范围内 Binary files /tmp/tmpahf6m6jo/1kQmabvHcl/webcamoid-8.6.1+dfsg/StandAlone/share/ts/zh_TW.qm and /tmp/tmpahf6m6jo/eHmyYI0aGX/webcamoid-8.8.0+dfsg/StandAlone/share/ts/zh_TW.qm differ diff -Nru webcamoid-8.6.1+dfsg/StandAlone/share/ts/zh_TW.ts webcamoid-8.8.0+dfsg/StandAlone/share/ts/zh_TW.ts --- webcamoid-8.6.1+dfsg/StandAlone/share/ts/zh_TW.ts 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/share/ts/zh_TW.ts 2021-02-15 15:25:23.000000000 +0000 @@ -139,38 +139,44 @@ AudioInfo - + Description 說明 - - + + Device description 裝置說明 - - - + + + Device id 裝置 id - + Sample Format 樣本格式 - + Channels 頻道 - + Sample Rate 採樣率 + + + Latency (ms) + Is the amount of accumulated audio ready to play, measured in time. Higher latency == smoother audio playback, but more desynchronization with the video; Lowerer latency == audio desynchronization near to the video, but glitchy audio playback. https://en.wikipedia.org/wiki/Latency_(audio) + + CodecConfigs @@ -268,62 +274,62 @@ GeneralConfig - + Play webcam on start 在開始時播放網路攝影機 - + Enable advanced effects mode 啟用進階效果模式 - + Frameworks & libraries - + Video capture - + Desktop capture - + Audio capture/play - + Video convert - + Audio convert - + Virtual camera driver - + Video playback - + Video record - + Root method @@ -372,7 +378,7 @@ MediaTools - + Daily Build @@ -562,35 +568,35 @@ Recording - + Audio - + Video - + Subtitle - - + + audio - - + + video - - + + subtitle @@ -620,6 +626,7 @@ GOP + Group of pictures. https://en.wikipedia.org/wiki/Group_of_pictures @@ -841,7 +848,8 @@ - + + Scan block @@ -856,6 +864,7 @@ Transform matrix + https://en.wikipedia.org/wiki/Transformation_matrix @@ -892,7 +901,7 @@ - + Search 搜尋 @@ -933,6 +942,7 @@ Style + Different font rendering strategies @@ -1104,6 +1114,7 @@ Base + Base color, show the image without modifications @@ -1114,6 +1125,7 @@ Heat + https://en.wikipedia.org/wiki/Heat_map @@ -1129,6 +1141,7 @@ Sepia + https://en.wikipedia.org/wiki/Sepia_(color) @@ -1148,7 +1161,7 @@ - + Custom @@ -1160,7 +1173,7 @@ - + Please choose an image file @@ -1168,6 +1181,7 @@ Convolve matrix + https://en.wikipedia.org/wiki/Kernel_(image_processing) @@ -1227,11 +1241,13 @@ Mu + Mu factor (µ letter from greek), represents the average of a group of values (https://en.wikipedia.org/wiki/Arithmetic_mean) Sigma + Sigma factor (σ letter from greek), represents the standard deviation of a group of values (https://en.wikipedia.org/wiki/Standard_deviation) @@ -1275,6 +1291,7 @@ Canny mode + https://en.wikipedia.org/wiki/Canny_edge_detector @@ -1290,6 +1307,7 @@ Equalize + https://en.wikipedia.org/wiki/Histogram_equalization @@ -1298,404 +1316,414 @@ - + Haar file + https://en.wikipedia.org/wiki/Haar-like_feature + https://en.wikipedia.org/wiki/Haar-like_feature - + Eye - + Eye glasses - + Frontal face alternative 1 - + Frontal face alternative 2 - + Frontal face alternative 3 - + Frontal face default - + Full body - + Left Eye 1 - + Lower body - + Eye pair big - + Eye pair small - + Left ear - + Left eye 2 - + Mouth - + Nose - + Right ear - + Right Eye 1 - + Upper body 1 - + Profile face - + Right eye 2 - + Smile - + Upper body - + Marker type - + Rectangle - + Ellipse - + Image - + Pixelate - + Blur - + + Blur Outer + + + + Marker style - + Solid - + Dash - + Dot - + Dash dot - + Dash dot dot - + Marker color - + + Marker width - + Masks - + Angel - + Bear - + Beaver - + Cat - + Chicken - + Cow - + Devil - + Dog - + Dalmatian dog - + Happy dog - + Dragon - + Elephant 1 - + Elephant 2 - + Elk - + Frog - + Ghost - + Giraffe - + Gnu - + Goat - + Hippo - + Horse - + Gray horse - + Koala - + Monkey - + Gray mouse - + White mouse - + Panda - + Penguin - + Pumpkin 1 - + Pumpkin 2 - + Raccoon - + Rhino - + Sheep - + Skull 1 - + Skull 2 - + Triceratops - + Zebra - + Marker picture - - Replace face with this picture. + + Replace face with this picture - + + Pixel grid size - + + Blur radius - + Select marker color @@ -1734,16 +1762,19 @@ Luma threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Alpha diff + Alpha channel, also known as the transparency component of a pixel in an image Alpha variation + Alpha channel, also known as the transparency component of a pixel in an image @@ -1864,11 +1895,13 @@ Luma Threshold + Minimum luminance/light/white level/intensity in a gray or black and white picture (https://en.wikipedia.org/wiki/Luma_(video)) Choose the automata color + https://en.wikipedia.org/wiki/Life-like_cellular_automaton @@ -1917,22 +1950,22 @@ - + Output format - + File extensions - + This output format has not specific extensions - + Advanced Format Options @@ -1989,6 +2022,7 @@ Alpha differential + Alpha channel, also known as the transparency component of a pixel in an image @@ -2057,17 +2091,17 @@ - + Video format - + Resolution - + FPS @@ -2132,8 +2166,8 @@ - - Error creating camera + + Error creating camera: @@ -2147,7 +2181,7 @@ 取消 - + This system is not supported yet diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/audiolayer.cpp webcamoid-8.8.0+dfsg/StandAlone/src/audiolayer.cpp --- webcamoid-8.6.1+dfsg/StandAlone/src/audiolayer.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/audiolayer.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -27,8 +27,8 @@ #include #include #include -#include #include +#include #include "audiolayer.h" @@ -36,18 +36,32 @@ #define EXTERNAL_MEDIA_INPUT ":externalinput:" #define MAX_SAMPLE_RATE 512e3 +using ObjectPtr = QSharedPointer; + class AudioLayerPrivate { public: QQmlApplicationEngine *m_engine {nullptr}; QStringList m_audioInput; QStringList m_inputs; - AkCaps m_inputCaps; - AkCaps m_outputCaps; + AkAudioCaps m_inputCaps; + AkAudioCaps m_outputCaps; QString m_inputDescription; AkElementPtr m_audioOut {AkElement::create("AudioDevice")}; + ObjectPtr m_audioOutSettings { + AkElement::create("AudioDevice", + AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + }; AkElementPtr m_audioIn {AkElement::create("AudioDevice")}; + ObjectPtr m_audioInSettings { + AkElement::create("AudioDevice", + AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + }; AkElementPtr m_audioConvert {AkElement::create("ACapsConvert")}; + ObjectPtr m_audioConvertSettings { + AkElement::create("ACapsConvert", + AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + }; AkElementPtr m_audioGenerator {AkElement::create("AudioGen")}; AkElementPtr m_audioSwitch {AkElement::create("Multiplex")}; QMutex m_mutex; @@ -87,9 +101,9 @@ this, SIGNAL(audioOutputChanged(const QString &))); QObject::connect(this->d->m_audioOut.data(), - SIGNAL(capsChanged(const AkCaps &)), + SIGNAL(capsChanged(const AkAudioCaps &)), this, - SIGNAL(outputDeviceCapsChanged(const AkCaps &))); + SIGNAL(outputDeviceCapsChanged(const AkAudioCaps &))); QObject::connect(this->d->m_audioOut.data(), SIGNAL(outputsChanged(const QStringList &)), this, @@ -98,6 +112,10 @@ SIGNAL(stateChanged(AkElement::ElementState)), this, SIGNAL(outputStateChanged(AkElement::ElementState))); + QObject::connect(this->d->m_audioOut.data(), + SIGNAL(latencyChanged(int)), + this, + SIGNAL(outputLatencyChanged(int))); } if (this->d->m_audioIn) { @@ -112,22 +130,26 @@ SIGNAL(inputsChanged(const QStringList &)), this, SLOT(privInputsChanged(const QStringList &))); + QObject::connect(this->d->m_audioIn.data(), + SIGNAL(latencyChanged(int)), + this, + SIGNAL(inputLatencyChanged(int))); } - if (this->d->m_audioOut) { - QObject::connect(this->d->m_audioOut.data(), + if (this->d->m_audioOutSettings) { + QObject::connect(this->d->m_audioOutSettings.data(), SIGNAL(audioLibChanged(const QString &)), this, SLOT(saveAudioDeviceAudioLib(const QString &))); - } else if (this->d->m_audioIn) { - QObject::connect(this->d->m_audioIn.data(), + } else if (this->d->m_audioInSettings) { + QObject::connect(this->d->m_audioInSettings.data(), SIGNAL(audioLibChanged(const QString &)), this, SLOT(saveAudioDeviceAudioLib(const QString &))); } - if (this->d->m_audioConvert) { - QObject::connect(this->d->m_audioConvert.data(), + if (this->d->m_audioConvertSettings) { + QObject::connect(this->d->m_audioConvertSettings.data(), SIGNAL(convertLibChanged(const QString &)), this, SLOT(saveAudioConvertConvertLib(const QString &))); @@ -214,50 +236,47 @@ return QStringList(); } -AkCaps AudioLayer::inputCaps() const +AkAudioCaps AudioLayer::inputCaps() const { return this->d->m_inputCaps; } -AkCaps AudioLayer::outputCaps() const +AkAudioCaps AudioLayer::outputCaps() const { if (this->d->m_audioInput.contains(EXTERNAL_MEDIA_INPUT)) { if (this->d->m_inputCaps) return this->d->m_inputCaps; - AkCaps caps; - if (this->d->m_audioGenerator) - caps = this->d->m_audioGenerator->property("caps").toString(); + return this->d->m_audioGenerator->property("caps").value(); - return caps; + return {}; } if (this->d->m_audioInput.contains(DUMMY_INPUT_DEVICE)) { - AkCaps caps; - if (this->d->m_audioGenerator) - caps = this->d->m_audioGenerator->property("caps").toString(); + return this->d->m_audioGenerator->property("caps").value(); - return caps; + return {}; } - return this->d->m_audioIn? - this->d->m_audioIn->property("caps").value(): - AkCaps(); + if (this->d->m_audioIn) + return this->d->m_audioIn->property("caps").value(); + + return {}; } -AkCaps AudioLayer::inputDeviceCaps() const +AkAudioCaps AudioLayer::inputDeviceCaps() const { return this->outputCaps(); } -AkCaps AudioLayer::outputDeviceCaps() const +AkAudioCaps AudioLayer::outputDeviceCaps() const { if (this->d->m_audioOut) - return this->d->m_audioOut->property("caps").value(); + return this->d->m_audioOut->property("caps").value(); - return AkCaps(); + return {}; } QString AudioLayer::inputDescription() const @@ -300,10 +319,28 @@ return AkElement::ElementStateNull; } +int AudioLayer::inputLatency() const +{ + if (this->d->m_audioIn) + return this->d->m_audioIn->property("latency").toInt(); + + return 1; +} + +int AudioLayer::outputLatency() const +{ + if (this->d->m_audioOut) + return this->d->m_audioOut->property("latency").toInt(); + + return 1; +} + AkAudioCaps AudioLayer::preferredFormat(const QString &device) { if (device == DUMMY_INPUT_DEVICE) - return AkAudioCaps(AkAudioCaps::SampleFormat_s16, 1, 8000); + return AkAudioCaps(AkAudioCaps::SampleFormat_s16, + AkAudioCaps::Layout_mono, + 8000); if (device == EXTERNAL_MEDIA_INPUT) { if (this->d->m_inputCaps) @@ -312,7 +349,7 @@ AkAudioCaps caps; if (this->d->m_audioGenerator) - caps = this->d->m_audioGenerator->property("caps").toString(); + caps = this->d->m_audioGenerator->property("caps").value(); return caps; } @@ -330,10 +367,15 @@ return AkAudioCaps(); } -QStringList AudioLayer::supportedFormats(const QString &device) +QList AudioLayer::supportedFormats(const QString &device) const { if (device == DUMMY_INPUT_DEVICE) - return QStringList {"flt", "s32", "s16", "u8"}; + return { + AkAudioCaps::SampleFormat_s32, + AkAudioCaps::SampleFormat_s16, + AkAudioCaps::SampleFormat_flt, + AkAudioCaps::SampleFormat_u8, + }; if (device == EXTERNAL_MEDIA_INPUT) { AkAudioCaps caps; @@ -341,10 +383,10 @@ if (this->d->m_inputCaps) caps = this->d->m_inputCaps; else if (this->d->m_audioGenerator) - caps = this->d->m_audioGenerator->property("caps").toString(); + caps = this->d->m_audioGenerator->property("caps").value(); if (caps) - return QStringList {AkAudioCaps::sampleFormatToString(caps.format())}; + return {caps.format()}; } else if (this->d->m_audioOut) { QList supportedFormats; QMetaObject::invokeMethod(this->d->m_audioOut.data(), @@ -352,21 +394,16 @@ Q_RETURN_ARG(QList, supportedFormats), Q_ARG(QString, device)); - QStringList supportedFormatsStr; - - for (auto &format: supportedFormats) - supportedFormatsStr << AkAudioCaps::sampleFormatToString(format); - - return supportedFormatsStr; + return supportedFormats; } - return QStringList(); + return {}; } -QList AudioLayer::supportedChannels(const QString &device) +QList AudioLayer::supportedChannelLayouts(const QString &device) const { if (device == DUMMY_INPUT_DEVICE) - return QList {1, 2}; + return {AkAudioCaps::Layout_mono, AkAudioCaps::Layout_stereo}; if (device == EXTERNAL_MEDIA_INPUT) { AkAudioCaps caps; @@ -374,24 +411,24 @@ if (this->d->m_inputCaps) caps = this->d->m_inputCaps; else if (this->d->m_audioGenerator) - caps = this->d->m_audioGenerator->property("caps").toString(); + caps = this->d->m_audioGenerator->property("caps").value(); if (caps) - return QList {caps.channels()}; + return {caps.layout()}; } else if (this->d->m_audioOut) { - QList supportedChannels; + QList supportedChannelLayouts; QMetaObject::invokeMethod(this->d->m_audioOut.data(), - "supportedChannels", - Q_RETURN_ARG(QList, supportedChannels), + "supportedChannelLayouts", + Q_RETURN_ARG(QList, supportedChannelLayouts), Q_ARG(QString, device)); - return supportedChannels; + return supportedChannelLayouts; } - return QList(); + return {}; } -QList AudioLayer::supportedSampleRates(const QString &device) +QList AudioLayer::supportedSampleRates(const QString &device) const { if (device == DUMMY_INPUT_DEVICE) return this->d->m_commonSampleRates.toList(); @@ -402,7 +439,7 @@ if (this->d->m_inputCaps) caps = this->d->m_inputCaps; else if (this->d->m_audioGenerator) - caps = this->d->m_audioGenerator->property("caps").toString(); + caps = this->d->m_audioGenerator->property("caps").value(); if (caps) return QList {caps.rate()}; @@ -416,7 +453,7 @@ return supportedSampleRates; } - return QList(); + return {}; } void AudioLayer::setAudioInput(const QStringList &audioInput) @@ -460,7 +497,7 @@ } } -void AudioLayer::setInputCaps(const AkCaps &inputCaps) +void AudioLayer::setInputCaps(const AkAudioCaps &inputCaps) { if (this->d->m_inputCaps == inputCaps) return; @@ -469,7 +506,7 @@ emit this->inputCapsChanged(inputCaps); } -void AudioLayer::setInputDeviceCaps(const AkCaps &inputDeviceCaps) +void AudioLayer::setInputDeviceCaps(const AkAudioCaps &inputDeviceCaps) { if (this->d->m_audioInput.contains(EXTERNAL_MEDIA_INPUT) || this->inputDeviceCaps() == inputDeviceCaps) @@ -477,17 +514,18 @@ if (this->d->m_audioInput.contains(DUMMY_INPUT_DEVICE)) { if (this->d->m_audioGenerator) - this->d->m_audioGenerator->setProperty("caps", inputDeviceCaps.toString()); + this->d->m_audioGenerator->setProperty("caps", QVariant::fromValue(inputDeviceCaps)); } else if (this->d->m_audioIn) this->d->m_audioIn->setProperty("caps", QVariant::fromValue(inputDeviceCaps)); emit inputDeviceCapsChanged(inputDeviceCaps); } -void AudioLayer::setOutputDeviceCaps(const AkCaps &outputDeviceCaps) +void AudioLayer::setOutputDeviceCaps(const AkAudioCaps &outputDeviceCaps) { if (this->d->m_audioOut) - this->d->m_audioOut->setProperty("caps", QVariant::fromValue(outputDeviceCaps)); + this->d->m_audioOut->setProperty("caps", + QVariant::fromValue(outputDeviceCaps)); } void AudioLayer::setInputDescription(const QString &inputDescription) @@ -544,6 +582,18 @@ return false; } +void AudioLayer::setInputLatency(int inputLatency) +{ + if (this->d->m_audioIn) + this->d->m_audioIn->setProperty("latency", inputLatency); +} + +void AudioLayer::setOutputLatency(int outputLatency) +{ + if (this->d->m_audioOut) + this->d->m_audioOut->setProperty("latency", outputLatency); +} + void AudioLayer::resetAudioInput() { QStringList devices; @@ -566,7 +616,7 @@ void AudioLayer::resetInputCaps() { - this->setInputCaps(AkCaps()); + this->setInputCaps({}); } void AudioLayer::resetInputDeviceCaps() @@ -601,6 +651,16 @@ this->setOutputState(AkElement::ElementStateNull); } +void AudioLayer::resetInputLatency() +{ + this->setInputLatency(1); +} + +void AudioLayer::resetOutputLatency() +{ + this->setOutputLatency(1); +} + AkPacket AudioLayer::iStream(const AkPacket &packet) { if (packet.caps().mimeType() != "audio/x-raw") @@ -655,7 +715,7 @@ void AudioLayer::updateInputState() { - AkCaps outputCaps = this->outputCaps(); + auto outputCaps = this->outputCaps(); if (this->d->m_outputCaps != outputCaps) { this->d->m_outputCaps = outputCaps; @@ -669,7 +729,7 @@ void AudioLayer::updateOutputState() { - AkCaps outputCaps = this->outputCaps(); + auto outputCaps = this->outputCaps(); if (this->d->m_outputCaps != outputCaps) { this->d->m_outputCaps = outputCaps; @@ -686,18 +746,20 @@ QSettings config; config.beginGroup("Libraries"); - auto audioDev = this->d->m_audioOut? - this->d->m_audioOut: this->d->m_audioIn; + auto audioDev = this->d->m_audioOutSettings? + this->d->m_audioOutSettings: this->d->m_audioInSettings; if (audioDev) audioDev->setProperty("audioLib", config.value("AudioDevice.audioLib", audioDev->property("audioLib"))); - if (this->d->m_audioConvert) - this->d->m_audioConvert->setProperty("convertLib", - config.value("AudioConvert.convertLib", - this->d->m_audioConvert->property("convertLib"))); + if (this->d->m_audioConvertSettings) { + auto convertLib = + config.value("AudioConvert.convertLib", + this->d->m_audioConvertSettings->property("convertLib")); + this->d->m_audioConvertSettings->setProperty("convertLib", convertLib); + } config.endGroup(); @@ -756,15 +818,17 @@ config.endGroup(); config.beginGroup("Libraries"); - auto audioDev = this->d->m_audioOut? - this->d->m_audioOut: this->d->m_audioIn; + auto audioDev = this->d->m_audioOutSettings? + this->d->m_audioOutSettings: this->d->m_audioInSettings; if (audioDev) config.setValue("AudioDevice.audioLib", audioDev->property("audioLib")); - if (this->d->m_audioConvert) - config.setValue("AudioConvert.convertLib", - this->d->m_audioConvert->property("convertLib")); + if (this->d->m_audioConvertSettings) { + auto convertLib = + this->d->m_audioConvertSettings->property("convertLib"); + config.setValue("AudioConvert.convertLib", convertLib); + } config.endGroup(); } diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/audiolayer.h webcamoid-8.8.0+dfsg/StandAlone/src/audiolayer.h --- webcamoid-8.6.1+dfsg/StandAlone/src/audiolayer.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/audiolayer.h 2021-02-15 15:25:23.000000000 +0000 @@ -21,14 +21,14 @@ #define AUDIOLAYER_H #include +#include class AudioLayerPrivate; class AudioLayer; -class AkCaps; class AkAudioCaps; class QQmlApplicationEngine; -typedef QSharedPointer AudioLayerPtr; +using AudioLayerPtr = QSharedPointer; class AudioLayer: public QObject { @@ -49,20 +49,20 @@ Q_PROPERTY(QStringList outputs READ outputs NOTIFY outputsChanged) - Q_PROPERTY(AkCaps inputCaps + Q_PROPERTY(AkAudioCaps inputCaps READ inputCaps WRITE setInputCaps RESET resetInputCaps NOTIFY inputCapsChanged) - Q_PROPERTY(AkCaps outputCaps + Q_PROPERTY(AkAudioCaps outputCaps READ outputCaps NOTIFY outputCapsChanged) - Q_PROPERTY(AkCaps inputDeviceCaps + Q_PROPERTY(AkAudioCaps inputDeviceCaps READ inputDeviceCaps WRITE setInputDeviceCaps RESET resetInputDeviceCaps NOTIFY inputDeviceCapsChanged) - Q_PROPERTY(AkCaps outputDeviceCaps + Q_PROPERTY(AkAudioCaps outputDeviceCaps READ outputDeviceCaps WRITE setOutputDeviceCaps RESET resetOutputDeviceCaps @@ -82,6 +82,16 @@ WRITE setInputState RESET resetInputState NOTIFY inputStateChanged) + Q_PROPERTY(int inputLatency + READ inputLatency + WRITE setInputLatency + RESET resetInputLatency + NOTIFY inputLatencyChanged) + Q_PROPERTY(int outputLatency + READ outputLatency + WRITE setOutputLatency + RESET resetOutputLatency + NOTIFY outputLatencyChanged) public: AudioLayer(QQmlApplicationEngine *engine=nullptr, @@ -92,18 +102,20 @@ Q_INVOKABLE QString audioOutput() const; Q_INVOKABLE QStringList inputs() const; Q_INVOKABLE QStringList outputs() const; - Q_INVOKABLE AkCaps inputCaps() const; - Q_INVOKABLE AkCaps outputCaps() const; - Q_INVOKABLE AkCaps inputDeviceCaps() const; - Q_INVOKABLE AkCaps outputDeviceCaps() const; + Q_INVOKABLE AkAudioCaps inputCaps() const; + Q_INVOKABLE AkAudioCaps outputCaps() const; + Q_INVOKABLE AkAudioCaps inputDeviceCaps() const; + Q_INVOKABLE AkAudioCaps outputDeviceCaps() const; Q_INVOKABLE QString inputDescription() const; Q_INVOKABLE QString description(const QString &device) const; Q_INVOKABLE AkElement::ElementState inputState() const; Q_INVOKABLE AkElement::ElementState outputState() const; + Q_INVOKABLE int inputLatency() const; + Q_INVOKABLE int outputLatency() const; Q_INVOKABLE AkAudioCaps preferredFormat(const QString &device); - Q_INVOKABLE QStringList supportedFormats(const QString &device); - Q_INVOKABLE QList supportedChannels(const QString &device); - Q_INVOKABLE QList supportedSampleRates(const QString &device); + Q_INVOKABLE QList supportedFormats(const QString &device) const; + Q_INVOKABLE QList supportedChannelLayouts(const QString &device) const; + Q_INVOKABLE QList supportedSampleRates(const QString &device) const; private: AudioLayerPrivate *d; @@ -113,24 +125,28 @@ void audioOutputChanged(const QString &audioOutput); void inputsChanged(const QStringList &inputs); void outputsChanged(const QStringList &outputs); - void inputCapsChanged(const AkCaps &inputCaps); - void outputCapsChanged(const AkCaps &outputCaps); - void inputDeviceCapsChanged(const AkCaps &inputDeviceCaps); - void outputDeviceCapsChanged(const AkCaps &outputDeviceCaps); + void inputCapsChanged(const AkAudioCaps &inputCaps); + void outputCapsChanged(const AkAudioCaps &outputCaps); + void inputDeviceCapsChanged(const AkAudioCaps &inputDeviceCaps); + void outputDeviceCapsChanged(const AkAudioCaps &outputDeviceCaps); void inputDescriptionChanged(const QString &inputDescription); void inputStateChanged(AkElement::ElementState inputState); void outputStateChanged(AkElement::ElementState outputState); + void inputLatencyChanged(int inputLatency); + void outputLatencyChanged(int outputLatency); void oStream(const AkPacket &packet); public slots: void setAudioInput(const QStringList &audioInput); void setAudioOutput(const QString &audioOutput); - void setInputCaps(const AkCaps &inputCaps); - void setInputDeviceCaps(const AkCaps &inputDeviceCaps); - void setOutputDeviceCaps(const AkCaps &outputDeviceCaps); + void setInputCaps(const AkAudioCaps &inputCaps); + void setInputDeviceCaps(const AkAudioCaps &inputDeviceCaps); + void setOutputDeviceCaps(const AkAudioCaps &outputDeviceCaps); void setInputDescription(const QString &inputDescription); void setInputState(AkElement::ElementState inputState); bool setOutputState(AkElement::ElementState outputState); + void setInputLatency(int inputLatency); + void setOutputLatency(int outputLatency); void resetAudioInput(); void resetAudioOutput(); void resetInputCaps(); @@ -139,6 +155,8 @@ void resetInputDescription(); void resetInputState(); void resetOutputState(); + void resetInputLatency(); + void resetOutputLatency(); AkPacket iStream(const AkPacket &packet); void setQmlEngine(QQmlApplicationEngine *engine=nullptr); diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/main.cpp webcamoid-8.8.0+dfsg/StandAlone/src/main.cpp --- webcamoid-8.6.1+dfsg/StandAlone/src/main.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/main.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -16,7 +16,7 @@ * * Web-Site: http://webcamoid.github.io/ */ - +#include #include #include #include diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/mediasource.cpp webcamoid-8.8.0+dfsg/StandAlone/src/mediasource.cpp --- webcamoid-8.6.1+dfsg/StandAlone/src/mediasource.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/mediasource.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -24,9 +24,14 @@ #include #include #include +#include +#include +#include #include "mediasource.h" +using ObjectPtr = QSharedPointer; + class MediaSourcePrivate { public: @@ -37,11 +42,23 @@ QStringList m_desktops; QVariantMap m_uris; QMap m_descriptions; - AkCaps m_audioCaps; - AkCaps m_videoCaps; + AkAudioCaps m_audioCaps; + AkVideoCaps m_videoCaps; AkElementPtr m_cameraCapture {AkElement::create("VideoCapture")}; + ObjectPtr m_cameraCaptureSettings { + AkElement::create("VideoCapture", + AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + }; AkElementPtr m_desktopCapture {AkElement::create("DesktopCapture")}; + ObjectPtr m_desktopCaptureSettings { + AkElement::create("DesktopCapture", + AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + }; AkElementPtr m_uriCapture {AkElement::create("MultiSrc")}; + ObjectPtr m_uriCaptureSettings { + AkElement::create("MultiSrc", + AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + }; AkElement::ElementState m_inputState {AkElement::ElementStateNull}; bool m_playOnStart {false}; @@ -86,17 +103,20 @@ this, SIGNAL(error(const QString &))); QObject::connect(this->d->m_cameraCapture.data(), + SIGNAL(streamsChanged(const QList &)), + this, + SLOT(webcamStreamsChanged(const QList &))); + } + + if (this->d->m_cameraCaptureSettings) { + QObject::connect(this->d->m_cameraCaptureSettings.data(), SIGNAL(codecLibChanged(const QString &)), this, SLOT(saveVideoCaptureCodecLib(const QString &))); - QObject::connect(this->d->m_cameraCapture.data(), + QObject::connect(this->d->m_cameraCaptureSettings.data(), SIGNAL(captureLibChanged(const QString &)), this, SLOT(saveVideoCaptureCaptureLib(const QString &))); - QObject::connect(this->d->m_cameraCapture.data(), - SIGNAL(streamsChanged(const QList &)), - this, - SLOT(webcamStreamsChanged(const QList &))); } if (this->d->m_desktopCapture) { @@ -113,7 +133,10 @@ SIGNAL(error(const QString &)), this, SIGNAL(error(const QString &))); - QObject::connect(this->d->m_desktopCapture.data(), + } + + if (this->d->m_desktopCaptureSettings) { + QObject::connect(this->d->m_desktopCaptureSettings.data(), SIGNAL(captureLibChanged(const QString &)), this, SLOT(saveDesktopCaptureCaptureLib(const QString &))); @@ -133,7 +156,10 @@ SIGNAL(error(const QString &)), this, SIGNAL(error(const QString &))); - QObject::connect(this->d->m_uriCapture.data(), + } + + if (this->d->m_uriCaptureSettings) { + QObject::connect(this->d->m_uriCaptureSettings.data(), SIGNAL(codecLibChanged(const QString &)), this, SLOT(saveMultiSrcCodecLib(const QString &))); @@ -215,12 +241,12 @@ return this->d->m_uris; } -AkCaps MediaSource::audioCaps() const +AkAudioCaps MediaSource::audioCaps() const { return this->d->m_audioCaps; } -AkCaps MediaSource::videoCaps() const +AkVideoCaps MediaSource::videoCaps() const { return this->d->m_videoCaps; } @@ -425,8 +451,8 @@ auto source = this->d->sourceElement(stream); if (!source) { - this->setAudioCaps(AkCaps()); - this->setVideoCaps(AkCaps()); + this->setAudioCaps({}); + this->setVideoCaps({}); if (state != AkElement::ElementStateNull) emit this->stateChanged(AkElement::ElementStateNull); @@ -587,7 +613,7 @@ return true; } -void MediaSource::setAudioCaps(const AkCaps &audioCaps) +void MediaSource::setAudioCaps(const AkAudioCaps &audioCaps) { if (this->d->m_audioCaps == audioCaps) return; @@ -596,7 +622,7 @@ emit this->audioCapsChanged(audioCaps); } -void MediaSource::setVideoCaps(const AkCaps &videoCaps) +void MediaSource::setVideoCaps(const AkVideoCaps &videoCaps) { if (this->d->m_videoCaps == videoCaps) return; @@ -611,25 +637,33 @@ config.beginGroup("Libraries"); - if (this->d->m_cameraCapture) { - this->d->m_cameraCapture->setProperty("codecLib", - config.value("VideoCapture.codecLib", - this->d->m_cameraCapture->property("codecLib"))); - this->d->m_cameraCapture->setProperty("captureLib", - config.value("VideoCapture.captureLib", - this->d->m_cameraCapture->property("captureLib"))); + if (this->d->m_cameraCaptureSettings) { + auto codecLib = + config.value("VideoCapture.codecLib", + this->d->m_cameraCaptureSettings->property("codecLib")); + this->d->m_cameraCaptureSettings->setProperty("codecLib", codecLib); + auto captureLib = + config.value("VideoCapture.captureLib", + this->d->m_cameraCaptureSettings->property("captureLib")); + this->d->m_cameraCaptureSettings->setProperty("captureLib", + captureLib); + } + + if (this->d->m_desktopCaptureSettings) { + auto captureLib = + config.value("DesktopCapture.captureLib", + this->d->m_desktopCaptureSettings->property("captureLib")); + this->d->m_desktopCaptureSettings->setProperty("captureLib", + captureLib); + } + + if (this->d->m_uriCaptureSettings) { + auto codecLib = + config.value("MultiSrc.codecLib", + this->d->m_uriCaptureSettings->property("codecLib")); + this->d->m_uriCapture->setProperty("codecLib", codecLib); } - if (this->d->m_desktopCapture) - this->d->m_desktopCapture->setProperty("captureLib", - config.value("DesktopCapture.captureLib", - this->d->m_desktopCapture->property("captureLib"))); - - if (this->d->m_uriCapture) - this->d->m_uriCapture->setProperty("codecLib", - config.value("MultiSrc.codecLib", - this->d->m_uriCapture->property("codecLib"))); - config.endGroup(); config.beginGroup("StreamConfigs"); @@ -747,23 +781,27 @@ config.beginGroup("Libraries"); - if (this->d->m_cameraCapture) { - config.setValue("VideoCapture.codecLib", this->d->m_cameraCapture->property("codecLib")); - config.setValue("VideoCapture.captureLib", this->d->m_cameraCapture->property("captureLib")); + if (this->d->m_cameraCaptureSettings) { + config.setValue("VideoCapture.codecLib", + this->d->m_cameraCaptureSettings->property("codecLib")); + config.setValue("VideoCapture.captureLib", + this->d->m_cameraCaptureSettings->property("captureLib")); } - if (this->d->m_desktopCapture) - config.setValue("DesktopCapture.captureLib", this->d->m_desktopCapture->property("captureLib")); - - if (this->d->m_uriCapture) - config.setValue("MultiSrc.codecLib", this->d->m_uriCapture->property("codecLib")); + if (this->d->m_desktopCaptureSettings) + config.setValue("DesktopCapture.captureLib", + this->d->m_desktopCaptureSettings->property("captureLib")); + + if (this->d->m_uriCaptureSettings) + config.setValue("MultiSrc.codecLib", + this->d->m_uriCaptureSettings->property("codecLib")); config.endGroup(); } void MediaSource::webcamStreamsChanged(const QList &streams) { - Q_UNUSED(streams); + Q_UNUSED(streams) this->streamUpdated(this->d->m_stream); } diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/mediasource.h webcamoid-8.8.0+dfsg/StandAlone/src/mediasource.h --- webcamoid-8.6.1+dfsg/StandAlone/src/mediasource.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/mediasource.h 2021-02-15 15:25:23.000000000 +0000 @@ -24,10 +24,11 @@ class MediaSourcePrivate; class MediaSource; -class AkCaps; +class AkAudioCaps; +class AkVideoCaps; class QQmlApplicationEngine; -typedef QSharedPointer MediaSourcePtr; +using MediaSourcePtr = QSharedPointer; class MediaSource: public QObject { @@ -51,10 +52,10 @@ WRITE setUris RESET resetUris NOTIFY urisChanged) - Q_PROPERTY(AkCaps audioCaps + Q_PROPERTY(AkAudioCaps audioCaps READ audioCaps NOTIFY audioCapsChanged) - Q_PROPERTY(AkCaps videoCaps + Q_PROPERTY(AkVideoCaps videoCaps READ videoCaps NOTIFY videoCapsChanged) Q_PROPERTY(AkElement::ElementState state @@ -78,8 +79,8 @@ Q_INVOKABLE QStringList cameras() const; Q_INVOKABLE QStringList desktops() const; Q_INVOKABLE QVariantMap uris() const; - Q_INVOKABLE AkCaps audioCaps() const; - Q_INVOKABLE AkCaps videoCaps() const; + Q_INVOKABLE AkAudioCaps audioCaps() const; + Q_INVOKABLE AkVideoCaps videoCaps() const; Q_INVOKABLE AkElement::ElementState state() const; Q_INVOKABLE bool playOnStart() const; Q_INVOKABLE QString description(const QString &stream) const; @@ -97,8 +98,8 @@ void camerasChanged(const QStringList &cameras); void desktopsChanged(const QStringList &desktops); void urisChanged(const QVariantMap &uris); - void audioCapsChanged(const AkCaps &audioCaps); - void videoCapsChanged(const AkCaps &videoCaps); + void audioCapsChanged(const AkAudioCaps &audioCaps); + void videoCapsChanged(const AkVideoCaps &videoCaps); void stateChanged(AkElement::ElementState state); void playOnStartChanged(bool playOnStart); void oStream(const AkPacket &packet); @@ -121,8 +122,8 @@ bool setStreams(const QStringList &streams); bool setCameras(const QStringList &cameras); bool setDesktops(const QStringList &desktops); - void setAudioCaps(const AkCaps &audioCaps); - void setVideoCaps(const AkCaps &videoCaps); + void setAudioCaps(const AkAudioCaps &audioCaps); + void setVideoCaps(const AkVideoCaps &videoCaps); void loadProperties(); void saveStream(const QString &stream); void saveUris(const QVariantMap &uris); diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/mediatools.cpp webcamoid-8.8.0+dfsg/StandAlone/src/mediatools.cpp --- webcamoid-8.6.1+dfsg/StandAlone/src/mediatools.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/mediatools.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "mediatools.h" diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/pluginconfigs.h webcamoid-8.8.0+dfsg/StandAlone/src/pluginconfigs.h --- webcamoid-8.6.1+dfsg/StandAlone/src/pluginconfigs.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/pluginconfigs.h 2021-02-15 15:25:23.000000000 +0000 @@ -27,7 +27,7 @@ class CliOptions; class QQmlApplicationEngine; -typedef QSharedPointer PluginConfigsPtr; +using PluginConfigsPtr = QSharedPointer; class PluginConfigs: public QObject { diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/recording.cpp webcamoid-8.8.0+dfsg/StandAlone/src/recording.cpp --- webcamoid-8.6.1+dfsg/StandAlone/src/recording.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/recording.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,6 +17,7 @@ * Web-Site: http://webcamoid.github.io/ */ +#include #include #include #include @@ -26,22 +27,32 @@ #include #include #include +#include +#include +#include #include +#include #include "recording.h" #define DEFAULT_RECORD_AUDIO true #define AUDIO_RECORDING_KEY "Enable audio recording" +using ObjectPtr = QSharedPointer; + class RecordingPrivate { public: QQmlApplicationEngine *m_engine {nullptr}; QStringList m_availableFormats; - AkCaps m_audioCaps; - AkCaps m_videoCaps; + AkAudioCaps m_audioCaps; + AkVideoCaps m_videoCaps; QString m_videoFileName; AkElementPtr m_record {AkElement::create("MultiSink")}; + ObjectPtr m_recordSettings { + AkElement::create("MultiSink", + AK_PLUGIN_TYPE_ELEMENT_SETTINGS) + }; QMutex m_mutex; AkVideoPacket m_curPacket; QImage m_photo; @@ -102,7 +113,10 @@ SIGNAL(supportedFormatsChanged(const QStringList &)), this, SLOT(updateFormat())); - QObject::connect(this->d->m_record.data(), + } + + if (this->d->m_recordSettings) { + QObject::connect(this->d->m_recordSettings.data(), SIGNAL(codecLibChanged(const QString &)), this, SLOT(saveMultiSinkCodecLib(const QString &))); @@ -166,12 +180,12 @@ return QString(); } -AkCaps Recording::audioCaps() const +AkAudioCaps Recording::audioCaps() const { return this->d->m_audioCaps; } -AkCaps Recording::videoCaps() const +AkVideoCaps Recording::videoCaps() const { return this->d->m_videoCaps; } @@ -285,7 +299,7 @@ "supportedFormats", Q_RETURN_ARG(QStringList, supportedFormats)); - for (const QString &format: supportedFormats) { + for (auto &format: supportedFormats) { QStringList audioCodecs; QMetaObject::invokeMethod(this->m_record.data(), "supportedCodecs", @@ -306,10 +320,15 @@ Q_RETURN_ARG(QStringList, extensions), Q_ARG(QString, format)); +#ifdef Q_OS_ANDROID + if (!videoCodecs.isEmpty() && !extensions.isEmpty()) + formats << format; +#else if ((format == "gif" || !audioCodecs.isEmpty()) && !videoCodecs.isEmpty() && !extensions.isEmpty()) formats << format; +#endif } return formats; @@ -321,7 +340,7 @@ this->d->m_record->setProperty("outputFormat", format); } -void Recording::setAudioCaps(const AkCaps &audioCaps) +void Recording::setAudioCaps(const AkAudioCaps &audioCaps) { if (this->d->m_audioCaps == audioCaps) return; @@ -330,7 +349,7 @@ emit this->audioCapsChanged(audioCaps); } -void Recording::setVideoCaps(const AkCaps &videoCaps) +void Recording::setVideoCaps(const AkVideoCaps &videoCaps) { if (this->d->m_videoCaps == videoCaps) return; @@ -375,21 +394,21 @@ QString defaultFormat; if (this->d->m_record) - defaultFormat = - this->d->m_record->property("codecLib").toString() == "gstreamer"? - "webmmux": "webm"; + QMetaObject::invokeMethod(this->d->m_record.data(), + "defaultFormat", + Q_RETURN_ARG(QString, defaultFormat)); this->setFormat(defaultFormat); } void Recording::resetAudioCaps() { - this->setAudioCaps(AkCaps()); + this->setAudioCaps({}); } void Recording::resetVideoCaps() { - this->setVideoCaps(AkCaps()); + this->setVideoCaps({}); } void Recording::resetRecordAudio() @@ -487,12 +506,11 @@ if (!this->d->m_record) return; - auto codecLib = this->d->m_record->property("codecLib").toString(); - - if (codecLib.isEmpty()) - return; - - this->setFormat(codecLib == "gstreamer"? "webmmux": "webm"); + QString defaultFormat; + QMetaObject::invokeMethod(this->d->m_record.data(), + "defaultFormat", + Q_RETURN_ARG(QString, defaultFormat)); + this->setFormat(defaultFormat); } void Recording::loadProperties() @@ -501,19 +519,23 @@ config.beginGroup("Libraries"); - if (this->d->m_record) - this->d->m_record->setProperty("codecLib", - config.value("MultiSink.codecLib", - this->d->m_record->property("codecLib"))); + if (this->d->m_recordSettings) { + auto codecLib = + config.value("MultiSink.codecLib", + this->d->m_recordSettings->property("codecLib")); + this->d->m_recordSettings->setProperty("codecLib", codecLib); + } config.endGroup(); QString defaultFormat; - if (this->d->m_record) - defaultFormat = - this->d->m_record->property("codecLib").toString() == "gstreamer"? - "webmmux": "webm"; + if (this->d->m_record) { + QString defaultFormat; + QMetaObject::invokeMethod(this->d->m_record.data(), + "defaultFormat", + Q_RETURN_ARG(QString, defaultFormat)); + } QString preferredFormat = this->d->m_availableFormats.isEmpty() @@ -875,9 +897,10 @@ QSettings config; config.beginGroup("Libraries"); - if (this->d->m_record) - config.setValue("MultiSink.codecLib", - this->d->m_record->property("codecLib")); + if (this->d->m_recordSettings) { + auto codecLib = this->d->m_recordSettings->property("codecLib"); + config.setValue("MultiSink.codecLib", codecLib); + } config.endGroup(); } diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/recording.h webcamoid-8.8.0+dfsg/StandAlone/src/recording.h --- webcamoid-8.6.1+dfsg/StandAlone/src/recording.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/recording.h 2021-02-15 15:25:23.000000000 +0000 @@ -24,10 +24,11 @@ class RecordingPrivate; class Recording; -class AkCaps; +class AkAudioCaps; +class AkVideoCaps; class QQmlApplicationEngine; -typedef QSharedPointer RecordingPtr; +using RecordingPtr = QSharedPointer; class Recording: public QObject { @@ -40,12 +41,12 @@ WRITE setFormat RESET resetFormat NOTIFY formatChanged) - Q_PROPERTY(AkCaps audioCaps + Q_PROPERTY(AkAudioCaps audioCaps READ audioCaps WRITE setAudioCaps RESET resetAudioCaps NOTIFY audioCapsChanged) - Q_PROPERTY(AkCaps videoCaps + Q_PROPERTY(AkVideoCaps videoCaps READ videoCaps WRITE setVideoCaps RESET resetVideoCaps @@ -73,8 +74,8 @@ Q_INVOKABLE QStringList availableFormats() const; Q_INVOKABLE QString format() const; - Q_INVOKABLE AkCaps audioCaps() const; - Q_INVOKABLE AkCaps videoCaps() const; + Q_INVOKABLE AkAudioCaps audioCaps() const; + Q_INVOKABLE AkVideoCaps videoCaps() const; Q_INVOKABLE bool recordAudio() const; Q_INVOKABLE QString videoFileName() const; Q_INVOKABLE AkElement::ElementState state() const; @@ -91,16 +92,16 @@ signals: void availableFormatsChanged(const QStringList &availableFormats); void formatChanged(const QString &format); - void audioCapsChanged(const AkCaps &audioCaps); - void videoCapsChanged(const AkCaps &videoCaps); + void audioCapsChanged(const AkAudioCaps &audioCaps); + void videoCapsChanged(const AkVideoCaps &videoCaps); void recordAudioChanged(bool recordAudio); void videoFileNameChanged(const QString &videoFileName); void stateChanged(AkElement::ElementState state); public slots: void setFormat(const QString &format); - void setAudioCaps(const AkCaps &audioCaps); - void setVideoCaps(const AkCaps &videoCaps); + void setAudioCaps(const AkAudioCaps &audioCaps); + void setVideoCaps(const AkVideoCaps &videoCaps); void setRecordAudio(bool recordAudio); void setVideoFileName(const QString &videoFileName); void setState(AkElement::ElementState state); diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/updates.cpp webcamoid-8.8.0+dfsg/StandAlone/src/updates.cpp --- webcamoid-8.6.1+dfsg/StandAlone/src/updates.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/updates.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -17,7 +17,6 @@ * Web-Site: http://webcamoid.github.io/ */ -#include #include #include #include diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/updates.h webcamoid-8.8.0+dfsg/StandAlone/src/updates.h --- webcamoid-8.6.1+dfsg/StandAlone/src/updates.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/updates.h 2021-02-15 15:25:23.000000000 +0000 @@ -27,7 +27,7 @@ class QQmlApplicationEngine; class QNetworkReply; -typedef QSharedPointer UpdatesPtr; +using UpdatesPtr = QSharedPointer; class Updates: public QObject { diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/videodisplay.cpp webcamoid-8.8.0+dfsg/StandAlone/src/videodisplay.cpp --- webcamoid-8.6.1+dfsg/StandAlone/src/videodisplay.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/videodisplay.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -67,17 +67,13 @@ this->d->m_frame.convertToFormat(QImage::Format_ARGB32); this->d->m_mutex.unlock(); -#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) if (this->window()->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) { -#endif frame = frame.scaled(this->boundingRect().size().toSize(), this->d->m_fillDisplay? Qt::IgnoreAspectRatio: Qt::KeepAspectRatio, Qt::SmoothTransformation); -#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) } -#endif auto videoFrame = this->window()->createTextureFromImage(frame); diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/videoeffects.cpp webcamoid-8.8.0+dfsg/StandAlone/src/videoeffects.cpp --- webcamoid-8.6.1+dfsg/StandAlone/src/videoeffects.cpp 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/videoeffects.cpp 2021-02-15 15:25:23.000000000 +0000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "videoeffects.h" @@ -48,7 +49,7 @@ this->d->m_videoMux = AkElement::create("Multiplex"); if (this->d->m_videoMux) { - this->d->m_videoMux->setProperty("caps", "video/x-raw"); + this->d->m_videoMux->setProperty("caps", QVariant::fromValue(AkCaps("video/x-raw"))); this->d->m_videoMux->setProperty("outputIndex", 0); QObject::connect(this->d->m_videoMux.data(), diff -Nru webcamoid-8.6.1+dfsg/StandAlone/src/videoeffects.h webcamoid-8.8.0+dfsg/StandAlone/src/videoeffects.h --- webcamoid-8.6.1+dfsg/StandAlone/src/videoeffects.h 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/src/videoeffects.h 2021-02-15 15:25:23.000000000 +0000 @@ -26,7 +26,7 @@ class VideoEffects; class QQmlApplicationEngine; -typedef QSharedPointer VideoEffectsPtr; +using VideoEffectsPtr = QSharedPointer; class VideoEffects: public QObject { diff -Nru webcamoid-8.6.1+dfsg/StandAlone/StandAlone.pro webcamoid-8.8.0+dfsg/StandAlone/StandAlone.pro --- webcamoid-8.6.1+dfsg/StandAlone/StandAlone.pro 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/StandAlone.pro 2021-02-15 15:25:23.000000000 +0000 @@ -192,12 +192,10 @@ docs.CONFIG += no_check_exist } -!android { - !macx | !isEmpty(NOAPPBUNDLE) { - INSTALLS += license - license.files = ../COPYING - license.path = $${LICENSEDIR} - } +!macx | !isEmpty(NOAPPBUNDLE) { + INSTALLS += license + license.files = ../COPYING + license.path = $${LICENSEDIR} } unix: !android: !macx { @@ -213,7 +211,7 @@ } android { - QT += concurrent xml + QT += concurrent xml androidextras DISTFILES += \ share/android/AndroidManifest.xml \ @@ -226,4 +224,10 @@ share/android/res/values/libs.xml ANDROID_PACKAGE_SOURCE_DIR = $$PWD/share/android + + INSTALLS += \ + androidFiles + + androidFiles.files = share/android/* + androidFiles.path = $${EXECPREFIX} } diff -Nru webcamoid-8.6.1+dfsg/StandAlone/translations.qrc webcamoid-8.8.0+dfsg/StandAlone/translations.qrc --- webcamoid-8.6.1+dfsg/StandAlone/translations.qrc 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/StandAlone/translations.qrc 2021-02-15 15:25:23.000000000 +0000 @@ -18,6 +18,7 @@ share/ts/pt.qm share/ts/pt_BR.qm share/ts/ru.qm + share/ts/tr.qm share/ts/uk.qm share/ts/zh_CN.qm share/ts/zh_TW.qm diff -Nru webcamoid-8.6.1+dfsg/.travis.yml webcamoid-8.8.0+dfsg/.travis.yml --- webcamoid-8.6.1+dfsg/.travis.yml 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/.travis.yml 2021-02-15 15:25:23.000000000 +0000 @@ -3,61 +3,53 @@ cache: ccache: true timeout: 1000 + directories: + - keystores env: global: - - QTVER=5.12.1 - - PPAQTVER=512 - - QTIFWVER=3.0.6 - - APPIMAGEVER=11 - - ARCH_ROOT_DATE=2019.02.01 + - QTVER=5.15.2 + - PPAQTVER=515 + - QTVER_ANDROID=5.14.2 + - QTIFWVER=4.0.1 + - APPIMAGEVER=12 + - ARCH_ROOT_DATE=2021.02.01 - ARCH_ROOT_URL=https://mirror.rackspace.com/archlinux - - FFMPEG_VERSION=4.1.1 + - SDKVER=6858069 + - NDKVER=r22 + - ANDROID_BUILD_TOOLS_VERSION=30.0.3 + - GITHUB_HUBVER=2.14.2 # BT_KEY - - secure: "sFnbUeX1mP/G4LVT56VDFyDgWS8KKy7qSlmhNg6YRJuhtfcAoiBjJrO300TREg46nUK3QAwSHt/py3F5WSdHcZ2dniV8ON+zLL0qcVxTglB2DHVUeCStYykTqoV3uZoxYYPHXCd1KTW3ZzdSpCaHVl39REtM0R4tMARNkl3lYhEsS7M6TCjispTLLl9qXdSp86IvtMCPx3mcbjcY59pk/fwwUgneRbocD+7DyVZfFvF98UXh5VGPIKry65DLhNowqsDtBZqYqlAih2LAOuJPxCQKe4pEdPZm81kzGduIV1X+AjBEv7W5K8IXdNm4EG7gMS74i4XW4p4Jn5Axr8An4kTsZnTaGUE0t2RjCJicoa3+CkYJTRDM6CoXoBBJQoerued3MVrH7DvuYtslyrmW4nJu8bTNmVGjS8zuPq4QbfZmekxzbMQWjuEcsw7iwAHIf/hDyRtUUX/T4ioDAU5C72Wx6XSSlSlEDCeEBuM3jnsS5zf54g39mgZkPGlbTaRrdYuxmmDBvh9mYzbb1ANcUW3XEu5rA+j69xOeeVLQVbXZJd04zudBzFg5Kyp2cGNI1KC+27ZOvSTRtrG+V7Ham9lEisJ01tUASV0gdUUSSYHPvD8z6bfJF30Gj/W7hBXqOzXpo2SQ/jPHQ4O68tlUlVBYu2HcCCjHncb25NJWpMk=" + - secure: "RiR23dM8ft06+5ezNAlfpJXNRQhFH2Cy3hTY9oWD6nyw0qsydgOA9qlogBP0o1/kikyqt2uxv/VRcqZnBV3nkwEg9AuiCRgOuKqMtFdxwNnF8wqxUUz4pun9FQGLNnKkIznJkV61vsuRs8GSO95X3KEwgsoGPD60WQDDuFj3wXcI1kIN7HEP1t3Kq8lbhsYhbMPPeZBUGYcEjuWMz/GcfdcEUQLD6F0bkfEQgLZ+/d5Nqxk3NTJGM/LUYLKuWOthqsK7qNp/BCTRnOCg44NV3XO0DXti4lNkbtbfbLZIEMfD5EeTnbznBd+AHH2OTnw2Gn5ViVz7Z2C9mZgcN+/XyEJi7K80ab9DR9s+ZLMFO2yyF6MVf7/qiOzL0RT7lGFHt2HPLBpTji3qmgPN4JXaXKfF3nIzOjaoUibhTzwh5NlMpkAFlydmYwhBS3argsKQgeck3YTWUUnQVFvkmhFHVZzFBGtqy+0dPr9WGyay0mKKYpnLHqGk74K23dGnBKzk+iJs9o9zVQaSdvS5XnSeRsQCAYlqEKy/sSdrZnLYAOaLv1f291CIm76+e5B2sIkZaGcox7d3rcYw/tqn7ozgsKcyT1BJq8/ZyYSXsIT826ZeDiZd4MFjSQTeas5c9V85btDq2W9LvA66KqzTq0dH5pfJ67+BJJ7ebxUf4HNw6ME=" + # GITHUB_TOKEN + - secure: "Mttcf69zNcwl9Zuxu2Od5woHe/kCxIuKRmQTTqyfS84vMiq4lWaPA8PNx9vhu7aOrFsGwu158fUVA0+34klW3UNn2H1IBxIXH10gsAmZVnjUuN4jXvQd1kB682dAUrXb7OxEPHj5IhS4STwwYUcto1b+H1tsPr3XMH3fLXSUp2It7eHU10iNwS/J39kVyyOSnWq0g3LgdIeh22zYrAMGvlt7iOqJXgbtdvHel9xG4HSEB9I/QaGqSkO1q9GG2zz9+7rOMRzSQFP0ke2wKeE1NfyYMD9X2ont7gIKkcZx2jad4Sqw/AAw7HM75e5lgLtTfQ0B3QN3Luj20RWPSRJbQL7KNn1KWzrnip2Xe6KSNVvSk066JMkZnr7B3BGTzcoroRI6jsxxLTu9uSCfv6koVIROYcuoUdHKSyZnzR8egoaRXOFC88EnKvSZZTKYaKdQ9kWDUVh6jdXWv8Q5Kx6360CmcGw6mWDRZf6HBIzbeDbOTSzYW5NQrZ/sjN7c4GLySOJNmEpNLwBT9l9A82E4Wju0o74sCxcQ1CqH2xguhTGeEiFwQpOxqy093hEYb6wvArGhvycpgbK7a1vUT0vEoAQmUkamH6zczSckSz9gx4cME429KeTAS16iWB/vIUOgRwy5Ra6vkMn5zFP6iPTRLdiBAhPN+9F4fyHag30ZiIY=" matrix: include: - os: linux - dist: xenial + dist: focal compiler: gcc env: - ARCH_ROOT_BUILD=1 - os: linux - dist: xenial + dist: focal compiler: clang env: - ARCH_ROOT_BUILD=1 - os: linux - dist: xenial + dist: focal compiler: gcc env: - ARCH_ROOT_BUILD=1 - ARCH_ROOT_MINGW=x86_64 - - DAILY_BUILD=1 - os: linux - dist: xenial + dist: focal compiler: gcc env: - ARCH_ROOT_BUILD=1 - ARCH_ROOT_MINGW=i686 - - DAILY_BUILD=1 - - os: linux - dist: xenial - compiler: gcc - env: - - ARCH_ROOT_BUILD=1 - - ARCH_ROOT_MINGW=x86_64 - - RELEASE_BUILD=1 - os: linux - dist: xenial - compiler: gcc - env: - - ARCH_ROOT_BUILD=1 - - ARCH_ROOT_MINGW=i686 - - RELEASE_BUILD=1 - - os: linux - sudo: required + dist: focal services: - docker compiler: gcc @@ -65,7 +57,7 @@ - DOCKERSYS=debian - DOCKERIMG=debian:testing - os: linux - sudo: required + dist: focal services: - docker compiler: clang @@ -73,43 +65,7 @@ - DOCKERSYS=debian - DOCKERIMG=debian:testing - os: linux - sudo: required - services: - - docker - compiler: gcc - env: - - DOCKERSYS=fedora - - DOCKERIMG=fedora:27 - - FEDORAVER=27 - - os: linux - sudo: required - services: - - docker - compiler: clang - env: - - DOCKERSYS=fedora - - DOCKERIMG=fedora:27 - - FEDORAVER=27 - - os: linux - sudo: required - services: - - docker - compiler: gcc - env: - - DOCKERSYS=fedora - - DOCKERIMG=fedora:28 - - FEDORAVER=28 - - os: linux - sudo: required - services: - - docker - compiler: clang - env: - - DOCKERSYS=fedora - - DOCKERIMG=fedora:28 - - FEDORAVER=28 - - os: linux - sudo: required + dist: focal services: - docker compiler: gcc @@ -118,7 +74,7 @@ - DOCKERIMG=fedora:rawhide - FEDORAVER=rawhide - os: linux - sudo: required + dist: focal services: - docker compiler: clang @@ -127,7 +83,7 @@ - DOCKERIMG=fedora:rawhide - FEDORAVER=rawhide - os: linux - sudo: required + dist: focal services: - docker compiler: gcc @@ -135,7 +91,7 @@ - DOCKERSYS=opensuse - DOCKERIMG=opensuse/tumbleweed - os: linux - sudo: required + dist: focal services: - docker compiler: clang @@ -143,174 +99,146 @@ - DOCKERSYS=opensuse - DOCKERIMG=opensuse/tumbleweed - os: linux - sudo: required + dist: focal services: - docker compiler: gcc env: - DOCKERSYS=debian - - DOCKERIMG=ubuntu:xenial + - DOCKERIMG=ubuntu:focal - DAILY_BUILD=1 - os: linux - sudo: required + dist: focal services: - docker compiler: gcc env: - DOCKERSYS=debian - - DOCKERIMG=ubuntu:xenial + - DOCKERIMG=ubuntu:focal - RELEASE_BUILD=1 - os: linux - sudo: required + dist: focal services: - docker compiler: gcc env: - DOCKERSYS=debian - - DOCKERIMG=ubuntu:xenial + - DOCKERIMG=ubuntu:latest - os: linux - sudo: required + dist: focal services: - docker compiler: clang env: - DOCKERSYS=debian - - DOCKERIMG=ubuntu:xenial + - DOCKERIMG=ubuntu:latest - os: linux - sudo: required + dist: focal services: - docker compiler: gcc env: - DOCKERSYS=debian - - DOCKERIMG=ubuntu:bionic + - DOCKERIMG=ubuntu:devel - os: linux - sudo: required + dist: focal services: - docker compiler: clang env: - DOCKERSYS=debian - - DOCKERIMG=ubuntu:bionic - - os: linux - sudo: required - services: - - docker - compiler: gcc - env: - - DOCKERSYS=debian - - DOCKERIMG=ubuntu:cosmic - - os: linux - sudo: required - services: - - docker - compiler: clang - env: - - DOCKERSYS=debian - - DOCKERIMG=ubuntu:cosmic - - os: linux - sudo: required - services: - - docker - compiler: gcc - env: - - DOCKERSYS=debian - - DOCKERIMG=ubuntu:disco - - os: linux - sudo: required - services: - - docker - compiler: clang - env: - - DOCKERSYS=debian - - DOCKERIMG=ubuntu:disco + - DOCKERIMG=ubuntu:devel - os: osx - osx_image: xcode9.1 + osx_image: xcode10.2 compiler: clang env: - DAILY_BUILD=1 - os: osx - osx_image: xcode9.1 + osx_image: xcode10.2 compiler: clang env: - RELEASE_BUILD=1 - os: osx - osx_image: xcode9.1 + osx_image: xcode10.3 compiler: clang - os: osx - osx_image: xcode9.2 + osx_image: xcode11 compiler: clang - os: osx - osx_image: xcode9.3 + osx_image: xcode11.1 compiler: clang - os: osx - osx_image: xcode9.4 + osx_image: xcode11.2 + compiler: clang + - os: osx + osx_image: xcode11.3 + compiler: clang + - os: osx + osx_image: xcode11.4 + compiler: clang + - os: osx + osx_image: xcode11.5 compiler: clang - env: - - DISABLE_CCACHE=1 - os: osx - osx_image: xcode10 + osx_image: xcode11.6 compiler: clang - os: osx - osx_image: xcode10.1 + osx_image: xcode12 + compiler: clang + - os: osx + osx_image: xcode12u + compiler: clang + - os: osx + osx_image: xcode12.2 + compiler: clang + - os: linux + dist: focal compiler: clang - - language: android - jdk: oraclejdk8 - android: - components: - - tools - - platform-tools - - build-tools-28.0.3 - - android-22 - - sys-img-armeabi-v7a-android-24 env: - ANDROID_BUILD=1 + - ANDROID_PLATFORM=24 - COMPILER=clang - - QTVER=5.12.0 - - NDKVER=r18b - - TARGET_ARCH=armv7 - - language: android - jdk: oraclejdk8 - android: - components: - - tools - - platform-tools - - build-tools-28.0.3 - - android-22 - - sys-img-arm64-v8a-android-24 + - TARGET_ARCH=armeabi-v7a + - os: linux + dist: focal + compiler: clang env: - ANDROID_BUILD=1 + - ANDROID_PLATFORM=24 - COMPILER=clang - - QTVER=5.12.0 - - NDKVER=r18b - - TARGET_ARCH=arm64_v8a - - language: android - jdk: oraclejdk8 - android: - components: - - tools - - platform-tools - - build-tools-28.0.3 - - android-22 - - sys-img-x86-android-24 + - TARGET_ARCH=arm64-v8a + - os: linux + dist: focal + compiler: clang env: - ANDROID_BUILD=1 + - ANDROID_PLATFORM=24 - COMPILER=clang - - QTVER=5.12.0 - - NDKVER=r18b - TARGET_ARCH=x86 + - os: linux + dist: focal + compiler: clang + env: + - ANDROID_BUILD=1 + - ANDROID_PLATFORM=24 + - COMPILER=clang + - TARGET_ARCH=x86_64 + - os: linux + dist: focal + compiler: clang + env: + - ANDROID_BUILD=1 + - ANDROID_PLATFORM=24 + - COMPILER=clang + - TARGET_ARCH=armeabi-v7a:arm64-v8a:x86:x86_64 + - DAILY_BUILD=1 before_install: | if [ -z "${ANDROID_BUILD}" ]; then if [ "${TRAVIS_OS_NAME}" = linux ] && [ -z "${ARCH_ROOT_BUILD}" ]; then docker pull ${DOCKERIMG} docker ps -a - docker run -it -d -v ${PWD}:/sources -v $HOME/.ccache:/ccache -e CCACHE_DIR=/ccache -w /sources --name ${DOCKERSYS} ${DOCKERIMG} /bin/sh - elif [ "${TRAVIS_OS_NAME}" = osx ]; then - brew unlink python - brew update - brew upgrade - brew link --overwrite numpy + docker run --privileged -it -d -v ${PWD}:/sources -v $HOME/.ccache:/ccache -e CCACHE_DIR=/ccache -w /sources --name ${DOCKERSYS} ${DOCKERIMG} /bin/sh fi fi @@ -349,10 +277,6 @@ - chmod +x ports/ci/travis/upload.sh - ports/ci/travis/upload.sh -branches: - only: - - master - notifications: recipients: - hipersayan.x@gmail.com diff -Nru webcamoid-8.6.1+dfsg/webcamoid.desktop webcamoid-8.8.0+dfsg/webcamoid.desktop --- webcamoid-8.6.1+dfsg/webcamoid.desktop 2019-03-25 12:04:23.000000000 +0000 +++ webcamoid-8.8.0+dfsg/webcamoid.desktop 2021-02-15 15:25:23.000000000 +0000 @@ -10,13 +10,14 @@ GenericName[it]=Webcam Capture Software GenericName[ja]=ウェブカメラのキャプチャソフトウェア GenericName[ko]=웹캠 캡처 소프트웨어 +GenericName[pl]=Oprogramowanie do przechwytywania z kamery internetowej GenericName[pt]=Software de Captura de Webcam -GenericName[ru]=Веб-камера захвата программного обеспечения +GenericName[ru]=Программа для захвата веб-камеры GenericName[zh_CN]=摄像头捕捉软件 GenericName[zh_TW]=攝像頭捕捉軟件 Comment=Take photos and record videos with your webcam Comment[ca]=Fer fotos i gravar vídeos amb la seva webcam -Comment[de]=Maak foto's en video's opnemen met uw webcam +Comment[de]=Nehme Fotos und Videos mit deiner Webcam auf Comment[el]=Τραβήξτε φωτογραφίες και εγγραφή βίντεο με την κάμερα σας Comment[es]=Tome fotos y grabe videos con su camara web Comment[fr]=Prenez des photos et enregistrer des vidéos avec votre webcam @@ -24,8 +25,9 @@ Comment[it]=Scatta foto e registrare video con la tua webcam Comment[ja]=ウェブカメラで写真や記録ビデオを撮影 Comment[ko]=웹캠으로 사진과 기록 비디오를 촬영 +Comment[pl]=Rób zdjęcia i nagrywaj wideo z kamery internetowej Comment[pt]=Tirar fotos e gravar vídeos com sua webcam -Comment[ru]=Возьмите фотографии и записывать видео с веб-камеры +Comment[ru]=Снимайте фотографии и записывайте видео с веб-камеры Comment[zh_CN]=拍摄照片和录制视频与您的摄像头 Comment[zh_TW]=拍攝照片和錄製視頻與您的攝像頭 Keywords=photo;video;webcam; diff -Nru webcamoid-8.6.1+dfsg/webcamoid.metainfo.xml webcamoid-8.8.0+dfsg/webcamoid.metainfo.xml --- webcamoid-8.6.1+dfsg/webcamoid.metainfo.xml 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/webcamoid.metainfo.xml 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,113 @@ + + + webcamoid.desktop + Webcamoid + Take photos and record videos with your webcam + Fer fotos i gravar vídeos amb la seva webcam + Maak foto's en video's opnemen met uw webcam + Τραβήξτε φωτογραφίες και εγγραφή βίντεο με την κάμερα σας + Tome fotos y grabe videos con su cámara web + Prenez des photos et enregistrer des vidéos avec votre webcam + Facer fotos e gravar vídeos coa súa cámara web + Scatta foto e registrare video con la tua webcam + ウェブカメラで写真や記録ビデオを撮影 + 웹캠으로 사진과 기록 비디오를 촬영 + Tirar fotos e gravar vídeos com sua webcam + Возьмите фотографии и записывать видео с веб-камеры + 拍摄照片和录制视频与您的摄像头 + 拍攝照片和錄製視頻與您的攝像頭 + Gonzalo Exequiel Pedone + +

+ Webcamoid is a full featured and multiplatform webcam suite. +

+
    +
  • Cross-platform (GNU/Linux, Mac, Windows)
  • +
  • Take pictures and record videos with the webcam
  • +
  • Manages multiple webcams
  • +
  • Written in C++ and Qt
  • +
  • Custom controls for each webcam
  • +
  • Add funny effects to the webcam
  • +
  • +60 effects available
  • +
  • Translated to many languages.
  • +
  • Use custom network and local files as capture devices
  • +
  • Capture from desktop
  • +
  • Many recording formats
  • +
  • Virtual webcam support for feeding other programs
  • +
+
+ + webcam + desktop + record + capture + + CC0-1.0 + GPL-3.0+ + https://github.com/webcamoid/webcamoid/issues + https://github.com/webcamoid/webcamoid/#donations + https://github.com/webcamoid/webcamoid/wiki + https://webcamoid.github.io/ + Webcamoid + none + + + Simple and intuitive + https://webcamoid.github.io/theme/images/screenshots/Main.png + + + Take pictures and record videos + https://webcamoid.github.io/theme/images/screenshots/Recording.png + + + Apply funny effects + https://webcamoid.github.io/theme/images/screenshots/Effects.png + + + Capture from desktop + https://webcamoid.github.io/theme/images/screenshots/DesktopCapture.png + + + Create a virtual webcam + https://webcamoid.github.io/theme/images/screenshots/VirtualCamera.png + + + hipersayan.x_AT_gmail_com + + + + + + + + + + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + +
diff -Nru webcamoid-8.6.1+dfsg/.weblate webcamoid-8.8.0+dfsg/.weblate --- webcamoid-8.6.1+dfsg/.weblate 1970-01-01 00:00:00.000000000 +0000 +++ webcamoid-8.8.0+dfsg/.weblate 2021-02-15 15:25:23.000000000 +0000 @@ -0,0 +1,3 @@ +[weblate] +url = https://hosted.weblate.org/api/ +translation = webcamoid/main