├── .github
├── FUNDING.yml
└── workflows
│ └── linux.yml
├── .gitignore
├── CMakeLists.txt
├── CONTRIBUTING.md
├── COPYING
├── ChangeLog
├── README.md
├── akvcam.kdev4
├── package_info.conf.in
├── ports
├── ci
│ └── linux
│ │ ├── build.sh
│ │ ├── deploy.sh
│ │ └── install_deps.sh
└── deploy
│ ├── installscript.posix.qs
│ └── setup.sh
├── share
├── config_example.ini
└── examples
│ └── output.c
└── src
├── Makefile
├── attributes.c
├── attributes.h
├── buffers.c
├── buffers.h
├── buffers_types.h
├── controls.c
├── controls.h
├── controls_types.h
├── device.c
├── device.h
├── device_types.h
├── dkms.conf
├── driver.c
├── driver.h
├── file_read.c
├── file_read.h
├── format.c
├── format.h
├── format_types.h
├── frame.c
├── frame.h
├── frame_filter.c
├── frame_filter.h
├── frame_filter_types.h
├── frame_types.h
├── ioctl.c
├── ioctl.h
├── list.c
├── list.h
├── list_types.h
├── log.c
├── log.h
├── map.c
├── map.h
├── module.c
├── rbuffer.c
├── rbuffer.h
├── settings.c
├── settings.h
├── utils.c
└── utils.h
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: hipersayanX
2 | patreon: hipersayanx
3 | ko_fi: hipersayanx
4 | liberapay: hipersayanx
5 | custom: ["https://www.paypal.me/WebcamoidDonations", "https://buymeacoffee.com/hipersayanx", "https://webcamoid.github.io/donations#crypto"]
6 |
--------------------------------------------------------------------------------
/.github/workflows/linux.yml:
--------------------------------------------------------------------------------
1 | name: Linux Ubuntu
2 |
3 | on: [push, pull_request]
4 |
5 | env:
6 | QTIFWVER: 4.8.0
7 |
8 | jobs:
9 | build:
10 | name: Ubuntu x86_64
11 | runs-on: ubuntu-latest
12 | strategy:
13 | max-parallel: 10
14 | fail-fast: false
15 | matrix:
16 | include:
17 | - dockerimg: amd64/ubuntu:focal
18 | repository: v4.19.316
19 | kernel_version: 4.19.316-0419316
20 | kernel_version_c: 202406161134
21 | upload: 1
22 | - dockerimg: amd64/ubuntu:focal
23 | repository: v5.4.278
24 | kernel_version: 5.4.278-0504278
25 | kernel_version_c: 202406161242
26 | upload: 0
27 | # Do not update
28 | - dockerimg: amd64/ubuntu:jammy
29 | repository: v5.10.130
30 | kernel_version: 5.10.130-0510130
31 | kernel_version_c: 202207121545
32 | upload: 0
33 | - dockerimg: amd64/ubuntu:jammy
34 | repository: v5.15.161
35 | kernel_version: 5.15.161-0515161
36 | kernel_version_c: 202406161242
37 | upload: 0
38 | - dockerimg: amd64/ubuntu:mantic
39 | repository: v6.1.95
40 | kernel_version: 6.1.95-060195
41 | kernel_version_c: 202406211343
42 | upload: 0
43 | - dockerimg: amd64/ubuntu:oracular
44 | repository: v6.6.35
45 | kernel_version: 6.6.35-060635
46 | kernel_version_c: 202406210941
47 | upload: 0
48 | - dockerimg: amd64/ubuntu:noble
49 | repository: v6.8.12
50 | kernel_version: 6.8.12-060812
51 | kernel_version_c: 202405300722
52 | upload: 0
53 | - dockerimg: amd64/ubuntu:noble
54 | repository: v6.9.3
55 | kernel_version: 6.9.3-060903
56 | kernel_version_c: 202405300957
57 | upload: 0
58 | steps:
59 | - uses: actions/checkout@v2
60 | - name: Release build
61 | uses: addnab/docker-run-action@v3
62 | if: ${{ startsWith(github.ref, 'refs/tags/') }}
63 | with:
64 | username: ${{ secrets.DOCKER_USERNAME }}
65 | password: ${{ secrets.DOCKER_PASSWORD }}
66 | registry: gcr.io
67 | image: ${{ matrix.dockerimg }}
68 | options: >-
69 | --privileged
70 | -v ${{ github.workspace }}:/sources
71 | -e GITHUB_REF=${{ env.GITHUB_REF }}
72 | -e GITHUB_SERVER_URL=${{ env.GITHUB_SERVER_URL }}
73 | -e GITHUB_REPOSITORY=${{ env.GITHUB_REPOSITORY }}
74 | -e GITHUB_RUN_ID=${{ env.GITHUB_RUN_ID }}
75 | -e DOCKERIMG=${{ matrix.dockerimg }}
76 | -e REPOSITORY=${{ matrix.repository }}
77 | -e KERNEL_VERSION=${{ matrix.kernel_version }}
78 | -e KERNEL_VERSION_C=${{ matrix.kernel_version_c }}
79 | -e ARCHITECTURE=amd64
80 | -e QTIFWVER=${{ env.QTIFWVER }}
81 | -e UPLOAD=${{ matrix.upload }}
82 | run: |
83 | cd /sources
84 | echo
85 | echo Install dependencies
86 | echo
87 | chmod +x ports/ci/linux/install_deps.sh
88 | ./ports/ci/linux/install_deps.sh
89 | echo
90 | echo Release Build
91 | echo
92 | chmod +x ports/ci/linux/build.sh
93 | ./ports/ci/linux/build.sh
94 | echo
95 | echo Release Deploy
96 | echo
97 | chmod +x ports/ci/linux/deploy.sh
98 | ./ports/ci/linux/deploy.sh
99 | - name: Daily build
100 | uses: addnab/docker-run-action@v3
101 | if: ${{ !startsWith(github.ref, 'refs/tags/') }}
102 | with:
103 | username: ${{ secrets.DOCKER_USERNAME }}
104 | password: ${{ secrets.DOCKER_PASSWORD }}
105 | registry: gcr.io
106 | image: ${{ matrix.dockerimg }}
107 | options: >-
108 | --privileged
109 | -v ${{ github.workspace }}:/sources
110 | -e GITHUB_REF=${{ env.GITHUB_REF }}
111 | -e GITHUB_SERVER_URL=${{ env.GITHUB_SERVER_URL }}
112 | -e GITHUB_REPOSITORY=${{ env.GITHUB_REPOSITORY }}
113 | -e GITHUB_RUN_ID=${{ env.GITHUB_RUN_ID }}
114 | -e DOCKERIMG=${{ matrix.dockerimg }}
115 | -e REPOSITORY=${{ matrix.repository }}
116 | -e KERNEL_VERSION=${{ matrix.kernel_version }}
117 | -e KERNEL_VERSION_C=${{ matrix.kernel_version_c }}
118 | -e ARCHITECTURE=amd64
119 | -e QTIFWVER=${{ env.QTIFWVER }}
120 | -e UPLOAD=${{ matrix.upload }}
121 | -e DAILY_BUILD=1
122 | run: |
123 | cd /sources
124 | echo
125 | echo Install dependencies
126 | echo
127 | chmod +x ports/ci/linux/install_deps.sh
128 | ./ports/ci/linux/install_deps.sh
129 | echo
130 | echo Daily Build
131 | echo
132 | chmod +x ports/ci/linux/build.sh
133 | ./ports/ci/linux/build.sh
134 | echo
135 | echo Daily Deploy
136 | echo
137 | chmod +x ports/ci/linux/deploy.sh
138 | ./ports/ci/linux/deploy.sh
139 | - name: Release Upload
140 | uses: softprops/action-gh-release@v1
141 | if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.upload }}
142 | with:
143 | files: packages-v4.19/*
144 | env:
145 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
146 | - name: Daily Build Upload
147 | uses: softprops/action-gh-release@v1
148 | if: ${{ !startsWith(github.ref, 'refs/tags/') && matrix.upload }}
149 | with:
150 | body: "${{ github.event.head_commit.message }} (commit: ${{ github.sha }})
**Note**: Ignore the commit information of the tag, the files in the release keep updating with every new build, these packages were built from ${{ github.sha }} commit."
151 | prerelease: true
152 | files: packages-v4.19/*
153 | name: Daily Build
154 | tag_name: daily-build
155 | env:
156 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
157 | # multiarch:
158 | # name: Ubuntu Multiarch
159 | # runs-on: ubuntu-latest
160 | # strategy:
161 | # max-parallel: 10
162 | # fail-fast: false
163 | # matrix:
164 | # include:
165 | # - distro: ubuntu_latest
166 | # architecture: aarch64
167 | # repository: v6.8.12
168 | # kernel_version: 6.8.12-060812
169 | # kernel_version_c: 202405300722
170 | # upload: 1
171 | # - distro: ubuntu_latest
172 | # architecture: aarch64
173 | # repository: v6.9.3
174 | # kernel_version: 6.9.3-060903
175 | # kernel_version_c: 202405300957
176 | # upload: 0
177 | # steps:
178 | # - uses: actions/checkout@v2
179 | # - name: Release build
180 | # uses: uraimo/run-on-arch-action@v2
181 | # if: ${{ startsWith(github.ref, 'refs/tags/') }}
182 | # with:
183 | # arch: ${{ matrix.architecture }}
184 | # distro: ${{ matrix.distro }}
185 | # githubToken: ${{ github.token }}
186 | # dockerRunArgs: |
187 | # --privileged
188 | # -v "${{ github.workspace }}:/sources"
189 | # env: |
190 | # GITHUB_REF: "${{ env.GITHUB_REF }}"
191 | # GITHUB_SERVER_URL: "${{ env.GITHUB_SERVER_URL }}"
192 | # GITHUB_REPOSITORY: "${{ env.GITHUB_REPOSITORY }}"
193 | # GITHUB_RUN_ID: "${{ env.GITHUB_RUN_ID }}"
194 | # REPOSITORY: ${{ matrix.repository }}
195 | # ARCHITECTURE: ${{ matrix.architecture }}
196 | # KERNEL_VERSION: ${{ matrix.kernel_version }}
197 | # KERNEL_VERSION_C: ${{ matrix.kernel_version_c }}
198 | # QTIFWVER: ${{ env.QTIFWVER }}
199 | # UPLOAD: ${{ matrix.upload }}
200 | # run: |
201 | # cd /sources
202 | # echo
203 | # echo Install dependencies
204 | # echo
205 | # chmod +x ports/ci/linux/install_deps.sh
206 | # ./ports/ci/linux/install_deps.sh
207 | # echo
208 | # echo Daily Build
209 | # echo
210 | # chmod +x ports/ci/linux/build.sh
211 | # ./ports/ci/linux/build.sh
212 | # echo
213 | # echo Daily Deploy
214 | # echo
215 | # chmod +x ports/ci/linux/deploy.sh
216 | # ./ports/ci/linux/deploy.sh
217 | # - name: Daily build
218 | # uses: uraimo/run-on-arch-action@v2
219 | # if: ${{ !startsWith(github.ref, 'refs/tags/') }}
220 | # with:
221 | # arch: ${{ matrix.architecture }}
222 | # distro: ${{ matrix.distro }}
223 | # githubToken: ${{ github.token }}
224 | # dockerRunArgs: |
225 | # --privileged
226 | # -v "${{ github.workspace }}:/sources"
227 | # env: |
228 | # GITHUB_REF: "${{ env.GITHUB_REF }}"
229 | # GITHUB_SERVER_URL: "${{ env.GITHUB_SERVER_URL }}"
230 | # GITHUB_REPOSITORY: "${{ env.GITHUB_REPOSITORY }}"
231 | # GITHUB_RUN_ID: "${{ env.GITHUB_RUN_ID }}"
232 | # REPOSITORY: ${{ matrix.repository }}
233 | # ARCHITECTURE: ${{ matrix.architecture }}
234 | # KERNEL_VERSION: ${{ matrix.kernel_version }}
235 | # KERNEL_VERSION_C: ${{ matrix.kernel_version_c }}
236 | # QTIFWVER: ${{ env.QTIFWVER }}
237 | # DAILY_BUILD: 1
238 | # run: |
239 | # cd /sources
240 | # echo
241 | # echo Install dependencies
242 | # echo
243 | # chmod +x ports/ci/linux/install_deps.sh
244 | # ./ports/ci/linux/install_deps.sh
245 | # echo
246 | # echo Daily Build
247 | # echo
248 | # chmod +x ports/ci/linux/build.sh
249 | # ./ports/ci/linux/build.sh
250 | # echo
251 | # echo Daily Deploy
252 | # echo
253 | # chmod +x ports/ci/linux/deploy.sh
254 | # ./ports/ci/linux/deploy.sh
255 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Makefile
2 | !src/Makefile
3 | *.user
4 | *.pro.user.*
5 | *.cmd
6 | *.mk
7 | *.mod
8 | *.mod.c
9 | *.mod.o
10 | *.o
11 | *.ko
12 | *.so
13 | *.so.*
14 | Module.symvers
15 | modules.order
16 | .qmake.stash
17 | *.kate-swp
18 | *.tmp
19 | *.o.d
20 | *.ur-safe
21 | __pycache__
22 | packages_auto
23 | .kdev4
24 | CMakeLists.txt.user.*
25 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # akvcam, virtual camera for Linux.
2 | # Copyright (C) 2021 Gonzalo Exequiel Pedone
3 | #
4 | # This program is free software; you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation; either version 2 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License along
15 | # with this program; if not, write to the Free Software Foundation, Inc.,
16 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 |
18 | cmake_minimum_required(VERSION 3.14)
19 |
20 | project(akvcam LANGUAGES C)
21 |
22 | set(CMAKE_VERBOSE_MAKEFILE ON)
23 | execute_process(COMMAND uname -r
24 | OUTPUT_VARIABLE KERNEL_RELEASE
25 | OUTPUT_STRIP_TRAILING_WHITESPACE)
26 | set(KERNEL_DIR /lib/modules/${KERNEL_RELEASE}/build CACHE PATH "Kernel sources")
27 | set(USE_SPARSE OFF CACHE BOOL "Use sparse for bug catching")
28 | set(SPARSE_MODE 2 CACHE STRING "Sparse mode")
29 | set(DAILY_BUILD OFF CACHE BOOL "Mark this as a daily build")
30 |
31 | if (USE_SPARSE)
32 | set(MAKE_CMD make KERNEL_DIR=${KERNEL_DIR} USE_SPARSE=1 SPARSE_MODE=${SPARSE_MODE})
33 | else ()
34 | set(MAKE_CMD make KERNEL_DIR=${KERNEL_DIR})
35 | endif ()
36 |
37 | file(GLOB_RECURSE MODULE_SOURCES
38 | RELATIVE ${CMAKE_SOURCE_DIR}
39 | CONFIGURE_DEPENDS
40 | ${CMAKE_SOURCE_DIR}/src/*.h
41 | ${CMAKE_SOURCE_DIR}/src/*.c)
42 |
43 | foreach(SOURCE_FILE ${MODULE_SOURCES})
44 | configure_file(${SOURCE_FILE} ${SOURCE_FILE} COPYONLY)
45 | endforeach()
46 |
47 | configure_file(src/dkms.conf src/dkms.conf COPYONLY)
48 | configure_file(src/Makefile src/Makefile COPYONLY)
49 | add_custom_target(akvcam ALL ${MAKE_CMD}
50 | BYPRODUCTS src/akvcam.ko
51 | WORKING_DIRECTORY src
52 | VERBATIM
53 | SOURCES src/dkms.conf
54 | src/Makefile
55 | share/config_example.ini)
56 |
57 | # This is a hack for making possible for the IDE to detect the kernel include
58 | # directories. Don't try to build it, because it won't.
59 | add_library(akvcam-sources STATIC EXCLUDE_FROM_ALL ${MODULE_SOURCES})
60 | include_directories(src
61 | ${KERNEL_DIR}/include
62 | ${KERNEL_DIR}/include/linux
63 | ${KERNEL_DIR}/include/uapi
64 | ${KERNEL_DIR}/arch/x86/include
65 | ${KERNEL_DIR}/arch/x86/include/generated)
66 | add_definitions(-D__KERNEL__
67 | -DCONFIG_COMPAT
68 | -DCONFIG_HZ=300
69 | -DCONFIG_PAGE_OFFSET=0
70 | -DCONFIG_PCI
71 | -DKBUILD_MODNAME="")
72 |
73 | file(READ src/Makefile SRC_MAKEFILE)
74 | string(REGEX MATCH "MODULE_VERSION *= *([0-9]+.[0-9]+.[0-9]+)" _ ${SRC_MAKEFILE})
75 | set(VERSION ${CMAKE_MATCH_1})
76 | set(QTIFW_TARGET_DIR "\@ApplicationsDir\@/akvcam")
77 | configure_file(package_info.conf.in package_info.conf)
78 |
79 | install(FILES ${MODULE_SOURCES}
80 | src/dkms.conf
81 | src/Makefile
82 | COPYING
83 | DESTINATION .)
84 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # akvcam Individual Contributor License Agreement #
2 |
3 | Thank you for your interest in contributing to akvcam ("We" or "Us").
4 |
5 | This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please sign it and send it to Us by email, following the instructions at CONTRIBUTING.md. This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Us.
6 |
7 | You are accepting this agreement by making a pull request to the repository.
8 |
9 | ## 1. Definitions ##
10 |
11 | "You" means the individual who Submits a Contribution to Us.
12 |
13 | "Contribution" means any work of authorship that is Submitted by You to Us in which You own or assert ownership of the Copyright. If You do not own the Copyright in the entire work of authorship, please follow the instructions in CONTRIBUTING.md.
14 |
15 | "Copyright" means all rights protecting works of authorship owned or controlled by You, including copyright, moral and neighboring rights, as appropriate, for the full term of their existence including any extensions by You.
16 |
17 | "Material" means the work of authorship which is made available by Us to third parties. When this Agreement covers more than one software project, the Material means the work of authorship to which the Contribution was Submitted. After You Submit the Contribution, it may be included in the Material.
18 |
19 | "Submit" means any form of electronic, verbal, or written communication sent to Us or our representatives, including but not limited to electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Us for the purpose of discussing and improving the Material, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
20 |
21 | "Submission Date" means the date on which You Submit a Contribution to Us.
22 |
23 | "Effective Date" means the date You execute this Agreement or the date You first Submit a Contribution to Us, whichever is earlier.
24 |
25 | "Media" means any portion of a Contribution which is not software.
26 |
27 | ## 2. Grant of Rights ##
28 |
29 | ### 2.1 Copyright License ###
30 |
31 | (a) You retain ownership of the Copyright in Your Contribution and have the same rights to use or license the Contribution which You would have had without entering into the Agreement.
32 |
33 | (b) To the maximum extent permitted by the relevant law, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable license under the Copyright covering the Contribution, with the right to sublicense such rights through multiple tiers of sublicensees, to reproduce, modify, display, perform and distribute the Contribution as part of the Material; provided that this license is conditioned upon compliance with Section 2.3.
34 |
35 | ### 2.2 Patent License ###
36 |
37 | For patent claims including, without limitation, method, process, and apparatus claims which You own, control or have the right to grant, now or in the future, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable patent license, with the right to sublicense these rights to multiple tiers of sublicensees, to make, have made, use, sell, offer for sale, import and otherwise transfer the Contribution and the Contribution in combination with the Material (and portions of such combination). This license is granted only to the extent that the exercise of the licensed rights infringes such patent claims; and provided that this license is conditioned upon compliance with Section 2.3.
38 |
39 | ### 2.3 Outbound License ###
40 |
41 | As a condition on the grant of rights in Sections 2.1 and 2.2, We agree to license the Contribution only under the terms of the license or licenses which We are using on the Submission Date for the Material or any licenses on the Free Software Foundation's list of "Recommended copyleft licenses" on or after the Effective Date, whether or not such licenses are subsequently disapproved (including any right to adopt any future version of a license if permitted).
42 |
43 | In addition, We may use the following licenses for Media in the Contribution: Creative Commons Attribution Share Alike 3.0 (including any right to adopt any future version of a license if permitted).
44 |
45 | **2.4 Moral Rights.** If moral rights apply to the Contribution, to the maximum extent permitted by law, You waive and agree not to assert such moral rights against Us or our successors in interest, or any of our licensees, either direct or indirect.
46 |
47 | **2.5 Our Rights.** You acknowledge that We are not obligated to use Your Contribution as part of the Material and may decide to include any Contribution We consider appropriate.
48 |
49 | **2.6 Reservation of Rights.** Any rights not expressly licensed under this section are expressly reserved by You.
50 |
51 | ## 3. Agreement ##
52 |
53 | You confirm that:
54 |
55 | (a) You have the legal authority to enter into this Agreement.
56 |
57 | (b) You own the Copyright and patent claims covering the Contribution which are required to grant the rights under Section 2.
58 |
59 | (c) The grant of rights under Section 2 does not violate any grant of rights which You have made to third parties, including Your employer. If You are an employee, You have had Your employer approve this Agreement or sign the Entity version of this document. If You are less than eighteen years old, please have Your parents or guardian sign the Agreement.
60 |
61 | (d) You have followed the instructions in CONTRIBUTING.md, if You do not own the Copyright in the entire work of authorship Submitted.
62 |
63 | ## 4. Disclaimer ##
64 |
65 | EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO US. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW.
66 |
67 | ## 5. Consequential Damage Waiver ##
68 |
69 | TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED.
70 |
71 | ## 6. Miscellaneous ##
72 |
73 | 6.1 This Agreement will be governed by and construed in accordance with the laws of Argentina excluding its conflicts of law provisions. Under certain circumstances, the governing law in this section might be superseded by the United Nations Convention on Contracts for the International Sale of Goods ("UN Convention") and the parties intend to avoid the application of the UN Convention to this Agreement and, thus, exclude the application of the UN Convention in its entirety to this Agreement.
74 |
75 | 6.2 This Agreement sets out the entire agreement between You and Us for Your Contributions to Us and overrides all other agreements or understandings.
76 |
77 | 6.3 If You or We assign the rights or obligations received through this Agreement to a third party, as a condition of the assignment, that third party must agree in writing to abide by all the rights and obligations in the Agreement.
78 |
79 | 6.4 The failure of either party to require performance by the other party of any provision of this Agreement in one situation shall not affect the right of a party to require such performance at any time in the future. A waiver of performance under a provision in one situation shall not be considered a waiver of the performance of the provision in the future or a waiver of the provision in its entirety.
80 |
81 | 6.5 If any provision of this Agreement is found void and unenforceable, such provision will be replaced to the extent possible with a provision that comes closest to the meaning of the original provision and which is enforceable. The terms and conditions set forth in this Agreement shall apply notwithstanding any failure of essential purpose of this Agreement or any limited remedy to the maximum extent possible under law.
82 |
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
1 | akvcam 1.2.6:
2 |
3 | - Minimum supported kernel version: 4.19.
4 | - Fix v6.8 renamed symbols (Thanks to @iam-TJ).
5 |
6 | akvcam 1.2.5:
7 |
8 | - Fixed missing V4L2_DEVICE_NAME_SIZE variable in Linux version > 6.7.
9 |
10 | akvcam 1.2.4:
11 |
12 | - Minimum supported kernel version: 4.14.
13 | - Remove deprecated REMAKE_INITRD (Thanks to dkadioglu).
14 | - Minimum number of buffers decreased to 2 (issue #20).
15 | - Added makeself as a new install option.
16 |
17 | akvcam 1.2.3:
18 |
19 | - Set v4l2_buffer.type after memset() (Thanks to Hirosam1).
20 |
21 | akvcam 1.2.2:
22 |
23 | - Properly mark installer as a GNU/Linux only installer.
24 |
25 | akvcam 1.2.1:
26 |
27 | - Fixed 'Swap Read and Blue' control.
28 | - Switched top build system from Qmake to Cmake, you can still use make
29 | command to build the module.
30 | - Removed the global_deleter, and all global objects, objects now have a well
31 | defined lifetime.
32 | - Removed dangerous static non-constant variables, this should make the module
33 | a bit more stable.
34 |
35 | akvcam 1.2.0:
36 |
37 | - Added support for linux 5.10.
38 | - Use V4L2 kernel APIs for dealing with almost anything, v4l2 protocol is too
39 | much complicated to be handled manually.
40 | - Added DMABUF support.
41 | - RW devices can also have controls too.
42 | - Removed a bunch of useless code.
43 |
44 | akvcam 1.1.1:
45 |
46 | - Minimum supported kernel version: 4.4
47 | - Maximum tested kernel version: 5.9
48 | - Install the module to /usr/src when running make install.
49 | - Added USE_DKMS for make install to install the module using DKMS.
50 | - Replaced spin_lock with mutex_lock_interruptible.
51 | - Don't stop streaming if the released node is not the node that started the
52 | streaming.
53 | - Print ioctl error messages.
54 | - Print the device that's calling the node and ioctl functions.
55 | - Added installer and daily build.
56 |
57 | akvcam 1.1.0:
58 |
59 | - Make it work with linux 5.7.
60 | - Allow setting the device number.
61 | - Added virtual camera usage example.
62 |
63 | akvcam 1.0.4:
64 |
65 | - Update to support 5.6 kernel.
66 |
67 | akvcam 1.0.3:
68 |
69 | - Set video_device.device_caps when creating akvcam_device.
70 |
71 | akvcam 1.0.2:
72 |
73 | - Fixed nearest video format calculation.
74 |
75 | akvcam 1.0.1:
76 |
77 | - Added support for linux 5.0.
78 |
79 | akvcam 1.0.0:
80 |
81 | - First release.
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # akvcam, Virtual camera driver for Linux #
2 |
3 | akvcam is a fully compliant V4L2 virtual camera driver for Linux.
4 |
5 | ## Features ##
6 |
7 | * Flexible configuration with a simple INI file like.
8 | * Support for map, user pointer, and read/write modes.
9 | * Can cat and echo to the device.
10 | * Supports emulated camera controls in capture devices (brightness, contrast, saturation, etc.).
11 | * Configurable default picture in case no input signal available.
12 | * The devices can't be rejected by programs that rejects M2M devices.
13 | * Fully compliant with V4L2 standard.
14 | * Support for LTS kernels.
15 |
16 | ## Build and Install ##
17 |
18 | Visit the [wiki](https://github.com/webcamoid/akvcam/wiki) for a comprehensive compile and install instructions.
19 |
20 | ## Downloads ##
21 |
22 | [](https://github.com/webcamoid/akvcam/releases)
23 | [](https://github.com/webcamoid/akvcam/releases/tag/daily-build)
24 | [](https://tooomm.github.io/github-release-stats/?username=webcamoid&repository=akvcam)
25 |
26 | ## Donations ##
27 |
28 | If you are interested in donating to the project you can look at all available methods in the [donations page](https://webcamoid.github.io/donations).
29 |
30 | ## Status ##
31 |
32 | [](https://github.com/webcamoid/akvcam/actions/workflows/linux.yml)
33 | [](https://www.codacy.com/gh/webcamoid/akvcam/dashboard?utm_source=github.com&utm_medium=referral&utm_content=webcamoid/akvcam&utm_campaign=Badge_Grade)
34 | [](https://www.openhub.net/p/akvcam)
35 |
36 | ## Reporting Bugs ##
37 |
38 | Report all issues in the [issues tracker](http://github.com/webcamoid/akvcam/issues).
39 |
--------------------------------------------------------------------------------
/akvcam.kdev4:
--------------------------------------------------------------------------------
1 | [Project]
2 | CreatedFrom=CMakeLists.txt
3 | Manager=KDevCMakeManager
4 | Name=akvcam
5 |
--------------------------------------------------------------------------------
/package_info.conf.in:
--------------------------------------------------------------------------------
1 | [Package]
2 | name = akvcam
3 | version = @VERSION@
4 | sourcesDir = @CMAKE_SOURCE_DIR@
5 | targetPlatform = posix
6 | buildInfoFile = share/build-info.txt
7 | targetArch = any
8 | outputFormats = QtIFW, Makeself
9 | hideArch = true
10 | dailyBuild = @DAILY_BUILD@
11 |
12 | [Makeself]
13 | name = akvcam-installer-cli
14 | appName = akvcam
15 | label = Install akvcam
16 | targetDir = /opt/akvcam
17 | license = COPYING
18 | installScript = ports/deploy/setup.sh
19 | installScriptArgs = akvcam @VERSION@
20 | pkgTargetPlatform = linux
21 |
22 | [QtIFW]
23 | organization = org.webcamoidprj
24 | name = akvcam-installer-gui
25 | appName = akvcam
26 | title = akvcam, fully compliant V4L2 virtual camera driver for Linux.
27 | description = Install akvcam
28 | url = https://github.com/webcamoid/akvcam
29 | targetDir = @QTIFW_TARGET_DIR@
30 | license = COPYING
31 | licenseName = GNU General Public License v2.0 or later
32 | script = ports/deploy/installscript.posix.qs
33 | changeLog = ChangeLog
34 | pkgTargetPlatform = linux
35 |
--------------------------------------------------------------------------------
/ports/ci/linux/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # akvcam, virtual camera for Linux.
4 | # Copyright (C) 2018 Gonzalo Exequiel Pedone
5 | #
6 | # This program is free software; you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation; either version 2 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License along
17 | # with this program; if not, write to the Free Software Foundation, Inc.,
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 |
20 | echo "Available kernel headers:"
21 | echo
22 | ls /usr/src | grep linux-headers- | sort
23 | echo
24 |
25 | # Build the driver and show it's info.
26 |
27 | export INSTALL_PREFIX="${PWD}/package-data-${REPOSITORY%.*}"
28 | cp -vf package_info.conf.in package_info.conf
29 | version=$(grep '^MODULE_VERSION' src/Makefile | awk -F= '{print $2}' | tr -d ' ')
30 | sed -i "s|@VERSION@|${version}|g" package_info.conf
31 | sed -i "s|@CMAKE_SOURCE_DIR@|${PWD}|g" package_info.conf
32 | sed -i "s|@QTIFW_TARGET_DIR@|@ApplicationsDir@/akvcam|g" package_info.conf
33 | sed -i "s|@DAILY_BUILD@|${DAILY_BUILD}|g" package_info.conf
34 | buildDir=src-${REPOSITORY%.*}
35 | cp -rvf src "${buildDir}"
36 | cd "${buildDir}"
37 | export CFLAGS="-I/usr/src/linux-headers-${KERNEL_VERSION}"
38 | make KERNEL_DIR="/usr/src/linux-headers-${KERNEL_VERSION}-generic" USE_SPARSE=1
39 | make install INSTALLDIR="${INSTALL_PREFIX}/src"
40 | echo
41 | echo "Driver info:"
42 | echo
43 | modinfo akvcam.ko
44 |
--------------------------------------------------------------------------------
/ports/ci/linux/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # akvcam, virtual camera for Linux.
4 | # Copyright (C) 2020 Gonzalo Exequiel Pedone
5 | #
6 | # This program is free software; you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation; either version 2 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License along
17 | # with this program; if not, write to the Free Software Foundation, Inc.,
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 |
20 | git clone https://github.com/webcamoid/DeployTools.git
21 | git config --global --add safe.directory /sources
22 |
23 | export PATH="${PWD}/.local/bin:${PATH}"
24 | export INSTALL_PREFIX="${PWD}/package-data-${REPOSITORY%.*}"
25 | export PACKAGES_DIR="${PWD}/packages-${REPOSITORY%.*}"
26 | export PYTHONPATH="${PWD}/DeployTools"
27 |
28 | xvfb-run --auto-servernum python3 \
29 | ./DeployTools/deploy.py \
30 | -d "${INSTALL_PREFIX}" \
31 | -c ./package_info.conf \
32 | -o "${PACKAGES_DIR}"
33 |
--------------------------------------------------------------------------------
/ports/ci/linux/install_deps.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # akvcam, virtual camera for Linux.
4 | # Copyright (C) 2018 Gonzalo Exequiel Pedone
5 | #
6 | # This program is free software; you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation; either version 2 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License along
17 | # with this program; if not, write to the Free Software Foundation, Inc.,
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 |
20 | if [ ! -z "${USE_WGET}" ]; then
21 | export DOWNLOAD_CMD="wget -nv -c"
22 | else
23 | export DOWNLOAD_CMD="curl --retry 10 -sS -kLOC -"
24 | fi
25 |
26 | # Fix keyboard layout bug when running apt
27 |
28 | cat << EOF > keyboard_config
29 | XKBMODEL="pc105"
30 | XKBLAYOUT="us"
31 | XKBVARIANT=""
32 | XKBOPTIONS=""
33 | BACKSPACE="guess"
34 | EOF
35 |
36 | export LC_ALL=C
37 | export DEBIAN_FRONTEND=noninteractive
38 |
39 | apt-get -qq -y update
40 | apt-get install -qq -y keyboard-configuration
41 | cp -vf keyboard_config /etc/default/keyboard
42 | dpkg-reconfigure --frontend noninteractive keyboard-configuration
43 |
44 | # Install missing dependenies
45 |
46 | apt-get -qq -y upgrade
47 | apt-get -qq -y install \
48 | curl \
49 | libdbus-1-3 \
50 | libfontconfig1 \
51 | libgl1 \
52 | libx11-xcb1 \
53 | libxcb-glx0 \
54 | libxcb-icccm4 \
55 | libxcb-image0 \
56 | libxcb-keysyms1 \
57 | libxcb-randr0 \
58 | libxcb-render-util0 \
59 | libxcb-shape0 \
60 | libxcb-xfixes0 \
61 | libxcb-xinerama0 \
62 | libxext6 \
63 | libxkbcommon-x11-0 \
64 | libxrender1 \
65 | wget
66 |
67 | mkdir -p .local/bin
68 |
69 | if [ -z "${ARCHITECTURE}" ]; then
70 | architecture="${DOCKERIMG%%/*}"
71 | else
72 | case "${ARCHITECTURE}" in
73 | aarch64)
74 | architecture=arm64v8
75 | ;;
76 | armv7)
77 | architecture=arm32v7
78 | ;;
79 | *)
80 | architecture=${ARCHITECTURE}
81 | ;;
82 | esac
83 | fi
84 |
85 | if [[ ( "${architecture}" = amd64 || "${architecture}" = arm64v8 ) && ! -z "${QTIFWVER}" ]]; then
86 | # Install Qt Installer Framework
87 |
88 | case "${architecture}" in
89 | arm64v8)
90 | qtArch=arm64
91 | ;;
92 | *)
93 | qtArch=x64
94 | ;;
95 | esac
96 |
97 | qtIFW=QtInstallerFramework-linux-${qtArch}-${QTIFWVER}.run
98 | ${DOWNLOAD_CMD} "http://download.qt.io/official_releases/qt-installer-framework/${QTIFWVER}/${qtIFW}" || true
99 |
100 | if [ -e "${qtIFW}" ]; then
101 | if [ "${architecture}" = arm64v8 ]; then
102 | ln -svf libtiff.so.6 /usr/lib/aarch64-linux-gnu/libtiff.so.5
103 | ln -svf libwebp.so.7 /usr/lib/aarch64-linux-gnu/libwebp.so.6
104 | fi
105 |
106 | chmod +x "${qtIFW}"
107 | QT_QPA_PLATFORM=minimal \
108 | ./"${qtIFW}" \
109 | --verbose \
110 | --root ~/QtIFW \
111 | --accept-licenses \
112 | --accept-messages \
113 | --confirm-command \
114 | install
115 | cd .local
116 | cp -rvf ~/QtIFW/* .
117 | cd ..
118 | fi
119 | fi
120 |
121 | # Install dev tools
122 |
123 | apt-get -qq -y install \
124 | g++ \
125 | git \
126 | kmod \
127 | libelf-dev \
128 | make \
129 | makeself \
130 | python3 \
131 | sparse \
132 | wget \
133 | xvfb \
134 | xz-utils
135 |
136 | case "${architecture}" in
137 | arm64v8)
138 | systemArch=arm64
139 | ;;
140 | arm32v7)
141 | systemArch=armhf
142 | ;;
143 | *)
144 | systemArch=amd64
145 | ;;
146 | esac
147 |
148 | url=https://kernel.ubuntu.com/mainline/${REPOSITORY}
149 | headers=amd64/linux-headers-${KERNEL_VERSION}_${KERNEL_VERSION}.${KERNEL_VERSION_C}_all.deb
150 | headers_generic=${systemArch}/linux-headers-${KERNEL_VERSION}-generic_${KERNEL_VERSION}.${KERNEL_VERSION_C}_${systemArch}.deb
151 |
152 | for package in ${headers} ${headers_generic}; do
153 | ${DOWNLOAD_CMD} "${url}/${package}"
154 | dpkg -i "${package#*/}"
155 | done
156 |
--------------------------------------------------------------------------------
/ports/deploy/installscript.posix.qs:
--------------------------------------------------------------------------------
1 | function Component()
2 | {
3 | let paths = installer.environmentVariable("PATH").split(":");
4 | let kernelVersion = installer.execute("uname", ["-r"])[0].trim();
5 | let linuxSources = "/lib/modules/" + kernelVersion + "/build";
6 | let cmds = ["dkms", "gcc", "kmod", "make"]
7 |
8 | for (;;) {
9 | let missing_dependencies = [];
10 |
11 | for (let i in cmds)
12 | if (installer.findPath(cmds[i], paths).length < 1)
13 | missing_dependencies.push(cmds[i]);
14 |
15 | if (!installer.fileExists(linuxSources + "/include/generated/uapi/linux/version.h"))
16 | missing_dependencies.push("linux-headers");
17 |
18 | if (missing_dependencies.length < 1)
19 | break;
20 |
21 | let result = QMessageBox.information("missing_dependencies",
22 | "Missing dependencies",
23 | "The following dependencies are missing: "
24 | + missing_dependencies.join(", ")
25 | + ". Install them and try again",
26 | QMessageBox.Retry | QMessageBox.Close);
27 |
28 | if (result == QMessageBox.Close) {
29 | QMessageBox.critical("missing_dependencies.dialog_close",
30 | "Error",
31 | "Aborting driver installation due to unmeet dependencies.",
32 | QMessageBox.Ok);
33 | installer.setCanceled();
34 |
35 | break;
36 | }
37 | }
38 | }
39 |
40 | Component.prototype.beginInstallation = function()
41 | {
42 | component.beginInstallation();
43 | }
44 |
45 | Component.prototype.createOperations = function()
46 | {
47 | component.createOperations();
48 |
49 | // Create a symlink to the sources.
50 | component.addElevatedOperation("Execute",
51 | "ln",
52 | "-s",
53 | "@TargetDir@/src",
54 | "/usr/src/@Name@-@Version@",
55 | "UNDOEXECUTE",
56 | "rm",
57 | "-f",
58 | "/usr/src/@Name@-@Version@");
59 |
60 | // Run DKMS.
61 | component.addElevatedOperation("Execute",
62 | "dkms",
63 | "install",
64 | "@Name@/@Version@",
65 | "UNDOEXECUTE",
66 | "dkms",
67 | "remove",
68 | "@Name@/@Version@",
69 | "--all");
70 | }
71 |
--------------------------------------------------------------------------------
/ports/deploy/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | scriptPath=$(readlink -f "$0")
4 | installDataFile=install.data
5 | NAME=$1
6 |
7 | if [ -z "$NAME" ]; then
8 | NAME=$(grep 'NAME=' "${installDataFile}" 2>/dev/null)
9 | NAME=${NAME#*=}
10 | fi
11 |
12 | VERSION=$2
13 |
14 | if [ -z "$VERSION" ]; then
15 | VERSION=$(grep 'VERSION=' "${installDataFile}" 2>/dev/null)
16 | VERSION=${VERSION#*=}
17 | fi
18 |
19 | TARGET_DIR=$(dirname "${scriptPath}")
20 |
21 | if [ ! -z "$3" ]; then
22 | TARGET_DIR=$3
23 | fi
24 |
25 | SCRIPT_BASENAME=$(basename "$0")
26 | SUDO_CMD=
27 |
28 | if [ ! -w "${TARGET_DIR}" ]; then
29 | SUDO_CMD=sudo
30 | fi
31 |
32 | if [ -z "${NAME}" ]; then
33 | echo "Installation started"
34 | else
35 | echo "${NAME} installation started"
36 | fi
37 |
38 | echo
39 | ${SUDO_CMD} chmod 755 "${TARGET_DIR}"
40 |
41 | echo "Writting install data"
42 | installData=${TARGET_DIR}/${installDataFile}
43 |
44 | ${SUDO_CMD} tee "${installData}" > /dev/null < /dev/null < /dev/null </dev/null
120 |
121 | # https://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.html
122 | sensible_directories="
123 | /
124 | /bin
125 | /boot
126 | /dev
127 | /etc
128 | /home
129 | \${HOME}
130 | /lib
131 | /media
132 | /mnt
133 | /opt
134 | /proc
135 | /root
136 | /run
137 | /sbin
138 | /svr
139 | /sys
140 | /tmp
141 | /usr
142 | /usr/bin
143 | /usr/include
144 | /usr/lib
145 | /usr/libexec
146 | /usr/local
147 | /usr/local/share
148 | /usr/sbin
149 | /usr/share
150 | /usr/share/color
151 | /usr/share/dict
152 | /usr/share/man
153 | /usr/share/misc
154 | /usr/share/ppd
155 | /usr/share/sgml
156 | /usr/share/xml
157 | /usr/src
158 | /var
159 | /var/account
160 | /var/cache
161 | /var/cache/fonts
162 | /var/cache/man
163 | /var/crash
164 | /var/games
165 | /var/lib
166 | /var/lib/color
167 | /var/lib/hwclock
168 | /var/lib/misc
169 | /var/lock
170 | /var/log
171 | /var/mail
172 | /var/opt
173 | /var/run
174 | /var/spool
175 | /var/spool/cron
176 | /var/spool/lpd
177 | /var/spool/rwho
178 | /var/tmp
179 | /var/yp
180 | \${XDG_DESKTOP_DIR}
181 | \${XDG_DOCUMENTS_DIR}
182 | \${XDG_DOWNLOAD_DIR}
183 | \${XDG_MUSIC_DIR}
184 | \${XDG_PICTURES_DIR}
185 | \${XDG_PUBLICSHARE_DIR}
186 | \${XDG_TEMPLATES_DIR}
187 | \${XDG_VIDEOS_DIR}"
188 |
189 | for sdir in \$sensible_directories; do
190 | if [ "\$sdir" = "\$directory" ]; then
191 | echo true
192 |
193 | return 1
194 | fi
195 | done
196 |
197 | echo false
198 |
199 | return 0
200 | }
201 |
202 | sensibleDir=\$(is_sensible_directory "\${TARGET_DIR}")
203 |
204 | if [ "\${sensibleDir}" = true ]; then
205 | echo "'\${TARGET_DIR}' can't be deleted"
206 | else
207 | echo "Deleting '\${TARGET_DIR}'"
208 | \${SUDO_CMD} rm -rf "\${TARGET_DIR}" 2>/dev/null
209 | fi
210 |
211 | echo
212 |
213 | if [ -z "\${NAME}" ]; then
214 | echo "Uninstallation finished"
215 | else
216 | echo "\${NAME} uninstallation finished"
217 | fi
218 | EOF
219 |
220 | ${SUDO_CMD} chmod 755 "${uninstallScript}"
221 |
222 | detect_missing_dependencies() {
223 | linuxSources=/lib/modules/$(uname -r)/build
224 | cmds="dkms gcc kmod make"
225 | missing_dependencies="";
226 |
227 | for cmd in $cmds; do
228 | cmdPath=$(which "${cmd}" 2>/dev/null)
229 |
230 | if [ "$?" != 0 ]; then
231 | if [ -z "${missing_dependencies}" ]; then
232 | missing_dependencies="${cmd}"
233 | else
234 | missing_dependencies="${missing_dependencies} ${cmd}"
235 | fi
236 | fi
237 | done
238 |
239 | if [ ! -e "${linuxSources}/include/generated/uapi/linux/version.h" ]; then
240 | if [ -z "${missing_dependencies}" ]; then
241 | missing_dependencies=linux-headers
242 | else
243 | missing_dependencies="${missing_dependencies} linux-headers"
244 | fi
245 | fi
246 |
247 | echo "${missing_dependencies}"
248 | }
249 |
250 | distro() {
251 | distroId=$(grep -h ^ID_LIKE= /etc/*-release | tr -d '"')
252 |
253 | if [ -z "${distroId}" ]; then
254 | distroId=$(grep -h ^ID= /etc/*-release | tr -d '"')
255 | fi
256 |
257 | distroId=${distroId#*=}
258 |
259 | case "${distroId}" in
260 | *suse*)
261 | distroId=opensuse
262 | ;;
263 | *)
264 | ;;
265 | esac
266 |
267 | echo "${distroId}"
268 | }
269 |
270 | distro_package() {
271 | distroId=$1
272 | package=$2
273 | depsMap=""
274 |
275 | case "${distro}Id" in
276 | arch)
277 | depsMap=";dkms:dkms"
278 | depsMap="${depsMap};gcc:gcc"
279 | depsMap="${depsMap};kmod:kmod"
280 | depsMap="${depsMap};make:make"
281 | depsMap="${depsMap};linux-headers:linux-headers"
282 | ;;
283 | debian)
284 | depsMap=";dkms:dkms"
285 | depsMap="${depsMap};gcc:gcc"
286 | depsMap="${depsMap};kmod:kmod"
287 | depsMap="${depsMap};make:make"
288 | depsMap="${depsMap};linux-headers:linux-headers-$(uname -r)"
289 | ;;
290 | fedora)
291 | depsMap=";dkms:dkms"
292 | depsMap="${depsMap};gcc:gcc"
293 | depsMap="${depsMap};kmod:kmod"
294 | depsMap="${depsMap};make:make"
295 | depsMap="${depsMap};linux-headers:kernel-devel kernel-headers"
296 | ;;
297 | mageia)
298 | depsMap=";dkms:dkms"
299 | depsMap="${depsMap};gcc:gcc"
300 | depsMap="${depsMap};kmod:kmod"
301 | depsMap="${depsMap};make:make"
302 | depsMap="${depsMap};linux-headers:kernel-linus-devel"
303 | ;;
304 | opensuse)
305 | depsMap=";dkms:dkms"
306 | depsMap="${depsMap};gcc:gcc"
307 | depsMap="${depsMap};kmod:kmod"
308 | depsMap="${depsMap};make:make"
309 | depsMap="${depsMap};linux-headers:kernel-devel"
310 | ;;
311 | *)
312 | depsMap=";dkms:dkms"
313 | depsMap="${depsMap};gcc:gcc"
314 | depsMap="${depsMap};kmod:kmod"
315 | depsMap="${depsMap};make:make"
316 | depsMap="${depsMap};linux-headers:linux-headers"
317 | ;;
318 | esac
319 |
320 | packages="${depsMap#*;${package}:}"
321 | packages="${packages%%;*}"
322 |
323 | if [ -z "${packages}" ]; then
324 | echo "${package}"
325 | else
326 | echo "${packages}"
327 | fi
328 | }
329 |
330 | distro_packages() {
331 | distroId=$1
332 | shift
333 | packages=""
334 |
335 | for package in $@; do
336 | distroPackage=$(distro_package "${distroId}" "${package}")
337 |
338 | if [ -z "${packages}" ]; then
339 | packages="${distroPackage}"
340 | else
341 | packages="${packages} ${distroPackage}"
342 | fi
343 | done
344 |
345 | echo "${packages}"
346 | }
347 |
348 | install_packages() {
349 | distroId=$1
350 | shift
351 | missing_dependencies=$@
352 | SUDO_CMD=
353 |
354 | if [ "$EUID" != 0 ]; then
355 | SUDO_CMD=sudo
356 | fi
357 |
358 | case "${distroId}" in
359 | arch)
360 | ${SUDO_CMD} pacman -Syu --noconfirm --ignore linux,linux-api-headers,linux-docs,linux-firmware,linux-headers,pacman
361 | ${SUDO_CMD} pacman --noconfirm --needed -S ${missing_dependencies}
362 | ;;
363 | debian)
364 | ${SUDO_CMD} apt-get -y update
365 | ${SUDO_CMD} apt-get -y upgrade
366 | ${SUDO_CMD} apt-get -y install ${missing_dependencies}
367 | ;;
368 | fedora)
369 | ${SUDO_CMD} dnf -y upgrade-minimal --exclude=systemd,systemd-libs
370 | ${SUDO_CMD} dnf -y --skip-broken install ${missing_dependencies}
371 | ;;
372 | mageia)
373 | ${SUDO_CMD} dnf -y update
374 | ${SUDO_CMD} dnf -y install ${missing_dependencies}
375 | ;;
376 | opensuse)
377 | ${SUDO_CMD} zypper -n dup
378 | ${SUDO_CMD} zypper -n in ${missing_dependencies}
379 | ;;
380 | *)
381 | ;;
382 | esac
383 | }
384 |
385 | is_distro_supported() {
386 | distroId=$1
387 |
388 | case "${distroId}" in
389 | arch)
390 | ;;
391 | debian)
392 | ;;
393 | fedora)
394 | ;;
395 | mageia)
396 | ;;
397 | opensuse)
398 | ;;
399 | *)
400 | echo false
401 |
402 | return 0
403 | ;;
404 | esac
405 |
406 | echo true
407 |
408 | return 1
409 | }
410 |
411 | distroId=$(distro)
412 | missing_dependencies=$(detect_missing_dependencies)
413 | missing_dependencies=$(distro_packages "${distroId}" ${missing_dependencies})
414 |
415 | if [ ! -z "${missing_dependencies}" ]; then
416 | if [ "$(is_distro_supported "${distroId}")" = true ]; then
417 | echo "Installing missing dependencies:" $(echo "${missing_dependencies}" | sed 's/ /, /g')
418 | echo
419 | install_packages "${distroId}" ${missing_dependencies}
420 |
421 | if [ "$?" != 0 ]; then
422 | exit $?
423 | fi
424 | else
425 | echo "The following dependencies are missing:" $(echo "${missing_dependencies}" | sed 's/ /, /g') >&2
426 | echo >&2
427 | echo "Install them and then run '${TARGET_DIR}/${SCRIPT_BASENAME}' script." >&2
428 |
429 | exit -1
430 | fi
431 | fi
432 |
433 | echo "Creating a symlink to the sources"
434 |
435 | write_link() {
436 | SUDO_CMD=
437 |
438 | if [ "$EUID" != 0 ]; then
439 | SUDO_CMD=sudo
440 | fi
441 |
442 | ${SUDO_CMD} ln -sf "${TARGET_DIR}/src" "/usr/src/${NAME}-${VERSION}"
443 |
444 | if [ "$?" != 0 ]; then
445 | exit $?
446 | fi
447 | }
448 |
449 | write_link
450 |
451 | echo "Runnig DKMS"
452 |
453 | run_dkms() {
454 | SUDO_CMD=
455 |
456 | if [ "$EUID" != 0 ]; then
457 | SUDO_CMD=sudo
458 | fi
459 |
460 | ${SUDO_CMD} dkms install "${NAME}/${VERSION}"
461 |
462 | if [ "$?" != 0 ]; then
463 | exit $?
464 | fi
465 | }
466 |
467 | run_dkms
468 | echo
469 |
470 | if [ -z "${NAME}" ]; then
471 | echo "Installation finished"
472 | else
473 | echo "${NAME} installation finished"
474 | fi
475 |
--------------------------------------------------------------------------------
/share/config_example.ini:
--------------------------------------------------------------------------------
1 | # Virtual camera configuration file example.
2 | #
3 | # Please, read the instructions to the end.
4 |
5 | [Cameras]
6 | # First at all you must define how many virtual cameras will be created.
7 | cameras/size = 2
8 |
9 | # Then, define it's properties.
10 | #
11 | # A virtual camera can be of 2 types: 'capture' and 'output'.
12 | # A 'capture' device will be seen as a normal webcam by any webcam capture
13 | # program.
14 | # A 'output' device will receive frames from a producer program and send it to
15 | # one or many 'capture' devices.
16 | #
17 | # A camera can have also 3 capture/output modes: 'mmap', 'userptr' and 'rw'.
18 | # 'mmap' is the most widely supported mode by far, enabling this is more than
19 | # enough in most cases. 'rw' allow you to "echo" or "cat" frames as raw data
20 | # directly to the device using the default frame format. Enabling 'rw' mode will
21 | # disable emulated camera controls in the 'capture' device (brightness,
22 | # contrast, saturation, etc.).
23 | # A device can support all 3 modes at same time.
24 | #
25 | # 'formats' is a comma separated list of index in the format list bellow.
26 | #
27 | # It's also possible to set the device number by setting the 'videonr' property,
28 | # if for example videonr=7 the the device will be created as "/dev/video7".
29 | # If 'videonr' is already taken, negative or not set, the driver will assign the
30 | # first free device number.
31 | cameras/1/type = output
32 | cameras/1/mode = mmap, userptr, rw
33 | cameras/1/description = Virtual Camera (output device)
34 | cameras/1/formats = 2
35 | cameras/1/videonr = 7
36 |
37 | cameras/2/type = capture
38 | cameras/2/mode = mmap, rw
39 | cameras/2/description = Virtual Camera
40 | cameras/2/formats = 1, 2
41 |
42 | [Formats]
43 | # Define how many formats will be supported by the camera.
44 | formats/size = 2
45 |
46 | # Now define the frame pixel formats, resolutions and frame rates supported by
47 | # the camera.
48 | #
49 | # Supported capture formats:
50 | #
51 | # RGB32
52 | # RGB24
53 | # RGB16
54 | # RGB15
55 | # BGR32
56 | # BGR24
57 | # UYVY
58 | # YUY2
59 | #
60 | # Supported output formats:
61 | #
62 | # RGB24
63 | # BGR24
64 | #
65 | # YUY2 640x480 is one of the most widely supported formats in webcam capture
66 | # programs. First format defined is the default frame format for
67 | # 'capture'/'output'.
68 | # 'width', 'height' and 'fps' are unsigned integers.
69 | formats/1/format = YUY2
70 | formats/1/width = 640
71 | formats/1/height = 480
72 | formats/1/fps = 30
73 |
74 | # The parameters can also be specified as a comma separated list, so it's
75 | # possible to combine the parameters to define several formats in one group.
76 | # 'fps' can also be defined as a fraction.
77 | # The following lines will define 4 formats:
78 | #
79 | # RGB24 640x480 20 FPS
80 | # RGB24 640x480 7.5 FPS
81 | # YUY2 640x480 20 FPS
82 | # YUY2 640x480 7.5 FPS
83 | formats/2/format = RGB24, YUY2
84 | formats/2/width = 640
85 | formats/2/height = 480
86 | formats/2/fps = 20/1, 15/2
87 |
88 | # Finally, to create a fully working virtual camera, you must connect one
89 | # 'output' to one or many 'capture' devices.
90 | # Connections are made by index, separated by a colon. The first index is the
91 | # 'output' device, the following index are 'capture' devices.
92 | [Connections]
93 | connections/size = 1
94 | connections/1/connection = 1:2
95 |
96 | # You can also define a default frame when a 'capture' device is not receiving
97 | # any input. Only 24 bpp and 32 bpp BMP files are supported.
98 | [General]
99 | default_frame = /etc/akvcam/default_frame.bmp
100 |
101 | # This config will take effect on modprobe/insmod.
102 |
--------------------------------------------------------------------------------
/share/examples/output.c:
--------------------------------------------------------------------------------
1 | /* Virtual camera output example.
2 | * Copyright (C) 2020 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | *
18 | * Alternatively you can redistribute this file under the terms of the
19 | * BSD license as stated below:
20 | *
21 | * Redistribution and use in source and binary forms, with or without
22 | * modification, are permitted provided that the following conditions
23 | * are met:
24 | *
25 | * 1. Redistributions of source code must retain the above copyright
26 | * notice, this list of conditions and the following disclaimer.
27 | * 2. Redistributions in binary form must reproduce the above copyright
28 | * notice, this list of conditions and the following disclaimer in
29 | * the documentation and/or other materials provided with the
30 | * distribution.
31 | * 3. The names of its contributors may not be used to endorse or promote
32 | * products derived from this software without specific prior written
33 | * permission.
34 | *
35 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
41 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
42 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 | */
47 |
48 | #include
49 | #include
50 | #include
51 | #include
52 | #include
53 | #include
54 | #include
55 | #include
56 |
57 | /* For the sake of simplicity, the program won't print anything to the terminal,
58 | * or do any validation check, you are adviced the check every single value
59 | * returned by ioctl() and other functions.
60 | * This program shows the very minimum code required to write frames to the
61 | * driver in every supported mode: rw, mmap and userptr.
62 | */
63 |
64 | // We'll assume this is a valid akvcam output device.
65 | #define VIDEO_OUTPUT "/dev/video7"
66 |
67 | /* Choose the desired capture method, possible values:
68 | *
69 | * V4L2_CAP_READWRITE for rw
70 | * V4L2_CAP_STREAMING for mmap and userptr
71 | */
72 | //#define CAPTURE_METHOD V4L2_CAP_READWRITE
73 | #define CAPTURE_METHOD V4L2_CAP_STREAMING
74 |
75 | /* Choose the desired memory mapping method, possible values:
76 | *
77 | * V4L2_MEMORY_MMAP
78 | * V4L2_MEMORY_USERPTR
79 | */
80 | #define MEMORY_TYPE V4L2_MEMORY_MMAP
81 | //#define MEMORY_TYPE V4L2_MEMORY_USERPTR
82 |
83 | // Choose the number of buffers to use in mmap and userptr.
84 | #define N_BUFFERS 4
85 |
86 | // Send frames for about 30 seconds in a 30 FPS stream.
87 | #define FPS 30
88 | #define DURATION_SECONDS 30
89 | #define N_FRAMES (FPS * DURATION_SECONDS)
90 |
91 | // This structure will store the frames data.
92 | struct DataBuffer
93 | {
94 | char *start;
95 | size_t length;
96 | };
97 |
98 | int main()
99 | {
100 | // Open the output device
101 | int fd = open(VIDEO_OUTPUT, O_RDWR | O_NONBLOCK, 0);
102 |
103 | /* Check that this is an actual output device and read the default frame
104 | * format.
105 | */
106 | struct v4l2_format fmt;
107 | memset(&fmt, 0, sizeof(struct v4l2_format));
108 | fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
109 | ioctl(fd, VIDIOC_G_FMT, &fmt);
110 |
111 | /* This step is not necessary, but you can also set a different output
112 | * format from the supported ones. Supported pixel formats are:
113 | *
114 | * V4L2_PIX_FMT_RGB24;
115 | * V4L2_PIX_FMT_BGR24;
116 | */
117 | fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
118 | fmt.fmt.pix.width = 640;
119 | fmt.fmt.pix.height = 480;
120 | ioctl(fd, VIDIOC_S_FMT, &fmt);
121 |
122 | // Query which methods are supported by the driver.
123 | struct v4l2_capability capabilities;
124 | memset(&capabilities, 0, sizeof(struct v4l2_capability));
125 | ioctl(fd, VIDIOC_QUERYCAP, &capabilities);
126 |
127 | struct DataBuffer *buffers = NULL;
128 |
129 | if (CAPTURE_METHOD == V4L2_CAP_READWRITE
130 | && capabilities.capabilities & V4L2_CAP_READWRITE) {
131 | // In 'rw' mode just reserve one single buffer.
132 | buffers = calloc(1, sizeof(struct DataBuffer));
133 | buffers->length = fmt.fmt.pix.sizeimage;
134 | buffers->start = calloc(1, fmt.fmt.pix.sizeimage);
135 | } else if (CAPTURE_METHOD == V4L2_CAP_STREAMING
136 | && capabilities.capabilities & V4L2_CAP_STREAMING) {
137 | // Request N_BUFFERS.
138 | struct v4l2_requestbuffers requestBuffers;
139 | memset(&requestBuffers, 0, sizeof(struct v4l2_requestbuffers));
140 | requestBuffers.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
141 | requestBuffers.memory = MEMORY_TYPE;
142 | requestBuffers.count = N_BUFFERS;
143 | ioctl(fd, VIDIOC_REQBUFS, &requestBuffers);
144 | buffers = calloc(requestBuffers.count,
145 | sizeof(struct DataBuffer));
146 |
147 | // Initialize the buffers.
148 | for (__u32 i = 0; i < requestBuffers.count; i++) {
149 | if (MEMORY_TYPE == V4L2_MEMORY_MMAP) {
150 | struct v4l2_buffer buffer;
151 | memset(&buffer, 0, sizeof(struct v4l2_buffer));
152 | buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
153 | buffer.memory = V4L2_MEMORY_MMAP;
154 | buffer.index = i;
155 | ioctl(fd, VIDIOC_QUERYBUF, &buffer);
156 | buffers[i].length = buffer.length;
157 | buffers[i].start = mmap(NULL,
158 | buffer.length,
159 | PROT_READ | PROT_WRITE,
160 | MAP_SHARED,
161 | fd,
162 | buffer.m.offset);
163 | } else {
164 | buffers[i].length = fmt.fmt.pix.sizeimage;
165 | buffers[i].start = calloc(1, fmt.fmt.pix.sizeimage);
166 | }
167 | }
168 |
169 | // Queue the buffers to the driver.
170 | for (__u32 i = 0; i < requestBuffers.count; i++) {
171 | struct v4l2_buffer buffer;
172 | memset(&buffer, 0, sizeof(struct v4l2_buffer));
173 |
174 | if (MEMORY_TYPE == V4L2_MEMORY_MMAP) {
175 | buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
176 | buffer.memory = V4L2_MEMORY_MMAP;
177 | buffer.index = i;
178 | } else {
179 | buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
180 | buffer.memory = V4L2_MEMORY_USERPTR;
181 | buffer.index = i;
182 | buffer.m.userptr = (unsigned long) buffers[i].start;
183 | buffer.length = buffers[i].length;
184 | }
185 |
186 | ioctl(fd, VIDIOC_QBUF, &buffer);
187 | }
188 |
189 | // Start the stream.
190 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
191 | ioctl(fd, VIDIOC_STREAMON, &type);
192 | }
193 |
194 | // Generate some random noise frames.
195 | srand(time(0));
196 |
197 | for (int i = 0; i < N_FRAMES; i++) {
198 | if (CAPTURE_METHOD == V4L2_CAP_READWRITE
199 | && capabilities.capabilities & V4L2_CAP_READWRITE) {
200 | // Write the frame data to the buffer.
201 | for (size_t byte = 0; byte < buffers->length; byte++)
202 | buffers->start[byte] = rand() & 0xff;
203 |
204 | write(fd, buffers->start, buffers->length);
205 | } else if (CAPTURE_METHOD == V4L2_CAP_STREAMING
206 | && capabilities.capabilities & V4L2_CAP_STREAMING) {
207 | // Dequeue one buffer.
208 | struct v4l2_buffer buffer;
209 | memset(&buffer, 0, sizeof(struct v4l2_buffer));
210 | buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
211 | buffer.memory = MEMORY_TYPE;
212 | ioctl(fd, VIDIOC_DQBUF, &buffer);
213 |
214 | // Write the frame data to the buffer.
215 | for (size_t byte = 0; byte < buffer.bytesused; byte++)
216 | buffers[buffer.index].start[byte] = rand() & 0xff;
217 |
218 | // Queue the buffer with the frame data.
219 | ioctl(fd, VIDIOC_QBUF, &buffer);
220 | }
221 |
222 | struct timespec ts;
223 | ts.tv_sec = 0;
224 | ts.tv_nsec = 1e9 / FPS;
225 | nanosleep(&ts, &ts);
226 | }
227 |
228 | // Free the buffers.
229 | if (CAPTURE_METHOD == V4L2_CAP_READWRITE
230 | && capabilities.capabilities & V4L2_CAP_READWRITE) {
231 | free(buffers->start);
232 | } else if (CAPTURE_METHOD == V4L2_CAP_STREAMING
233 | && capabilities.capabilities & V4L2_CAP_STREAMING) {
234 | // Stop the stream.
235 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
236 | ioctl(fd, VIDIOC_STREAMOFF, &type);
237 |
238 | for (__u32 i = 0; i < N_BUFFERS; i++) {
239 | if (MEMORY_TYPE == V4L2_MEMORY_MMAP)
240 | munmap(buffers[i].start, buffers[i].length);
241 | else
242 | free(buffers[i].start);
243 | }
244 | }
245 |
246 | free(buffers);
247 |
248 | // Close the output device.
249 | close(fd);
250 |
251 | return 0;
252 | }
253 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | MODULE_NAME = akvcam
2 | MODULE_VERSION = 1.2.6
3 | KERNEL_ROOT ?= $(shell realpath /lib/modules/$(shell uname -r))
4 | KERNEL_DIR ?= $(KERNEL_ROOT)/build
5 | COPY = cp -f
6 | MKDIR = mkdir -p
7 | RMDIR = rm -rvf
8 | PWD := $(shell pwd)
9 | DKMS := dkms
10 | DESTDIR :=
11 | PREFIX := $(DESTDIR)/usr/src
12 | INSTALLDIR := $(PREFIX)/$(MODULE_NAME)-$(MODULE_VERSION)
13 |
14 | HAVE_SPARSE := $(shell which sparse 2>/dev/null)
15 | SPARSE_MODE ?= 2
16 |
17 | ifdef USE_SPARSE
18 | ifdef HAVE_SPARSE
19 | SPARSE_VAR = C=$(SPARSE_MODE)
20 | endif
21 | endif
22 |
23 | obj-m += $(MODULE_NAME).o
24 | akvcam-objs := \
25 | module.o \
26 | attributes.o \
27 | buffers.o \
28 | controls.o \
29 | device.o \
30 | driver.o \
31 | file_read.o \
32 | format.o \
33 | frame.o \
34 | frame_filter.o \
35 | ioctl.o \
36 | list.o \
37 | log.o \
38 | map.o \
39 | rbuffer.o \
40 | settings.o \
41 | utils.o
42 |
43 | all:
44 | $(MAKE) -C $(KERNEL_DIR) M=$(PWD) $(SPARSE_VAR) modules
45 |
46 | clean:
47 | $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
48 |
49 | install: uninstall
50 | $(MKDIR) $(INSTALLDIR)
51 | $(COPY) Makefile $(INSTALLDIR)
52 | $(COPY) dkms.conf $(INSTALLDIR)
53 | $(COPY) *.h $(INSTALLDIR)
54 | $(COPY) *.c $(INSTALLDIR)
55 |
56 | dkms_install: | dkms_uninstall install
57 | $(DKMS) install $(MODULE_NAME)/$(MODULE_VERSION)
58 |
59 | uninstall:
60 | $(RMDIR) $(INSTALLDIR)
61 |
62 | dkms_uninstall:
63 | - $(DKMS) remove $(MODULE_NAME)/$(MODULE_VERSION) --all
64 | $(RMDIR) $(INSTALLDIR)
65 |
--------------------------------------------------------------------------------
/src/attributes.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 |
22 | #include "attributes.h"
23 | #include "controls.h"
24 | #include "device.h"
25 | #include "list.h"
26 |
27 | static const struct attribute_group *akvcam_attributes_capture_groups[2];
28 | static const struct attribute_group *akvcam_attributes_output_groups[2];
29 |
30 | typedef struct
31 | {
32 | AKVCAM_RW_MODE rw_mode;
33 | char str[AKVCAM_MAX_STRING_SIZE];
34 | } akvcam_attributes_rw_mode_strings, *akvcam_attributes_rw_mode_strings_t;
35 |
36 | typedef struct
37 | {
38 | const char *name;
39 | __u32 id;
40 | } akvcam_attributes_controls_map, *akvcam_attributes_controls_map_t;
41 |
42 | static akvcam_attributes_controls_map akvcam_attributes_controls[] = {
43 | {"brightness" , V4L2_CID_BRIGHTNESS },
44 | {"contrast" , V4L2_CID_CONTRAST },
45 | {"saturation" , V4L2_CID_SATURATION },
46 | {"hue" , V4L2_CID_HUE },
47 | {"gamma" , V4L2_CID_GAMMA },
48 | {"hflip" , V4L2_CID_HFLIP },
49 | {"vflip" , V4L2_CID_VFLIP },
50 | {"scaling" , AKVCAM_CID_SCALING },
51 | {"aspect_ratio", AKVCAM_CID_ASPECT_RATIO},
52 | {"swap_rgb" , AKVCAM_CID_SWAP_RGB },
53 | {"colorfx" , V4L2_CID_COLORFX },
54 | {NULL , 0 },
55 | };
56 |
57 | __u32 akvcam_attributes_controls_id_by_name(const char *name);
58 |
59 | const struct attribute_group **akvcam_attributes_groups(AKVCAM_DEVICE_TYPE device_type)
60 | {
61 | return device_type == AKVCAM_DEVICE_TYPE_OUTPUT?
62 | akvcam_attributes_output_groups:
63 | akvcam_attributes_capture_groups;
64 | }
65 |
66 | __u32 akvcam_attributes_controls_id_by_name(const char *name)
67 | {
68 | size_t i;
69 |
70 | for (i = 0; akvcam_attributes_controls[i].name; i++)
71 | if (strcmp(akvcam_attributes_controls[i].name, name) == 0)
72 | return akvcam_attributes_controls[i].id;
73 |
74 | return 0;
75 | }
76 |
77 | static ssize_t akvcam_attributes_connected_devices_show(struct device *dev,
78 | struct device_attribute *attribute,
79 | char *buffer)
80 | {
81 | struct video_device *vdev = to_video_device(dev);
82 | akvcam_device_t device = video_get_drvdata(vdev);
83 | akvcam_devices_list_t devices;
84 | akvcam_list_element_t it = NULL;
85 | size_t n = 0;
86 | size_t i;
87 |
88 | UNUSED(attribute);
89 | devices = akvcam_device_connected_devices_nr(device);
90 | memset(buffer, 0, PAGE_SIZE);
91 |
92 | for (i = 0; i < 64 && PAGE_SIZE > n; i++) {
93 | device = akvcam_list_next(devices, &it);
94 |
95 | if (!it)
96 | break;
97 |
98 | n = snprintf(buffer + n,
99 | PAGE_SIZE - n,
100 | "/dev/video%d\n",
101 | akvcam_device_num(device));
102 | }
103 |
104 | return n;
105 | }
106 |
107 | static ssize_t akvcam_attributes_streaming_devices_show(struct device *dev,
108 | struct device_attribute *attribute,
109 | char *buffer)
110 | {
111 | struct video_device *vdev = to_video_device(dev);
112 | akvcam_device_t device = video_get_drvdata(vdev);
113 | akvcam_devices_list_t devices;
114 | akvcam_list_element_t it = NULL;
115 | size_t n = 0;
116 | size_t i;
117 |
118 | UNUSED(attribute);
119 | devices = akvcam_device_connected_devices_nr(device);
120 | memset(buffer, 0, PAGE_SIZE);
121 |
122 | for (i = 0; i < 64;) {
123 | device = akvcam_list_next(devices, &it);
124 |
125 | if (!it)
126 | break;
127 |
128 | if (akvcam_device_streaming(device)) {
129 | n = snprintf(buffer + n,
130 | PAGE_SIZE - n,
131 | "/dev/video%d\n",
132 | akvcam_device_num(device));
133 | i++;
134 | }
135 | }
136 |
137 | return n;
138 | }
139 |
140 | static ssize_t akvcam_attributes_device_modes_show(struct device *dev,
141 | struct device_attribute *attribute,
142 | char *buffer)
143 | {
144 | struct video_device *vdev = to_video_device(dev);
145 | akvcam_device_t device = video_get_drvdata(vdev);
146 | AKVCAM_RW_MODE rw_mode = akvcam_device_rw_mode(device);
147 | char *data = buffer;
148 | size_t i;
149 | size_t n = 0;
150 | static const akvcam_attributes_rw_mode_strings rw_mode_strings[] = {
151 | {AKVCAM_RW_MODE_READWRITE, "rw" },
152 | {AKVCAM_RW_MODE_MMAP , "mmap" },
153 | {AKVCAM_RW_MODE_USERPTR , "userptr"},
154 | {AKVCAM_RW_MODE_DMABUF , "dmabuf" },
155 | {0 , "" },
156 | };
157 |
158 | UNUSED(attribute);
159 | memset(data, 0, PAGE_SIZE);
160 |
161 | for (i = 0; akvcam_strlen(rw_mode_strings[i].str) > 0; i++)
162 | if (rw_mode_strings[i].rw_mode & rw_mode)
163 | n += snprintf(data + n, PAGE_SIZE - n, "%s\n", rw_mode_strings[i].str);
164 |
165 | return (ssize_t) n;
166 | }
167 |
168 |
169 | static ssize_t akvcam_attributes_int_show(struct device *dev,
170 | struct device_attribute *attribute,
171 | char *buffer)
172 | {
173 | struct video_device *vdev = to_video_device(dev);
174 | akvcam_device_t device = video_get_drvdata(vdev);
175 | akvcam_controls_t controls;
176 | __u32 id = akvcam_attributes_controls_id_by_name(attribute->attr.name);
177 | __s32 value;
178 |
179 | controls = akvcam_device_controls_nr(device);
180 | value = akvcam_controls_value(controls, id);
181 | memset(buffer, 0, PAGE_SIZE);
182 |
183 | return snprintf(buffer, PAGE_SIZE, "%d\n", value);
184 | }
185 |
186 | static ssize_t akvcam_attributes_int_store(struct device *dev,
187 | struct device_attribute *attribute,
188 | const char *buffer,
189 | size_t size)
190 | {
191 | struct video_device *vdev = to_video_device(dev);
192 | akvcam_device_t device = video_get_drvdata(vdev);
193 | akvcam_controls_t controls;
194 | __u32 id = akvcam_attributes_controls_id_by_name(attribute->attr.name);
195 | __s32 value = 0;
196 | int result;
197 |
198 | if (kstrtos32(buffer, 10, (__s32 *) &value) != 0)
199 | return -EINVAL;
200 |
201 | controls = akvcam_device_controls_nr(device);
202 | result = akvcam_controls_set_value(controls, id, value);
203 |
204 | if (result)
205 | return result;
206 |
207 | return (ssize_t) size;
208 | }
209 |
210 | static ssize_t akvcam_attributes_menu_show(struct device *dev,
211 | struct device_attribute *attribute,
212 | char *buffer)
213 | {
214 | struct video_device *vdev = to_video_device(dev);
215 | akvcam_device_t device = video_get_drvdata(vdev);
216 | akvcam_controls_t controls;
217 | __u32 id = akvcam_attributes_controls_id_by_name(attribute->attr.name);
218 | const char *value;
219 |
220 | controls = akvcam_device_controls_nr(device);
221 | value = akvcam_controls_string_value(controls, id);
222 | memset(buffer, 0, PAGE_SIZE);
223 |
224 | return snprintf(buffer, PAGE_SIZE, "%s\n", value);
225 | }
226 |
227 | static ssize_t akvcam_attributes_menu_store(struct device *dev,
228 | struct device_attribute *attribute,
229 | const char *buffer,
230 | size_t size)
231 | {
232 | struct video_device *vdev = to_video_device(dev);
233 | akvcam_device_t device = video_get_drvdata(vdev);
234 | akvcam_controls_t controls;
235 | char *buffer_stripped;
236 | __u32 id = akvcam_attributes_controls_id_by_name(attribute->attr.name);
237 | ssize_t result;
238 |
239 | controls = akvcam_device_controls_nr(device);
240 | buffer_stripped = akvcam_strip_str(buffer, AKVCAM_MEMORY_TYPE_KMALLOC);
241 | result = akvcam_controls_set_string_value(controls, id, buffer_stripped);
242 | kfree(buffer_stripped);
243 |
244 | if (result)
245 | return result;
246 |
247 | return size;
248 | }
249 |
250 | static DEVICE_ATTR(connected_devices,
251 | S_IRUGO,
252 | akvcam_attributes_connected_devices_show,
253 | NULL);
254 | static DEVICE_ATTR(listeners,
255 | S_IRUGO,
256 | akvcam_attributes_streaming_devices_show,
257 | NULL);
258 | static DEVICE_ATTR(broadcasters,
259 | S_IRUGO,
260 | akvcam_attributes_streaming_devices_show,
261 | NULL);
262 | static DEVICE_ATTR(modes,
263 | S_IRUGO,
264 | akvcam_attributes_device_modes_show,
265 | NULL);
266 | static DEVICE_ATTR(brightness,
267 | S_IRUGO | S_IWUSR,
268 | akvcam_attributes_int_show,
269 | akvcam_attributes_int_store);
270 | static DEVICE_ATTR(contrast,
271 | S_IRUGO | S_IWUSR,
272 | akvcam_attributes_int_show,
273 | akvcam_attributes_int_store);
274 | static DEVICE_ATTR(saturation,
275 | S_IRUGO | S_IWUSR,
276 | akvcam_attributes_int_show,
277 | akvcam_attributes_int_store);
278 | static DEVICE_ATTR(hue,
279 | S_IRUGO | S_IWUSR,
280 | akvcam_attributes_int_show,
281 | akvcam_attributes_int_store);
282 | static DEVICE_ATTR(gamma,
283 | S_IRUGO | S_IWUSR,
284 | akvcam_attributes_int_show,
285 | akvcam_attributes_int_store);
286 | static DEVICE_ATTR(hflip,
287 | S_IRUGO | S_IWUSR,
288 | akvcam_attributes_int_show,
289 | akvcam_attributes_int_store);
290 | static DEVICE_ATTR(colorfx,
291 | S_IRUGO | S_IWUSR,
292 | akvcam_attributes_menu_show,
293 | akvcam_attributes_menu_store);
294 | static DEVICE_ATTR(vflip,
295 | S_IRUGO | S_IWUSR,
296 | akvcam_attributes_int_show,
297 | akvcam_attributes_int_store);
298 | static DEVICE_ATTR(aspect_ratio,
299 | S_IRUGO | S_IWUSR,
300 | akvcam_attributes_menu_show,
301 | akvcam_attributes_menu_store);
302 | static DEVICE_ATTR(scaling,
303 | S_IRUGO | S_IWUSR,
304 | akvcam_attributes_menu_show,
305 | akvcam_attributes_menu_store);
306 | static DEVICE_ATTR(swap_rgb,
307 | S_IRUGO | S_IWUSR,
308 | akvcam_attributes_int_show,
309 | akvcam_attributes_int_store);
310 |
311 | // Define capture groups.
312 |
313 | static struct attribute *akvcam_attributes_capture[] = {
314 | &dev_attr_connected_devices.attr,
315 | &dev_attr_broadcasters.attr,
316 | &dev_attr_modes.attr,
317 | &dev_attr_brightness.attr,
318 | &dev_attr_contrast.attr,
319 | &dev_attr_saturation.attr,
320 | &dev_attr_hue.attr,
321 | &dev_attr_gamma.attr,
322 | &dev_attr_hflip.attr,
323 | &dev_attr_vflip.attr,
324 | &dev_attr_colorfx.attr,
325 | NULL
326 | };
327 |
328 | static struct attribute_group akvcam_attributes_capture_group = {
329 | .name = "controls",
330 | .attrs = akvcam_attributes_capture
331 | };
332 |
333 | static const struct attribute_group *akvcam_attributes_capture_groups[] = {
334 | &akvcam_attributes_capture_group,
335 | NULL
336 | };
337 |
338 | // Define output groups.
339 |
340 | static struct attribute *akvcam_attributes_output[] = {
341 | &dev_attr_connected_devices.attr,
342 | &dev_attr_listeners.attr,
343 | &dev_attr_modes.attr,
344 | &dev_attr_hflip.attr,
345 | &dev_attr_vflip.attr,
346 | &dev_attr_aspect_ratio.attr,
347 | &dev_attr_scaling.attr,
348 | &dev_attr_swap_rgb.attr,
349 | NULL
350 | };
351 |
352 | static struct attribute_group akvcam_attributes_output_group = {
353 | .name = "controls",
354 | .attrs = akvcam_attributes_output
355 | };
356 |
357 | static const struct attribute_group *akvcam_attributes_output_groups[] = {
358 | &akvcam_attributes_output_group,
359 | NULL
360 | };
361 |
--------------------------------------------------------------------------------
/src/attributes.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_ATTRIBUTES_H
20 | #define AKVCAM_ATTRIBUTES_H
21 |
22 | #include "device_types.h"
23 |
24 | const struct attribute_group **akvcam_attributes_groups(AKVCAM_DEVICE_TYPE device_type);
25 |
26 | #endif // AKVCAM_ATTRIBUTES_H
27 |
--------------------------------------------------------------------------------
/src/buffers.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #include "buffers.h"
26 | #include "device.h"
27 | #include "format.h"
28 | #include "frame.h"
29 | #include "log.h"
30 |
31 | #define AKVCAM_BUFFERS_MIN 2
32 |
33 | typedef struct {
34 | struct vb2_v4l2_buffer vb;
35 | struct list_head list;
36 | } akvcam_buffers_buffer, *akvcam_buffers_buffer_t;
37 |
38 | static const struct vb2_ops akvcam_akvcam_buffers_queue_ops;
39 |
40 | struct akvcam_buffers
41 | {
42 | struct kref ref;
43 | struct list_head buffers;
44 | struct vb2_queue queue;
45 | struct mutex buffers_mutex;
46 | struct mutex frames_mutex;
47 | akvcam_format_t format;
48 | akvcam_signal_callback(buffers, streaming_started);
49 | akvcam_signal_callback(buffers, streaming_stopped);
50 | enum v4l2_buf_type type;
51 | AKVCAM_RW_MODE rw_mode;
52 | __u32 sequence;
53 | };
54 |
55 | akvcam_signal_define(buffers, streaming_started)
56 | akvcam_signal_define(buffers, streaming_stopped)
57 |
58 | enum vb2_io_modes akvcam_buffers_io_modes_from_device_type(enum v4l2_buf_type type,
59 | AKVCAM_RW_MODE rw_mode);
60 | int akvcam_buffers_queue_setup(struct vb2_queue *queue,
61 | unsigned int *num_buffers,
62 | unsigned int *num_planes,
63 | unsigned int sizes[],
64 | struct device *alloc_devs[]);
65 | int akvcam_buffers_buffer_prepare(struct vb2_buffer *buffer);
66 | void akvcam_buffers_buffer_queue(struct vb2_buffer *buffer);
67 | int akvcam_buffers_start_streaming(struct vb2_queue *queue, unsigned int count);
68 | void akvcam_buffers_stop_streaming(struct vb2_queue *queue);
69 |
70 | akvcam_buffers_t akvcam_buffers_new(AKVCAM_RW_MODE rw_mode,
71 | enum v4l2_buf_type type)
72 | {
73 | akvcam_buffers_t self = kzalloc(sizeof(struct akvcam_buffers), GFP_KERNEL);
74 |
75 | kref_init(&self->ref);
76 | INIT_LIST_HEAD(&self->buffers);
77 | mutex_init(&self->buffers_mutex);
78 | mutex_init(&self->frames_mutex);
79 | self->rw_mode = rw_mode;
80 | self->type = type;
81 | self->format = akvcam_format_new(0, 0, 0, NULL);
82 | self->queue.type = type;
83 | self->queue.io_modes =
84 | akvcam_buffers_io_modes_from_device_type(self->type,
85 | self->rw_mode);
86 | self->queue.drv_priv = self;
87 | self->queue.lock = &self->buffers_mutex;
88 | self->queue.buf_struct_size = sizeof(akvcam_buffers_buffer);
89 | self->queue.mem_ops = &vb2_vmalloc_memops;
90 | self->queue.ops = &akvcam_akvcam_buffers_queue_ops;
91 | self->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
92 |
93 | akvcam_buffers_set_count(self, AKVCAM_BUFFERS_MIN);
94 |
95 | return self;
96 | }
97 |
98 | static void akvcam_buffers_free(struct kref *ref)
99 | {
100 | akvcam_buffers_t self = container_of(ref, struct akvcam_buffers, ref);
101 | akvcam_format_delete(self->format);
102 | kfree(self);
103 | }
104 |
105 | void akvcam_buffers_delete(akvcam_buffers_t self)
106 | {
107 | if (self)
108 | kref_put(&self->ref, akvcam_buffers_free);
109 | }
110 |
111 | akvcam_buffers_t akvcam_buffers_ref(akvcam_buffers_t self)
112 | {
113 | if (self)
114 | kref_get(&self->ref);
115 |
116 | return self;
117 | }
118 |
119 | akvcam_format_t akvcam_buffers_format(akvcam_buffers_ct self)
120 | {
121 | return akvcam_format_new_copy(self->format);
122 | }
123 |
124 | void akvcam_buffers_set_format(akvcam_buffers_t self, akvcam_format_ct format)
125 | {
126 | akvcam_format_copy(self->format, format);
127 | }
128 |
129 | size_t akvcam_buffers_count(akvcam_buffers_ct self)
130 | {
131 | #if LINUX_VERSION_CODE < KERNEL_VERSION( 6, 8, 0)
132 | return self->queue.min_buffers_needed;
133 | #else
134 | return self->queue.min_queued_buffers;
135 | #endif
136 | }
137 |
138 | void akvcam_buffers_set_count(akvcam_buffers_t self, size_t nbuffers)
139 | {
140 | #if LINUX_VERSION_CODE < KERNEL_VERSION( 6, 8, 0)
141 | self->queue.min_buffers_needed = nbuffers;
142 | #else
143 | self->queue.min_queued_buffers = nbuffers;
144 | #endif
145 | }
146 |
147 | akvcam_frame_t akvcam_buffers_read_frame(akvcam_buffers_t self)
148 | {
149 | akvcam_frame_t frame;
150 | akvcam_buffers_buffer_t buf;
151 | size_t i;
152 |
153 | akpr_function();
154 |
155 | if (mutex_lock_interruptible(&self->frames_mutex))
156 | return NULL;
157 |
158 | if (list_empty(&self->buffers)) {
159 | mutex_unlock(&self->frames_mutex);
160 |
161 | return NULL;
162 | }
163 |
164 | buf = list_entry(self->buffers.next, akvcam_buffers_buffer, list);
165 | list_del(&buf->list);
166 | buf->vb.vb2_buf.timestamp = ktime_get_ns();
167 | buf->vb.field = V4L2_FIELD_NONE;
168 | buf->vb.sequence = self->sequence++;
169 | mutex_unlock(&self->frames_mutex);
170 |
171 | frame = akvcam_frame_new(self->format, NULL, 0);
172 |
173 | for (i = 0; i < buf->vb.vb2_buf.num_planes; i++) {
174 | memcpy(akvcam_frame_plane_data(frame, i),
175 | vb2_plane_vaddr(&buf->vb.vb2_buf, i),
176 | akvcam_format_plane_size(self->format, i));
177 | }
178 |
179 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
180 |
181 | return frame;
182 | }
183 |
184 | int akvcam_buffers_write_frame(akvcam_buffers_t self, akvcam_frame_t frame)
185 | {
186 | akvcam_buffers_buffer_t buf;
187 | size_t i;
188 | int result;
189 |
190 | akpr_function();
191 | result = mutex_lock_interruptible(&self->frames_mutex);
192 |
193 | if (result)
194 | return result;
195 |
196 | if (list_empty(&self->buffers)) {
197 | mutex_unlock(&self->frames_mutex);
198 |
199 | return -EAGAIN;
200 | }
201 |
202 | buf = list_entry(self->buffers.next, akvcam_buffers_buffer, list);
203 | list_del(&buf->list);
204 | buf->vb.vb2_buf.timestamp = ktime_get_ns();
205 | buf->vb.field = V4L2_FIELD_NONE;
206 | buf->vb.sequence = self->sequence++;
207 | mutex_unlock(&self->frames_mutex);
208 |
209 | for (i = 0; i < buf->vb.vb2_buf.num_planes; i++) {
210 | memcpy(vb2_plane_vaddr(&buf->vb.vb2_buf, i),
211 | akvcam_frame_plane_data(frame, i),
212 | vb2_plane_size(&buf->vb.vb2_buf, i));
213 | }
214 |
215 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
216 |
217 | return 0;
218 | }
219 |
220 | struct vb2_queue *akvcam_buffers_vb2_queue(akvcam_buffers_t self)
221 | {
222 | return &self->queue;
223 | }
224 |
225 | enum vb2_io_modes akvcam_buffers_io_modes_from_device_type(enum v4l2_buf_type type,
226 | AKVCAM_RW_MODE rw_mode)
227 | {
228 | enum vb2_io_modes io_modes = 0;
229 |
230 | if (rw_mode & AKVCAM_RW_MODE_READWRITE) {
231 | if (akvcam_device_type_from_v4l2(type) == AKVCAM_DEVICE_TYPE_CAPTURE)
232 | io_modes |= VB2_READ;
233 | else
234 | io_modes |= VB2_WRITE;
235 | }
236 |
237 | if (rw_mode & AKVCAM_RW_MODE_MMAP)
238 | io_modes |= VB2_MMAP;
239 |
240 | if (rw_mode & AKVCAM_RW_MODE_USERPTR)
241 | io_modes |= VB2_USERPTR;
242 |
243 | if (rw_mode & AKVCAM_RW_MODE_DMABUF)
244 | io_modes |= VB2_DMABUF;
245 |
246 | return io_modes;
247 | }
248 |
249 | int akvcam_buffers_queue_setup(struct vb2_queue *queue,
250 | unsigned int *num_buffers,
251 | unsigned int *num_planes,
252 | unsigned int sizes[],
253 | struct device *alloc_devs[])
254 | {
255 | akvcam_buffers_t self = vb2_get_drv_priv(queue);
256 | size_t i;
257 | UNUSED(alloc_devs);
258 | akpr_function();
259 |
260 | if (*num_buffers < 1)
261 | *num_buffers = 1;
262 |
263 | if (*num_planes > 0) {
264 | if (*num_planes < akvcam_format_planes(self->format))
265 | return -EINVAL;
266 |
267 | for (i = 0; i < *num_planes; i++)
268 | if (sizes[i] < akvcam_format_plane_size(self->format, i))
269 | return -EINVAL;
270 |
271 | return 0;
272 | }
273 |
274 | *num_planes = akvcam_format_planes(self->format);
275 |
276 | for (i = 0; i < *num_planes; i++)
277 | sizes[i] = akvcam_format_plane_size(self->format, i);
278 |
279 | return 0;
280 | }
281 |
282 | int akvcam_buffers_buffer_prepare(struct vb2_buffer *buffer)
283 | {
284 | akvcam_buffers_t self = vb2_get_drv_priv(buffer->vb2_queue);
285 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buffer);
286 | size_t i;
287 |
288 | akpr_function();
289 |
290 | for (i = 0; i < buffer->num_planes; i++) {
291 | size_t plane_size = akvcam_format_plane_size(self->format, i);
292 |
293 | if (vb2_plane_size(buffer, i) < plane_size)
294 | return -EINVAL;
295 | else
296 | vb2_set_plane_payload(buffer, i, plane_size);
297 | }
298 |
299 | if (vbuf->field == V4L2_FIELD_ANY)
300 | vbuf->field = V4L2_FIELD_NONE;
301 |
302 | return 0;
303 | }
304 |
305 | void akvcam_buffers_buffer_queue(struct vb2_buffer *buffer)
306 | {
307 | akvcam_buffers_t self = vb2_get_drv_priv(buffer->vb2_queue);
308 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buffer);
309 | akvcam_buffers_buffer_t buf = container_of(vbuf, akvcam_buffers_buffer, vb);
310 |
311 | akpr_function();
312 |
313 | if (!mutex_lock_interruptible(&self->frames_mutex)) {
314 | list_add_tail(&buf->list, &self->buffers);
315 | mutex_unlock(&self->frames_mutex);
316 | }
317 | }
318 |
319 | int akvcam_buffers_start_streaming(struct vb2_queue *queue, unsigned int count)
320 | {
321 | akvcam_buffers_t self = vb2_get_drv_priv(queue);
322 | UNUSED(count);
323 |
324 | akpr_function();
325 | self->sequence = 0;
326 |
327 | return akvcam_call_no_args(self, streaming_started);
328 | }
329 |
330 | void akvcam_buffers_stop_streaming(struct vb2_queue *queue)
331 | {
332 | akvcam_buffers_t self = vb2_get_drv_priv(queue);
333 |
334 | akpr_function();
335 | akvcam_emit_no_args(self, streaming_stopped);
336 |
337 | if (!mutex_lock_interruptible(&self->frames_mutex)) {
338 | akvcam_buffers_buffer_t buf;
339 | akvcam_buffers_buffer_t node;
340 |
341 | list_for_each_entry_safe(buf, node, &self->buffers, list) {
342 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
343 | list_del(&buf->list);
344 | }
345 |
346 | mutex_unlock(&self->frames_mutex);
347 | }
348 | }
349 |
350 | static const struct vb2_ops akvcam_akvcam_buffers_queue_ops = {
351 | .queue_setup = akvcam_buffers_queue_setup,
352 | .buf_prepare = akvcam_buffers_buffer_prepare,
353 | .buf_queue = akvcam_buffers_buffer_queue,
354 | .start_streaming = akvcam_buffers_start_streaming,
355 | .stop_streaming = akvcam_buffers_stop_streaming,
356 | .wait_prepare = vb2_ops_wait_prepare,
357 | .wait_finish = vb2_ops_wait_finish,
358 | };
359 |
--------------------------------------------------------------------------------
/src/buffers.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_BUFFERS_H
20 | #define AKVCAM_BUFFERS_H
21 |
22 | #include
23 |
24 | #include "buffers_types.h"
25 | #include "device_types.h"
26 | #include "format_types.h"
27 | #include "frame_types.h"
28 | #include "utils.h"
29 |
30 | enum v4l2_buf_type;
31 | struct vb2_queue;
32 |
33 | akvcam_buffers_t akvcam_buffers_new(AKVCAM_RW_MODE rw_mode,
34 | enum v4l2_buf_type type);
35 | void akvcam_buffers_delete(akvcam_buffers_t self);
36 | akvcam_buffers_t akvcam_buffers_ref(akvcam_buffers_t self);
37 |
38 | akvcam_format_t akvcam_buffers_format(akvcam_buffers_ct self);
39 | void akvcam_buffers_set_format(akvcam_buffers_t self, akvcam_format_ct format);
40 | size_t akvcam_buffers_count(akvcam_buffers_ct self);
41 | void akvcam_buffers_set_count(akvcam_buffers_t self, size_t nbuffers);
42 | akvcam_frame_t akvcam_buffers_read_frame(akvcam_buffers_t self);
43 | int akvcam_buffers_write_frame(akvcam_buffers_t self, akvcam_frame_t frame);
44 | struct vb2_queue *akvcam_buffers_vb2_queue(akvcam_buffers_t self);
45 |
46 | // signals
47 | akvcam_signal_no_args(buffers, streaming_started);
48 | akvcam_signal_no_args(buffers, streaming_stopped);
49 |
50 | #endif // AKVCAM_BUFFERS_H
51 |
--------------------------------------------------------------------------------
/src/buffers_types.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_BUFFERS_TYPES_H
20 | #define AKVCAM_BUFFERS_TYPES_H
21 |
22 | struct akvcam_buffers;
23 | typedef struct akvcam_buffers *akvcam_buffers_t;
24 | typedef const struct akvcam_buffers *akvcam_buffers_ct;
25 |
26 | #endif // AKVCAM_BUFFERS_TYPES_H
27 |
--------------------------------------------------------------------------------
/src/controls.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "controls.h"
24 | #include "frame_types.h"
25 |
26 | struct akvcam_controls
27 | {
28 | struct kref ref;
29 | struct v4l2_ctrl_handler handler;
30 | akvcam_signal_callback(controls, updated);
31 | };
32 |
33 | akvcam_signal_define(controls, updated)
34 |
35 | static const struct v4l2_ctrl_ops akvcam_controls_ops;
36 |
37 | static const struct v4l2_ctrl_config akvcam_controls_capture[] = {
38 | {.id = V4L2_CID_BRIGHTNESS, .min = -255 , .max = 255 , .step = 1},
39 | {.id = V4L2_CID_CONTRAST , .min = -255 , .max = 255 , .step = 1},
40 | {.id = V4L2_CID_SATURATION, .min = -255 , .max = 255 , .step = 1},
41 | {.id = V4L2_CID_HUE , .min = -359 , .max = 359 , .step = 1},
42 | {.id = V4L2_CID_GAMMA , .min = -255 , .max = 255 , .step = 1},
43 | {.id = V4L2_CID_HFLIP , .min = 0 , .max = 1 , .step = 1},
44 | {.id = V4L2_CID_VFLIP , .min = 0 , .max = 1 , .step = 1},
45 | {.id = V4L2_CID_COLORFX , .min = V4L2_COLORFX_NONE, .max = V4L2_COLORFX_BW, .step = 1},
46 | {.id = 0 },
47 | };
48 |
49 | static const char * const akvcam_controls_scaling_menu[] = {
50 | [AKVCAM_SCALING_FAST ] = "Fast" ,
51 | [AKVCAM_SCALING_LINEAR] = "Linear",
52 | };
53 |
54 | static const char * const akvcam_controls_aspect_menu[] = {
55 | [AKVCAM_ASPECT_RATIO_IGNORE ] = "Ignore" ,
56 | [AKVCAM_ASPECT_RATIO_KEEP ] = "Keep" ,
57 | [AKVCAM_ASPECT_RATIO_EXPANDING] = "Expanding",
58 | };
59 |
60 | static const struct v4l2_ctrl_config akvcam_controls_output[] = {
61 | {.id = V4L2_CID_HFLIP, .max = 1, .step = 1},
62 | {.id = V4L2_CID_VFLIP, .max = 1, .step = 1},
63 | {
64 | .id = AKVCAM_CID_SCALING,
65 | .type = V4L2_CTRL_TYPE_MENU,
66 | .name = "Scaling Mode",
67 | .max = ARRAY_SIZE(akvcam_controls_scaling_menu) - 1,
68 | .step = 0,
69 | .qmenu = akvcam_controls_scaling_menu,
70 | .ops = &akvcam_controls_ops
71 | },
72 | {
73 | .id = AKVCAM_CID_ASPECT_RATIO,
74 | .type = V4L2_CTRL_TYPE_MENU,
75 | .name = "Aspect Ratio Mode" ,
76 | .max = ARRAY_SIZE(akvcam_controls_aspect_menu) - 1,
77 | .step = 0,
78 | .qmenu = akvcam_controls_aspect_menu,
79 | .ops = &akvcam_controls_ops
80 | },
81 | {
82 | .id = AKVCAM_CID_SWAP_RGB,
83 | .type = V4L2_CTRL_TYPE_BOOLEAN,
84 | .name = "Swap Read and Blue",
85 | .max = 1,
86 | .step = 1,
87 | .ops = &akvcam_controls_ops
88 | },
89 | {.id = 0},
90 | };
91 |
92 | int akvcam_controls_cotrol_changed(struct v4l2_ctrl *control);
93 |
94 | akvcam_controls_t akvcam_controls_new(AKVCAM_DEVICE_TYPE device_type)
95 | {
96 | akvcam_controls_t self = kzalloc(sizeof(struct akvcam_controls), GFP_KERNEL);
97 | const struct v4l2_ctrl_config *control_params;
98 | size_t n_controls = 0;
99 | size_t i;
100 |
101 | kref_init(&self->ref);
102 |
103 | // Initialize controls with default values.
104 | if (device_type == AKVCAM_DEVICE_TYPE_OUTPUT)
105 | control_params = akvcam_controls_output;
106 | else
107 | control_params = akvcam_controls_capture;
108 |
109 | for (i = 0; control_params[i].id; i++)
110 | n_controls++;
111 |
112 | v4l2_ctrl_handler_init(&self->handler, n_controls);
113 |
114 | for (i = 0; control_params[i].id; i++) {
115 | const struct v4l2_ctrl_config *params = control_params + i;
116 |
117 | if (params->id < AKVCAM_CID_BASE) {
118 | const char *name;
119 | enum v4l2_ctrl_type type;
120 | s64 min;
121 | s64 max;
122 | u64 step;
123 | s64 def;
124 | u32 flags;
125 | v4l2_ctrl_fill(params->id,
126 | &name,
127 | &type,
128 | &min,
129 | &max,
130 | &step,
131 | &def,
132 | &flags);
133 |
134 | if (type == V4L2_CTRL_TYPE_MENU) {
135 | v4l2_ctrl_new_std_menu(&self->handler,
136 | &akvcam_controls_ops,
137 | params->id,
138 | params->max,
139 | params->menu_skip_mask,
140 | params->def);
141 | } else {
142 | v4l2_ctrl_new_std(&self->handler,
143 | &akvcam_controls_ops,
144 | params->id,
145 | params->min,
146 | params->max,
147 | params->step,
148 | params->def);
149 | }
150 | } else {
151 | v4l2_ctrl_new_custom(&self->handler, params, self);
152 | }
153 | }
154 |
155 | return self;
156 | }
157 |
158 | static void akvcam_controls_free(struct kref *ref)
159 | {
160 | akvcam_controls_t self = container_of(ref, struct akvcam_controls, ref);
161 | v4l2_ctrl_handler_free(&self->handler);;
162 | kfree(self);
163 | }
164 |
165 | void akvcam_controls_delete(akvcam_controls_t self)
166 | {
167 | if (self)
168 | kref_put(&self->ref, akvcam_controls_free);
169 | }
170 |
171 | akvcam_controls_t akvcam_controls_ref(akvcam_controls_t self)
172 | {
173 | if (self)
174 | kref_get(&self->ref);
175 |
176 | return self;
177 | }
178 | __s32 akvcam_controls_value(akvcam_controls_t self, __u32 id)
179 | {
180 | struct v4l2_ctrl *control = v4l2_ctrl_find(&self->handler, id);
181 |
182 | if (!control)
183 | return 0;
184 |
185 | return v4l2_ctrl_g_ctrl(control);
186 | }
187 |
188 | const char *akvcam_controls_string_value(akvcam_controls_t self, __u32 id)
189 | {
190 | struct v4l2_ctrl *control = v4l2_ctrl_find(&self->handler, id);
191 |
192 | if (!control || !control->qmenu)
193 | return NULL;
194 |
195 | return control->qmenu[v4l2_ctrl_g_ctrl(control)];
196 | }
197 |
198 | int akvcam_controls_set_value(akvcam_controls_t self, __u32 id, __s32 value)
199 | {
200 | struct v4l2_ctrl *control = v4l2_ctrl_find(&self->handler, id);
201 | int result;
202 |
203 | if (!control)
204 | return -EINVAL;
205 |
206 | result = v4l2_ctrl_s_ctrl(control, value);
207 |
208 | if (result)
209 | return result;
210 |
211 | akvcam_emit(self, updated, control->id, control->val);
212 |
213 | return 0;
214 | }
215 |
216 | int akvcam_controls_set_string_value(akvcam_controls_t self, __u32 id, const char *value)
217 | {
218 | struct v4l2_ctrl *control = v4l2_ctrl_find(&self->handler, id);
219 | s64 i;
220 | int result = -EINVAL;
221 |
222 | if (!control || !control->qmenu)
223 | return -EINVAL;
224 |
225 | for (i = 0; i <= control->maximum; i++)
226 | if (strncmp(control->qmenu[i], value, AKVCAM_MAX_STRING_SIZE) == 0) {
227 | result = 0;
228 |
229 | break;
230 | }
231 |
232 | if (result)
233 | return result;
234 |
235 | result = v4l2_ctrl_s_ctrl(control, i);
236 |
237 | if (result)
238 | return result;
239 |
240 | akvcam_emit(self, updated, control->id, control->val);
241 |
242 | return 0;
243 | }
244 |
245 | struct v4l2_ctrl_handler *akvcam_controls_handler(akvcam_controls_t self)
246 | {
247 | return self->handler.error? NULL: &self->handler;
248 | }
249 |
250 | int akvcam_controls_cotrol_changed(struct v4l2_ctrl *control)
251 | {
252 | akvcam_controls_t self =
253 | container_of(control->handler, struct akvcam_controls, handler);
254 |
255 | akvcam_emit(self, updated, control->id, control->val);
256 |
257 | return 0;
258 | }
259 |
260 | static const struct v4l2_ctrl_ops akvcam_controls_ops = {
261 | .s_ctrl = akvcam_controls_cotrol_changed,
262 | };
263 |
--------------------------------------------------------------------------------
/src/controls.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_CONTROLS_H
20 | #define AKVCAM_CONTROLS_H
21 |
22 | #include
23 |
24 | #include "controls_types.h"
25 | #include "device_types.h"
26 | #include "utils.h"
27 |
28 | // public
29 | akvcam_controls_t akvcam_controls_new(AKVCAM_DEVICE_TYPE device_type);
30 | void akvcam_controls_delete(akvcam_controls_t self);
31 | akvcam_controls_t akvcam_controls_ref(akvcam_controls_t self);
32 |
33 | __s32 akvcam_controls_value(akvcam_controls_t self, __u32 id);
34 | const char *akvcam_controls_string_value(akvcam_controls_t self, __u32 id);
35 | int akvcam_controls_set_value(akvcam_controls_t self, __u32 id, __s32 value);
36 | int akvcam_controls_set_string_value(akvcam_controls_t self, __u32 id, const char *value);
37 | struct v4l2_ctrl_handler *akvcam_controls_handler(akvcam_controls_t self);
38 |
39 | // signals
40 | akvcam_signal(controls, updated, __u32 id, __s32 value);
41 |
42 | #endif // AKVCAM_CONTROLS_H
43 |
--------------------------------------------------------------------------------
/src/controls_types.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_CONTROLS_TYPES_H
20 | #define AKVCAM_CONTROLS_TYPES_H
21 |
22 | #define AKVCAM_CID_BASE (V4L2_CID_USER_BASE | 0xe000)
23 | #define AKVCAM_CID_SCALING (AKVCAM_CID_BASE + 0)
24 | #define AKVCAM_CID_ASPECT_RATIO (AKVCAM_CID_BASE + 1)
25 | #define AKVCAM_CID_SWAP_RGB (AKVCAM_CID_BASE + 2)
26 |
27 | struct akvcam_controls;
28 | typedef struct akvcam_controls *akvcam_controls_t;
29 | typedef const struct akvcam_controls *akvcam_controls_ct;
30 |
31 | #endif // AKVCAM_CONTROLS_TYPES_H
32 |
--------------------------------------------------------------------------------
/src/device.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_DEVICE_H
20 | #define AKVCAM_DEVICE_H
21 |
22 | #include "device_types.h"
23 | #include "buffers_types.h"
24 | #include "controls_types.h"
25 | #include "format_types.h"
26 | #include "frame_filter_types.h"
27 | #include "frame_types.h"
28 |
29 | struct file;
30 |
31 | // public
32 | akvcam_device_t akvcam_device_new(const char *name,
33 | const char *description,
34 | AKVCAM_DEVICE_TYPE type,
35 | AKVCAM_RW_MODE rw_mode,
36 | akvcam_formats_list_t formats,
37 | akvcam_frame_ct default_frame,
38 | akvcam_frame_filter_ct frame_filter);
39 | void akvcam_device_delete(akvcam_device_t self);
40 | akvcam_device_t akvcam_device_ref(akvcam_device_t self);
41 |
42 | bool akvcam_device_register(akvcam_device_t self);
43 | void akvcam_device_unregister(akvcam_device_t self);
44 | int32_t akvcam_device_num(akvcam_device_ct self);
45 | void akvcam_device_set_num(akvcam_device_t self, int32_t num);
46 | bool akvcam_device_is_registered(akvcam_device_ct self);
47 | const char *akvcam_device_description(akvcam_device_t self);
48 | AKVCAM_DEVICE_TYPE akvcam_device_type(akvcam_device_ct self);
49 | enum v4l2_buf_type akvcam_device_v4l2_type(akvcam_device_ct self);
50 | AKVCAM_RW_MODE akvcam_device_rw_mode(akvcam_device_ct self);
51 | akvcam_formats_list_t akvcam_device_formats(akvcam_device_ct self);
52 | akvcam_format_t akvcam_device_format(akvcam_device_ct self);
53 | void akvcam_device_set_format(akvcam_device_t self,
54 | akvcam_format_t format);
55 | akvcam_controls_t akvcam_device_controls_nr(akvcam_device_ct self);
56 | akvcam_controls_t akvcam_device_controls(akvcam_device_ct self);
57 | akvcam_buffers_t akvcam_device_buffers_nr(akvcam_device_ct self);
58 | akvcam_buffers_t akvcam_device_buffers(akvcam_device_ct self);
59 | bool akvcam_device_streaming(akvcam_device_ct self);
60 | akvcam_devices_list_t akvcam_device_connected_devices_nr(akvcam_device_ct self);
61 | akvcam_devices_list_t akvcam_device_connected_devices(akvcam_device_ct self);
62 | __u32 akvcam_device_caps(akvcam_device_ct self);
63 |
64 | // public static
65 | AKVCAM_DEVICE_TYPE akvcam_device_type_from_v4l2(enum v4l2_buf_type type);
66 |
67 | #endif //AKVCAM_ DEVICE_H
68 |
--------------------------------------------------------------------------------
/src/device_types.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_DEVICE_TYPES_H
20 | #define AKVCAM_DEVICE_TYPES_H
21 |
22 | #include
23 |
24 | #include "list_types.h"
25 |
26 | #define AKVCAM_RW_MODE_READWRITE BIT(0)
27 | #define AKVCAM_RW_MODE_MMAP BIT(1)
28 | #define AKVCAM_RW_MODE_USERPTR BIT(2)
29 | #define AKVCAM_RW_MODE_DMABUF BIT(3)
30 |
31 | struct akvcam_device;
32 | typedef struct akvcam_device *akvcam_device_t;
33 | typedef const struct akvcam_device *akvcam_device_ct;
34 | typedef akvcam_list_tt(akvcam_device_t) akvcam_devices_list_t;
35 | typedef akvcam_list_ctt(akvcam_device_t) akvcam_devices_list_ct;
36 | typedef __u32 AKVCAM_RW_MODE;
37 |
38 | typedef enum
39 | {
40 | AKVCAM_DEVICE_TYPE_CAPTURE,
41 | AKVCAM_DEVICE_TYPE_OUTPUT,
42 | } AKVCAM_DEVICE_TYPE;
43 |
44 | #endif // AKVCAM_DEVICE_TYPES_H
45 |
--------------------------------------------------------------------------------
/src/dkms.conf:
--------------------------------------------------------------------------------
1 | PACKAGE_NAME="akvcam"
2 | PACKAGE_VERSION="1.2.6"
3 |
4 | MAKE[0]="make KERNEL_DIR=${kernel_source_dir} all"
5 | CLEAN="make clean"
6 |
7 | BUILT_MODULE_NAME[0]="$PACKAGE_NAME"
8 | DEST_MODULE_LOCATION[0]="/extra"
9 |
10 | AUTOINSTALL="yes"
11 |
--------------------------------------------------------------------------------
/src/driver.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_DRIVER_H
20 | #define AKVCAM_DRIVER_H
21 |
22 | #include
23 |
24 | // public static
25 | int akvcam_driver_init(const char *name, const char *description);
26 | void akvcam_driver_uninit(void);
27 |
28 | const char *akvcam_driver_name(void);
29 | const char *akvcam_driver_description(void);
30 | uint akvcam_driver_version(void);
31 |
32 | #endif // AKVCAM_DRIVER_H
33 |
--------------------------------------------------------------------------------
/src/file_read.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #include "file_read.h"
26 | #include "log.h"
27 | #include "rbuffer.h"
28 | #include "utils.h"
29 |
30 | #define AKVCAM_READ_BLOCK 512
31 |
32 | struct akvcam_file
33 | {
34 | struct kref ref;
35 | char *file_name;
36 | struct file *filp;
37 | akvcam_rbuffer_tt(char *) buffer;
38 | size_t size;
39 | size_t bytes_read;
40 | size_t file_bytes_read;
41 | bool is_open;
42 | };
43 |
44 | akvcam_file_t akvcam_file_new(const char *file_name)
45 | {
46 | akvcam_file_t self = kzalloc(sizeof(struct akvcam_file), GFP_KERNEL);
47 | kref_init(&self->ref);
48 | self->file_name = akvcam_strdup(file_name, AKVCAM_MEMORY_TYPE_KMALLOC);
49 | self->buffer = akvcam_rbuffer_new();
50 |
51 | return self;
52 | }
53 |
54 | static void akvcam_file_free(struct kref *ref)
55 | {
56 | akvcam_file_t self = container_of(ref, struct akvcam_file, ref);
57 | akvcam_file_close(self);
58 |
59 | if (self->file_name)
60 | kfree(self->file_name);
61 |
62 | akvcam_rbuffer_delete(self->buffer);
63 | kfree(self);
64 | }
65 |
66 | void akvcam_file_delete(akvcam_file_t self)
67 | {
68 | if (self)
69 | kref_put(&self->ref, akvcam_file_free);
70 | }
71 |
72 | akvcam_file_t akvcam_file_ref(akvcam_file_t self)
73 | {
74 | if (self)
75 | kref_get(&self->ref);
76 |
77 | return self;
78 | }
79 |
80 | const char *akvcam_file_file_name(akvcam_file_ct self)
81 | {
82 | return self->file_name;
83 | }
84 |
85 | void akvcam_file_set_file_name(akvcam_file_t self, const char *file_name)
86 | {
87 | if (self->file_name)
88 | kfree(self->file_name);
89 |
90 | self->file_name = akvcam_strdup(file_name, AKVCAM_MEMORY_TYPE_KMALLOC);
91 | }
92 |
93 | bool akvcam_file_open(akvcam_file_t self)
94 | {
95 | akvcam_file_close(self);
96 |
97 | if (akvcam_strlen(self->file_name) < 1)
98 | return false;
99 |
100 | self->filp = filp_open(self->file_name, O_RDONLY, 0);
101 |
102 | if (IS_ERR(self->filp)) {
103 | int error = PTR_ERR(self->filp);
104 | char *error_str = kzalloc(AKVCAM_MAX_STRING_SIZE, GFP_KERNEL);
105 |
106 | akvcam_string_from_error(error, error_str, AKVCAM_MAX_STRING_SIZE);
107 | akpr_err("%s\n", error_str);
108 | kfree(error_str);
109 |
110 | return false;
111 | }
112 |
113 | self->size = i_size_read(self->filp->f_inode);
114 | akvcam_rbuffer_resize(self->buffer,
115 | self->size,
116 | sizeof(char),
117 | AKVCAM_MEMORY_TYPE_VMALLOC);
118 | akvcam_rbuffer_clear(self->buffer);
119 | self->bytes_read = 0;
120 | self->file_bytes_read = 0;
121 | self->is_open = true;
122 |
123 | return true;
124 | }
125 |
126 | void akvcam_file_close(akvcam_file_t self)
127 | {
128 | if (!self->is_open)
129 | return;
130 |
131 | filp_close(self->filp, NULL);
132 | self->filp = NULL;
133 | akvcam_rbuffer_clear(self->buffer);
134 | akvcam_rbuffer_resize(self->buffer,
135 | 0,
136 | sizeof(char),
137 | AKVCAM_MEMORY_TYPE_VMALLOC);
138 | self->size = 0;
139 | self->bytes_read = 0;
140 | self->file_bytes_read = 0;
141 | self->is_open = false;
142 | }
143 |
144 | bool akvcam_file_is_open(akvcam_file_ct self)
145 | {
146 | return self->is_open;
147 | }
148 |
149 | bool akvcam_file_eof(akvcam_file_ct self)
150 | {
151 | return self->bytes_read >= self->size;
152 | }
153 |
154 | bool akvcam_file_seek(akvcam_file_t self, ssize_t offset, AKVCAM_FILE_SEEK pos)
155 | {
156 | if (!self->is_open)
157 | return false;
158 |
159 | akvcam_rbuffer_clear(self->buffer);
160 |
161 | switch (pos) {
162 | case AKVCAM_FILE_SEEK_BEG:
163 | self->bytes_read =
164 | self->file_bytes_read =
165 | (size_t) akvcam_bound(0, offset, (ssize_t) self->size);
166 |
167 | break;
168 |
169 | case AKVCAM_FILE_SEEK_CUR:
170 | self->bytes_read =
171 | self->file_bytes_read =
172 | (size_t) akvcam_bound(0,
173 | (ssize_t) self->bytes_read + offset,
174 | (ssize_t) self->size);
175 |
176 | break;
177 |
178 | case AKVCAM_FILE_SEEK_END:
179 | self->bytes_read =
180 | self->file_bytes_read =
181 | (size_t) akvcam_bound(0,
182 | (ssize_t) self->size + offset,
183 | (ssize_t) self->size);
184 |
185 | break;
186 | }
187 |
188 | vfs_setpos(self->filp, (loff_t) self->bytes_read, (loff_t) self->size);
189 |
190 | return true;
191 | }
192 |
193 | size_t akvcam_file_read(akvcam_file_t self, void *data, size_t size)
194 | {
195 | loff_t offset;
196 | char read_block[AKVCAM_READ_BLOCK];
197 |
198 | if (!self->is_open || size < 1)
199 | return 0;
200 |
201 | while (self->file_bytes_read < self->size
202 | && akvcam_rbuffer_data_size(self->buffer) < size) {
203 | ssize_t bytes_read;
204 |
205 | offset = (loff_t) self->file_bytes_read;
206 | bytes_read = kernel_read(self->filp,
207 | read_block,
208 | AKVCAM_READ_BLOCK,
209 | &offset);
210 |
211 | if (bytes_read < 1)
212 | break;
213 |
214 | akvcam_rbuffer_queue_bytes(self->buffer, read_block, (size_t) bytes_read);
215 | self->file_bytes_read += (size_t) bytes_read;
216 | }
217 |
218 | size = akvcam_min(akvcam_rbuffer_size(self->buffer), size);
219 |
220 | if (size < 1)
221 | return 0;
222 |
223 | akvcam_rbuffer_dequeue_bytes(self->buffer, data, &size, false);
224 | self->bytes_read += size;
225 |
226 | return size;
227 | }
228 |
229 | static bool akvcam_file_find_new_line(const char *element,
230 | const char *new_line)
231 | {
232 | return strncmp(element, new_line, 1) == 0;
233 | }
234 |
235 | char *akvcam_file_read_line(akvcam_file_t self)
236 | {
237 | loff_t offset;
238 | ssize_t bytes_read;
239 | ssize_t new_line = -1;
240 | char read_block[AKVCAM_READ_BLOCK];
241 | char *line;
242 |
243 | if (!self->is_open)
244 | return vzalloc(1);
245 |
246 | for (;;) {
247 | new_line = 0;
248 | akvcam_rbuffer_find(self->buffer,
249 | "\n",
250 | (akvcam_are_equals_t) akvcam_file_find_new_line,
251 | &new_line);
252 |
253 | if (new_line >= 0)
254 | break;
255 |
256 | if (self->file_bytes_read >= self->size)
257 | break;
258 |
259 | bytes_read = (ssize_t) akvcam_min(AKVCAM_READ_BLOCK,
260 | self->size - self->file_bytes_read);
261 |
262 | if (bytes_read < 1)
263 | break;
264 |
265 | offset = (loff_t) self->file_bytes_read;
266 | bytes_read = kernel_read(self->filp,
267 | read_block,
268 | (size_t) bytes_read,
269 | &offset);
270 | akvcam_rbuffer_queue_bytes(self->buffer, read_block, (size_t) bytes_read);
271 | self->file_bytes_read += (size_t) bytes_read;
272 | }
273 |
274 | if (new_line >= 0) {
275 | line = vzalloc((size_t) new_line + 2);
276 | new_line++;
277 | akvcam_rbuffer_dequeue_bytes(self->buffer,
278 | line,
279 | (size_t *) &new_line,
280 | false);
281 | line[(size_t) new_line - 1] = 0;
282 | self->bytes_read += (size_t) new_line;
283 | } else if (self->bytes_read < self->size) {
284 | new_line = (ssize_t) akvcam_rbuffer_data_size(self->buffer);
285 | line = vzalloc((size_t) new_line + 1);
286 | akvcam_rbuffer_dequeue_bytes(self->buffer,
287 | line,
288 | (size_t *) &new_line,
289 | false);
290 | self->bytes_read += (size_t) new_line;
291 | } else {
292 | line = vzalloc(1);
293 | }
294 |
295 | return line;
296 | }
297 |
--------------------------------------------------------------------------------
/src/file_read.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_FILE_H
20 | #define AKVCAM_FILE_H
21 |
22 | #include
23 |
24 | struct akvcam_file;
25 | typedef struct akvcam_file *akvcam_file_t;
26 | typedef const struct akvcam_file *akvcam_file_ct;
27 |
28 | typedef enum
29 | {
30 | AKVCAM_FILE_SEEK_BEG,
31 | AKVCAM_FILE_SEEK_CUR,
32 | AKVCAM_FILE_SEEK_END
33 | } AKVCAM_FILE_SEEK;
34 |
35 | // public
36 | akvcam_file_t akvcam_file_new(const char *file_name);
37 | void akvcam_file_delete(akvcam_file_t self);
38 | akvcam_file_t akvcam_file_ref(akvcam_file_t self);
39 |
40 | const char *akvcam_file_file_name(akvcam_file_ct self);
41 | void akvcam_file_set_file_name(akvcam_file_t self, const char *file_name);
42 | bool akvcam_file_open(akvcam_file_t self);
43 | void akvcam_file_close(akvcam_file_t self);
44 | bool akvcam_file_is_open(akvcam_file_ct self);
45 | bool akvcam_file_eof(akvcam_file_ct self);
46 | bool akvcam_file_seek(akvcam_file_t self, ssize_t offset, AKVCAM_FILE_SEEK pos);
47 | size_t akvcam_file_read(akvcam_file_t self, void *data, size_t size);
48 | char *akvcam_file_read_line(akvcam_file_t self);
49 |
50 | #endif // AKVCAM_FILE_H
51 |
--------------------------------------------------------------------------------
/src/format.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_FORMAT_H
20 | #define AKVCAM_FORMAT_H
21 |
22 | #include
23 |
24 | #include "format_types.h"
25 |
26 | struct v4l2_fract;
27 | struct v4l2_format;
28 |
29 | // public
30 | akvcam_format_t akvcam_format_new(__u32 fourcc,
31 | size_t width,
32 | size_t height,
33 | const struct v4l2_fract *frame_rate);
34 | akvcam_format_t akvcam_format_new_copy(akvcam_format_ct other);
35 | void akvcam_format_delete(akvcam_format_t self);
36 | akvcam_format_t akvcam_format_ref(akvcam_format_t self);
37 |
38 | void akvcam_format_copy(akvcam_format_t self, akvcam_format_ct other);
39 | __u32 akvcam_format_fourcc(akvcam_format_ct self);
40 | void akvcam_format_set_fourcc(akvcam_format_t self, __u32 fourcc);
41 | const char *akvcam_format_fourcc_str(akvcam_format_ct self);
42 | void akvcam_format_set_fourcc_str(akvcam_format_t self, const char *fourcc);
43 | size_t akvcam_format_width(akvcam_format_ct self);
44 | void akvcam_format_set_width(akvcam_format_t self, size_t width);
45 | size_t akvcam_format_height(akvcam_format_ct self);
46 | void akvcam_format_set_height(akvcam_format_t self, size_t height);
47 | struct v4l2_fract akvcam_format_frame_rate(akvcam_format_ct self);
48 | void akvcam_format_set_frame_rate(akvcam_format_t self, const struct v4l2_fract frame_rate);
49 | size_t akvcam_format_bpp(akvcam_format_ct self);
50 | size_t akvcam_format_bypl(akvcam_format_ct self, size_t plane);
51 | size_t akvcam_format_size(akvcam_format_ct self);
52 | size_t akvcam_format_planes(akvcam_format_ct self);
53 | size_t akvcam_format_offset(akvcam_format_ct self, size_t plane);
54 | size_t akvcam_format_plane_size(akvcam_format_ct self, size_t plane);
55 | bool akvcam_format_is_valid(akvcam_format_ct self);
56 | void akvcam_format_clear(akvcam_format_t self);
57 | const char *akvcam_format_to_string(akvcam_format_t self);
58 |
59 | // public static
60 | void akvcam_format_round_nearest(int width, int height,
61 | int *owidth, int *oheight,
62 | int align);
63 | __u32 akvcam_format_fourcc_from_string(const char *fourcc_str);
64 | const char *akvcam_format_string_from_fourcc(__u32 fourcc);
65 | akvcam_format_t akvcam_format_nearest(akvcam_formats_list_ct formats,
66 | akvcam_format_ct format);
67 | akvcam_pixel_formats_list_t akvcam_format_pixel_formats(akvcam_formats_list_ct formats);
68 | akvcam_resolutions_list_t akvcam_format_resolutions(akvcam_formats_list_t formats,
69 | __u32 fourcc);
70 | akvcam_fps_list_t akvcam_format_frame_rates(akvcam_formats_list_ct formats,
71 | __u32 fourcc,
72 | size_t width,
73 | size_t height);
74 | akvcam_format_ct akvcam_format_from_v4l2_nr(akvcam_formats_list_ct formats,
75 | const struct v4l2_format *format);
76 | akvcam_format_t akvcam_format_from_v4l2(akvcam_formats_list_ct formats,
77 | const struct v4l2_format *format);
78 | bool akvcam_format_have_multiplanar(akvcam_formats_list_ct formats);
79 |
80 | #endif // AKVCAM_FORMAT_H
81 |
--------------------------------------------------------------------------------
/src/format_types.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_FORMAT_TYPES_H
20 | #define AKVCAM_FORMAT_TYPES_H
21 |
22 | #include "list_types.h"
23 |
24 | typedef akvcam_list_tt(struct v4l2_frmsize_discrete) akvcam_resolutions_list_t;
25 | typedef akvcam_list_ctt(struct v4l2_frmsize_discrete) akvcam_resolutions_list_ct;
26 | typedef akvcam_list_tt(struct v4l2_fract) akvcam_fps_list_t;
27 | typedef akvcam_list_ctt(struct v4l2_fract) akvcam_fps_list_ct;
28 | typedef akvcam_list_tt(__u32) akvcam_pixel_formats_list_t;
29 | typedef akvcam_list_ctt(__u32) akvcam_pixel_formats_list_ct;
30 |
31 | struct akvcam_format;
32 | typedef struct akvcam_format *akvcam_format_t;
33 | typedef const struct akvcam_format *akvcam_format_ct;
34 | typedef akvcam_list_tt(akvcam_formats_t) akvcam_formats_list_t;
35 | typedef akvcam_list_ctt(akvcam_formats_t) akvcam_formats_list_ct;
36 |
37 | #endif // AKVCAM_FORMAT_TYPES_H
38 |
--------------------------------------------------------------------------------
/src/frame.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_FRAME_H
20 | #define AKVCAM_FRAME_H
21 |
22 | #include
23 |
24 | #include "frame_types.h"
25 | #include "format_types.h"
26 |
27 | // public
28 | akvcam_frame_t akvcam_frame_new(akvcam_format_t format,
29 | const void *data,
30 | size_t size);
31 | akvcam_frame_t akvcam_frame_new_copy(akvcam_frame_ct other);
32 | void akvcam_frame_delete(akvcam_frame_t self);
33 | akvcam_frame_t akvcam_frame_ref(akvcam_frame_t self);
34 |
35 | void akvcam_frame_copy(akvcam_frame_t self, akvcam_frame_ct other);
36 | akvcam_format_t akvcam_frame_format(akvcam_frame_ct self);
37 | void *akvcam_frame_data(akvcam_frame_ct self);
38 | void *akvcam_frame_line(akvcam_frame_ct self, size_t plane, size_t y);
39 | const void *akvcam_frame_const_line(akvcam_frame_ct self,
40 | size_t plane,
41 | size_t y);
42 | void *akvcam_frame_plane_data(akvcam_frame_ct self, size_t plane);
43 | const void *akvcam_frame_plane_const_data(akvcam_frame_ct self, size_t plane);
44 | size_t akvcam_frame_size(akvcam_frame_ct self);
45 | void akvcam_frame_resize(akvcam_frame_t self, size_t size);
46 | void akvcam_frame_clear(akvcam_frame_t self);
47 | bool akvcam_frame_load(akvcam_frame_t self, const char *file_name);
48 | void akvcam_frame_mirror(akvcam_frame_t self,
49 | bool horizontalMirror,
50 | bool verticalMirror);
51 | bool akvcam_frame_scaled(akvcam_frame_t self,
52 | size_t width,
53 | size_t height,
54 | AKVCAM_SCALING mode,
55 | AKVCAM_ASPECT_RATIO aspectRatio);
56 | bool akvcam_frame_convert(akvcam_frame_t self, __u32 fourcc);
57 |
58 | // public static
59 | const char *akvcam_frame_scaling_to_string(AKVCAM_SCALING scaling);
60 | const char *akvcam_frame_aspect_ratio_to_string(AKVCAM_ASPECT_RATIO aspect_ratio);
61 | bool akvcam_frame_can_convert(__u32 in_fourcc, __u32 out_fourcc);
62 |
63 | #endif // AKVCAM_FRAME_H
64 |
--------------------------------------------------------------------------------
/src/frame_filter.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2021 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include "frame_filter.h"
25 | #include "frame.h"
26 | #include "format.h"
27 | #include "log.h"
28 | #include "utils.h"
29 |
30 | typedef struct
31 | {
32 | uint8_t b;
33 | uint8_t g;
34 | uint8_t r;
35 | } akvcam_RGB24, *akvcam_RGB24_t;
36 |
37 | struct akvcam_frame_filter
38 | {
39 | struct kref ref;
40 | uint8_t *contrast_table;
41 | uint8_t *gamma_table;
42 | };
43 |
44 | void akvcam_rgb_to_hsl(int r, int g, int b, int *h, int *s, int *l);
45 | void akvcam_hsl_to_rgb(int h, int s, int l, int *r, int *g, int *b);
46 | void akvcam_init_contrast_table(akvcam_frame_filter_t self);
47 | void akvcam_init_gamma_table(akvcam_frame_filter_t self);
48 | int akvcam_grayval(int r, int g, int b);
49 | bool akvcam_filter_format_supported(__u32 fourcc);
50 |
51 | akvcam_frame_filter_t akvcam_frame_filter_new(void)
52 | {
53 | akvcam_frame_filter_t self =
54 | kzalloc(sizeof(struct akvcam_frame_filter), GFP_KERNEL);
55 | kref_init(&self->ref);
56 | akvcam_init_contrast_table(self);
57 | akvcam_init_gamma_table(self);
58 |
59 | return self;
60 | }
61 |
62 | static void akvcam_frame_filter_free(struct kref *ref)
63 | {
64 | akvcam_frame_filter_t self =
65 | container_of(ref, struct akvcam_frame_filter, ref);
66 |
67 | if (self->gamma_table)
68 | vfree(self->gamma_table);
69 |
70 | if (self->contrast_table)
71 | vfree(self->contrast_table);
72 |
73 | kfree(self);
74 | }
75 |
76 | void akvcam_frame_filter_delete(akvcam_frame_filter_t self)
77 | {
78 | if (self)
79 | kref_put(&self->ref, akvcam_frame_filter_free);
80 | }
81 |
82 | akvcam_frame_filter_t akvcam_frame_filter_ref(akvcam_frame_filter_t self)
83 | {
84 | if (self)
85 | kref_get(&self->ref);
86 |
87 | return self;
88 | }
89 |
90 | void akvcam_frame_filter_swap_rgb(akvcam_frame_filter_ct self,
91 | akvcam_frame_t frame)
92 | {
93 | __u32 fourcc;
94 | size_t width;
95 | size_t height;
96 | size_t x;
97 | size_t y;
98 | akvcam_format_t format;
99 | UNUSED(self);
100 |
101 | akpr_function();
102 |
103 | format = akvcam_frame_format(frame);
104 | fourcc = akvcam_format_fourcc(format);
105 |
106 | if (!akvcam_filter_format_supported(fourcc)) {
107 | akvcam_format_delete(format);
108 |
109 | return;
110 | }
111 |
112 | width = akvcam_format_width(format);
113 | height = akvcam_format_height(format);
114 | akvcam_format_delete(format);
115 |
116 | for (y = 0; y < height; y++) {
117 | akvcam_RGB24_t line = akvcam_frame_line(frame, 0, y);
118 |
119 | for (x = 0; x < width; x++) {
120 | uint8_t tmp = line[x].r;
121 | line[x].r = line[x].b;
122 | line[x].b = tmp;
123 | }
124 | }
125 | }
126 |
127 | void akvcam_frame_filter_hsl(akvcam_frame_filter_ct self,
128 | akvcam_frame_t frame,
129 | int hue,
130 | int saturation,
131 | int luminance)
132 | {
133 | __u32 fourcc;
134 | size_t width;
135 | size_t height;
136 | size_t x;
137 | size_t y;
138 | int h;
139 | int s;
140 | int l;
141 | int r;
142 | int g;
143 | int b;
144 | akvcam_format_t format;
145 | UNUSED(self);
146 |
147 | akpr_function();
148 |
149 | if (hue == 0 && saturation == 0 && luminance == 0)
150 | return;
151 |
152 | format = akvcam_frame_format(frame);
153 | fourcc = akvcam_format_fourcc(format);
154 |
155 | if (!akvcam_filter_format_supported(fourcc)) {
156 | akvcam_format_delete(format);
157 |
158 | return;
159 | }
160 |
161 | width = akvcam_format_width(format);
162 | height = akvcam_format_height(format);
163 | akvcam_format_delete(format);
164 |
165 | for (y = 0; y < height; y++) {
166 | akvcam_RGB24_t line = akvcam_frame_line(frame, 0, y);
167 |
168 | for (x = 0; x < width; x++) {
169 | akvcam_rgb_to_hsl(line[x].r, line[x].g, line[x].b, &h, &s, &l);
170 |
171 | h = akvcam_mod(h + hue, 360);
172 | s = akvcam_bound(0, s + saturation, 255);
173 | l = akvcam_bound(0, l + luminance, 255);
174 |
175 | akvcam_hsl_to_rgb(h, s, l, &r, &g, &b);
176 |
177 | line[x].r = (uint8_t) r;
178 | line[x].g = (uint8_t) g;
179 | line[x].b = (uint8_t) b;
180 | }
181 | }
182 | }
183 |
184 | void akvcam_frame_filter_contrast(akvcam_frame_filter_ct self,
185 | akvcam_frame_t frame,
186 | int contrast)
187 | {
188 | __u32 fourcc;
189 | size_t width;
190 | size_t height;
191 | size_t x;
192 | size_t y;
193 | size_t contrast_offset;
194 | akvcam_format_t format;
195 |
196 | akpr_function();
197 |
198 | if (!self->contrast_table || contrast == 0)
199 | return;
200 |
201 | format = akvcam_frame_format(frame);
202 | fourcc = akvcam_format_fourcc(format);
203 |
204 | if (!akvcam_filter_format_supported(fourcc)) {
205 | akvcam_format_delete(format);
206 |
207 | return;
208 | }
209 |
210 | width = akvcam_format_width(format);
211 | height = akvcam_format_height(format);
212 | akvcam_format_delete(format);
213 | contrast = akvcam_bound(-255, contrast, 255);
214 | contrast_offset = (size_t) (contrast + 255) << 8;
215 |
216 | for (y = 0; y < height; y++) {
217 | akvcam_RGB24_t line = akvcam_frame_line(frame, 0, y);
218 |
219 | for (x = 0; x < width; x++) {
220 | line[x].r = self->contrast_table[contrast_offset | line[x].r];
221 | line[x].g = self->contrast_table[contrast_offset | line[x].g];
222 | line[x].b = self->contrast_table[contrast_offset | line[x].b];
223 | }
224 | }
225 | }
226 |
227 | void akvcam_frame_filter_gamma(akvcam_frame_filter_ct self,
228 | akvcam_frame_t frame,
229 | int gamma)
230 | {
231 | __u32 fourcc;
232 | size_t width;
233 | size_t height;
234 | size_t x;
235 | size_t y;
236 | size_t gamma_offset;
237 | akvcam_format_t format;
238 |
239 | akpr_function();
240 |
241 | if (!self->gamma_table || gamma == 0)
242 | return;
243 |
244 | format = akvcam_frame_format(frame);
245 | fourcc = akvcam_format_fourcc(format);
246 |
247 | if (!akvcam_filter_format_supported(fourcc)) {
248 | akvcam_format_delete(format);
249 |
250 | return;
251 | }
252 |
253 | width = akvcam_format_width(format);
254 | height = akvcam_format_height(format);
255 | akvcam_format_delete(format);
256 | gamma = akvcam_bound(-255, gamma, 255);
257 | gamma_offset = (size_t) (gamma + 255) << 8;
258 |
259 | for (y = 0; y < height; y++) {
260 | akvcam_RGB24_t line = akvcam_frame_line(frame, 0, y);
261 |
262 | for (x = 0; x < width; x++) {
263 | line[x].r = self->gamma_table[gamma_offset | line[x].r];
264 | line[x].g = self->gamma_table[gamma_offset | line[x].g];
265 | line[x].b = self->gamma_table[gamma_offset | line[x].b];
266 | }
267 | }
268 | }
269 |
270 | void akvcam_frame_filter_gray(akvcam_frame_filter_ct self,
271 | akvcam_frame_t frame)
272 | {
273 | __u32 fourcc;
274 | size_t width;
275 | size_t height;
276 | size_t x;
277 | size_t y;
278 | akvcam_format_t format;
279 | UNUSED(self);
280 |
281 | akpr_function();
282 | format = akvcam_frame_format(frame);
283 | fourcc = akvcam_format_fourcc(format);
284 |
285 | if (!akvcam_filter_format_supported(fourcc)) {
286 | akvcam_format_delete(format);
287 |
288 | return;
289 | }
290 |
291 | width = akvcam_format_width(format);
292 | height = akvcam_format_height(format);
293 | akvcam_format_delete(format);
294 |
295 | for (y = 0; y < height; y++) {
296 | akvcam_RGB24_t line = akvcam_frame_line(frame, 0, y);
297 |
298 | for (x = 0; x < width; x++) {
299 | int luma = akvcam_grayval(line[x].r, line[x].g, line[x].b);
300 |
301 | line[x].r = (uint8_t) luma;
302 | line[x].g = (uint8_t) luma;
303 | line[x].b = (uint8_t) luma;
304 | }
305 | }
306 | }
307 |
308 | void akvcam_frame_filter_apply(akvcam_frame_filter_ct self,
309 | akvcam_frame_t frame,
310 | int hue,
311 | int saturation,
312 | int luminance,
313 | int contrast,
314 | int gamma,
315 | bool gray,
316 | bool swap_rgb)
317 | {
318 | akpr_function();
319 |
320 | if (swap_rgb)
321 | akvcam_frame_filter_swap_rgb(self, frame);
322 |
323 | akvcam_frame_filter_hsl(self, frame, hue, saturation, luminance);
324 | akvcam_frame_filter_gamma(self, frame, gamma);
325 | akvcam_frame_filter_contrast(self, frame, contrast);
326 |
327 | if (gray)
328 | akvcam_frame_filter_gray(self, frame);
329 | }
330 |
331 | void akvcam_rgb_to_hsl(int r, int g, int b, int *h, int *s, int *l)
332 | {
333 | int max = akvcam_max(r, akvcam_max(g, b));
334 | int min = akvcam_min(r, akvcam_min(g, b));
335 | int c = max - min;
336 |
337 | *l = (max + min) / 2;
338 |
339 | if (!c) {
340 | *h = 0;
341 | *s = 0;
342 | } else {
343 | if (max == r)
344 | *h = akvcam_mod(g - b, 6 * c);
345 | else if (max == g)
346 | *h = b - r + 2 * c;
347 | else
348 | *h = r - g + 4 * c;
349 |
350 | *h = 60 * (*h) / c;
351 | *s = 255 * c / (255 - akvcam_abs(max + min - 255));
352 | }
353 | }
354 |
355 | void akvcam_hsl_to_rgb(int h, int s, int l, int *r, int *g, int *b)
356 | {
357 | int c = s * (255 - akvcam_abs(2 * l - 255)) / 255;
358 | int x = c * (60 - akvcam_abs((h % 120) - 60)) / 60;
359 | int m;
360 |
361 | if (h >= 0 && h < 60) {
362 | *r = c;
363 | *g = x;
364 | *b = 0;
365 | } else if (h >= 60 && h < 120) {
366 | *r = x;
367 | *g = c;
368 | *b = 0;
369 | } else if (h >= 120 && h < 180) {
370 | *r = 0;
371 | *g = c;
372 | *b = x;
373 | } else if (h >= 180 && h < 240) {
374 | *r = 0;
375 | *g = x;
376 | *b = c;
377 | } else if (h >= 240 && h < 300) {
378 | *r = x;
379 | *g = 0;
380 | *b = c;
381 | } else if (h >= 300 && h < 360) {
382 | *r = c;
383 | *g = 0;
384 | *b = x;
385 | } else {
386 | *r = 0;
387 | *g = 0;
388 | *b = 0;
389 | }
390 |
391 | m = 2 * l - c;
392 |
393 | *r = (2 * (*r) + m) / 2;
394 | *g = (2 * (*g) + m) / 2;
395 | *b = (2 * (*b) + m) / 2;
396 | }
397 |
398 | void akvcam_init_contrast_table(akvcam_frame_filter_t self)
399 | {
400 | static const int64_t min_contrast = -255;
401 | static const int64_t max_contrast = 255;
402 | static const int64_t max_color = 255;
403 | int64_t contrast;
404 |
405 | self->contrast_table = vmalloc((max_color + 1) * (max_contrast - min_contrast + 1));
406 |
407 | for (contrast = min_contrast; contrast <= max_contrast; contrast++) {
408 | uint64_t i;
409 | int64_t f_num = 259 * (255 + contrast);
410 | int64_t f_den = 255 * (259 - contrast);
411 | size_t offset = (size_t) (contrast + 255) << 8;
412 |
413 | for (i = 0; i <= max_color; i++) {
414 | int64_t ic = (f_num * ((ssize_t) i - 128) + 128 * f_den) / f_den;
415 | self->contrast_table[offset | i] = (uint8_t) akvcam_bound(0, ic, 255);
416 | }
417 | }
418 | }
419 |
420 | /* Gamma correction is traditionally computed with the following formula:
421 | *
422 | * c = N * (c / N) ^ gamma
423 | *
424 | * Where 'c' is the color component and 'N' is the maximum value of the color
425 | * component, 255 in this case. The formula will define a curve between 0 and
426 | * N. When 'gamma' is 1 it will draw a rect, returning the identity image at the
427 | * output. when 'gamma' is near to 0 it will draw a decreasing curve (mountain),
428 | * Giving more light to darker colors. When 'gamma' is higher than 1 it will
429 | * draw a increasing curve (valley), making bright colors darker.
430 | *
431 | * Explained in a simple way, gamma correction will modify image brightness
432 | * preserving the contrast.
433 | *
434 | * The problem with the original formula is that it requires floating point
435 | * computing which is not possible in the kernel because not all target
436 | * architectures have a FPU.
437 | *
438 | * So instead, we will use a quadric function, that even if it does not returns
439 | * the same values, it will cause the same effect and is good enough for our
440 | * purpose. We use the formula:
441 | *
442 | * y = a * x ^ 2 + b * x
443 | *
444 | * and because we have the point (0, N) already defined, then we can calculate
445 | * b as :
446 | *
447 | * b = 1 - a * N
448 | *
449 | * and replacing
450 | *
451 | * y = a * x ^ 2 + (1 - a * N) * x
452 | *
453 | * we are missing a third point (x', y') to fully define the value of 'a', so
454 | * the value of 'a' will be given by:
455 | *
456 | * a = (y' - x') / (x' ^ 2 - N * x')
457 | *
458 | * we will take the point (x', y') from the segment orthogonal to the curve's
459 | * segment, that is:
460 | *
461 | * y' = N - x'
462 | *
463 | * Here x' will be our fake 'gamma' value.
464 | * Then the value of 'a' becomes:
465 | *
466 | * a = (N - 2 * x') / (x' ^ 2 - N * x')
467 | *
468 | * finally we clamp/bound the resulting value between 0 and N and that's what
469 | * this code does.
470 | */
471 | void akvcam_init_gamma_table(akvcam_frame_filter_t self)
472 | {
473 | static const int64_t min_gamma = -255;
474 | static const int64_t max_gamma = 255;
475 | static const int64_t max_color = 255;
476 | int64_t gamma;
477 |
478 | self->gamma_table = vmalloc((max_color + 1) * (max_gamma - min_gamma + 1));
479 |
480 | for (gamma = min_gamma; gamma <= max_gamma; gamma++) {
481 | int64_t i;
482 | int64_t g = (255 + gamma) >> 1;
483 | int64_t f_num = 2 * g - 255;
484 | int64_t f_den = g * (g - 255);
485 | size_t offset = (size_t) (gamma + 255) << 8;
486 |
487 | for (i = 0; i <= max_color; i++) {
488 | int64_t ig;
489 |
490 | if (g > 0 && g != 255) {
491 | ig = (f_num * i * i + (f_den - f_num * 255) * i) / f_den;
492 | ig = akvcam_bound(0, ig, 255);
493 | } else if (g != 255) {
494 | ig = 0;
495 | } else {
496 | ig = 255;
497 | }
498 |
499 | self->gamma_table[offset | i] = (uint8_t) ig;
500 | }
501 | }
502 | }
503 |
504 | int akvcam_grayval(int r, int g, int b)
505 | {
506 | return (11 * r + 16 * g + 5 * b) >> 5;
507 | }
508 |
509 | bool akvcam_filter_format_supported(__u32 fourcc)
510 | {
511 | size_t i;
512 | static const __u32 filter_contrast_formats[] = {
513 | V4L2_PIX_FMT_BGR24,
514 | V4L2_PIX_FMT_RGB24,
515 | 0
516 | };
517 |
518 | for (i = 0; filter_contrast_formats[i]; i++)
519 | if (filter_contrast_formats[i] == fourcc)
520 | return true;
521 |
522 | return false;
523 | }
524 |
--------------------------------------------------------------------------------
/src/frame_filter.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2021 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_FRAME_FILTER_H
20 | #define AKVCAM_FRAME_FILTER_H
21 |
22 | #include
23 |
24 | #include "frame_filter_types.h"
25 | #include "frame_types.h"
26 |
27 | // public
28 | akvcam_frame_filter_t akvcam_frame_filter_new(void);
29 | void akvcam_frame_filter_delete(akvcam_frame_filter_t self);
30 | akvcam_frame_filter_t akvcam_frame_filter_ref(akvcam_frame_filter_t self);
31 |
32 | void akvcam_frame_filter_swap_rgb(akvcam_frame_filter_ct self,
33 | akvcam_frame_t frame);
34 | void akvcam_frame_filter_hsl(akvcam_frame_filter_ct self,
35 | akvcam_frame_t frame,
36 | int hue,
37 | int saturation,
38 | int luminance);
39 | void akvcam_frame_filter_contrast(akvcam_frame_filter_ct self,
40 | akvcam_frame_t frame,
41 | int contrast);
42 | void akvcam_frame_filter_gamma(akvcam_frame_filter_ct self,
43 | akvcam_frame_t frame,
44 | int gamma);
45 | void akvcam_frame_filter_gray(akvcam_frame_filter_ct self,
46 | akvcam_frame_t frame);
47 | void akvcam_frame_filter_apply(akvcam_frame_filter_ct self,
48 | akvcam_frame_t frame,
49 | int hue,
50 | int saturation,
51 | int luminance,
52 | int contrast,
53 | int gamma,
54 | bool gray,
55 | bool swap_rgb);
56 |
57 | #endif // AKVCAM_FRAME_FILTER_H
58 |
--------------------------------------------------------------------------------
/src/frame_filter_types.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2021 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_FRAME_FILTER_TYPES_H
20 | #define AKVCAM_FRAME_FILTER_TYPES_H
21 |
22 | struct akvcam_frame_filter;
23 | typedef struct akvcam_frame_filter *akvcam_frame_filter_t;
24 | typedef const struct akvcam_frame_filter *akvcam_frame_filter_ct;
25 |
26 | #endif // AKVCAM_FRAME_FILTER_TYPES_H
27 |
--------------------------------------------------------------------------------
/src/frame_types.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_FRAME_TYPES_H
20 | #define AKVCAM_FRAME_TYPES_H
21 |
22 | struct akvcam_frame;
23 | typedef struct akvcam_frame *akvcam_frame_t;
24 | typedef const struct akvcam_frame *akvcam_frame_ct;
25 |
26 | typedef enum
27 | {
28 | AKVCAM_SCALING_FAST,
29 | AKVCAM_SCALING_LINEAR
30 | } AKVCAM_SCALING;
31 |
32 | typedef enum
33 | {
34 | AKVCAM_ASPECT_RATIO_IGNORE,
35 | AKVCAM_ASPECT_RATIO_KEEP,
36 | AKVCAM_ASPECT_RATIO_EXPANDING
37 | } AKVCAM_ASPECT_RATIO;
38 |
39 | #endif // AKVCAM_FRAME_TYPES_H
40 |
--------------------------------------------------------------------------------
/src/ioctl.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_IOCTL_H
20 | #define AKVCAM_IOCTL_H
21 |
22 | const struct v4l2_ioctl_ops *akvcam_ioctl_ops(void);
23 |
24 | #endif // AKVCAM_IOCTL_H
25 |
--------------------------------------------------------------------------------
/src/list.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 |
22 | #include "list.h"
23 |
24 | typedef struct akvcam_list_element
25 | {
26 | void *data;
27 | akvcam_copy_t copier;
28 | akvcam_delete_t deleter;
29 | struct akvcam_list_element *prev;
30 | struct akvcam_list_element *next;
31 | } akvcam_list_element, *akvcam_list_element_t;
32 |
33 | struct akvcam_list
34 | {
35 | struct kref ref;
36 | size_t size;
37 | akvcam_list_element_t head;
38 | akvcam_list_element_t tail;
39 | };
40 |
41 | void akvcam_matrix_combine_p(akvcam_matrix_ct matrix,
42 | size_t index,
43 | akvcam_list_t combined,
44 | akvcam_matrix_t combinations);
45 |
46 | akvcam_list_t akvcam_list_new(void)
47 | {
48 | akvcam_list_t self = kzalloc(sizeof(struct akvcam_list), GFP_KERNEL);
49 | kref_init(&self->ref);
50 |
51 | return self;
52 | }
53 |
54 | akvcam_list_t akvcam_list_new_copy(akvcam_list_ct other)
55 | {
56 | akvcam_list_t self = kzalloc(sizeof(struct akvcam_list), GFP_KERNEL);
57 | kref_init(&self->ref);
58 | akvcam_list_append(self, other);
59 |
60 | return self;
61 | }
62 |
63 | static void akvcam_list_free(struct kref *ref)
64 | {
65 | akvcam_list_t self = container_of(ref, struct akvcam_list, ref);
66 | akvcam_list_clear(self);
67 | kfree(self);
68 | }
69 |
70 | void akvcam_list_delete(akvcam_list_t self)
71 | {
72 | if (self)
73 | kref_put(&self->ref, akvcam_list_free);
74 | }
75 |
76 | akvcam_list_t akvcam_list_ref(akvcam_list_t self)
77 | {
78 | if (self)
79 | kref_get(&self->ref);
80 |
81 | return self;
82 | }
83 |
84 | void akvcam_list_copy(akvcam_list_t self, akvcam_list_ct other)
85 | {
86 | akvcam_list_clear(self);
87 | akvcam_list_append(self, other);
88 | }
89 |
90 | void akvcam_list_append(akvcam_list_t self, akvcam_list_ct other)
91 | {
92 | akvcam_list_element_t it = NULL;
93 |
94 | for (;;) {
95 | void *data = akvcam_list_next(other, &it);
96 |
97 | if (!it)
98 | break;
99 |
100 | akvcam_list_push_back(self,
101 | data,
102 | it->copier,
103 | it->deleter);
104 | }
105 | }
106 |
107 | size_t akvcam_list_size(akvcam_list_ct self)
108 | {
109 | if (!self)
110 | return 0;
111 |
112 | return self->size;
113 | }
114 |
115 | bool akvcam_list_empty(akvcam_list_ct self)
116 | {
117 | if (!self)
118 | return true;
119 |
120 | return self->size < 1;
121 | }
122 |
123 | void *akvcam_list_at(akvcam_list_ct self, size_t i)
124 | {
125 | akvcam_list_element_t it = NULL;
126 | size_t j;
127 |
128 | for (j = 0;; j++) {
129 | void *element_data = akvcam_list_next(self, &it);
130 |
131 | if (!it)
132 | break;
133 |
134 | if (i == j)
135 | return element_data;
136 | }
137 |
138 | return NULL;
139 | }
140 |
141 | void *akvcam_list_front(akvcam_list_ct self)
142 | {
143 | if (!self || self->size < 1)
144 | return NULL;
145 |
146 | return self->head->data;
147 | }
148 |
149 | void *akvcam_list_back(akvcam_list_ct self)
150 | {
151 | if (!self || self->size < 1)
152 | return NULL;
153 |
154 | return self->tail->data;
155 | }
156 |
157 | akvcam_list_element_t akvcam_list_push_back(akvcam_list_t self,
158 | void *data,
159 | akvcam_copy_t copier,
160 | akvcam_delete_t deleter)
161 | {
162 | akvcam_list_element_t element;
163 |
164 | if (!self)
165 | return NULL;
166 |
167 | element = kzalloc(sizeof(struct akvcam_list_element), GFP_KERNEL);
168 |
169 | if (!element) {
170 | akvcam_set_last_error(-ENOMEM);
171 |
172 | return NULL;
173 | }
174 |
175 | element->data = copier? copier(data): data;
176 | element->copier = copier;
177 | element->deleter = deleter;
178 | element->prev = self->tail;
179 | self->size++;
180 |
181 | if (self->tail) {
182 | self->tail->next = element;
183 | self->tail = element;
184 | } else {
185 | self->head = element;
186 | self->tail = element;
187 | }
188 |
189 | akvcam_set_last_error(0);
190 |
191 | return element;
192 | }
193 |
194 | akvcam_list_element_t akvcam_list_it(akvcam_list_ct self, size_t i)
195 | {
196 | akvcam_list_element_t it = NULL;
197 | size_t j;
198 |
199 | for (j = 0;; j++) {
200 | akvcam_list_next(self, &it);
201 |
202 | if (!it)
203 | break;
204 |
205 | if (i == j)
206 | return it;
207 | }
208 |
209 | return NULL;
210 | }
211 |
212 | void akvcam_list_erase(akvcam_list_t self, akvcam_list_element_ct element)
213 | {
214 | akvcam_list_element_t it;
215 |
216 | if (!self)
217 | return;
218 |
219 | for (it = self->head; it != NULL; it = it->next)
220 | if (it == element) {
221 | if (it->data && it->deleter)
222 | it->deleter(it->data);
223 |
224 | if (it->prev)
225 | it->prev->next = it->next;
226 | else
227 | self->head = it->next;
228 |
229 | if (it->next)
230 | it->next->prev = it->prev;
231 | else
232 | self->tail = it->prev;
233 |
234 | kfree(it);
235 | self->size--;
236 |
237 | break;
238 | }
239 | }
240 |
241 | void akvcam_list_clear(akvcam_list_t self)
242 | {
243 | akvcam_list_element_t element;
244 | akvcam_list_element_t next;
245 |
246 | if (!self)
247 | return;
248 |
249 | element = self->head;
250 |
251 | while (element) {
252 | if (element->data && element->deleter)
253 | element->deleter(element->data);
254 |
255 | next = element->next;
256 | kfree(element);
257 | element = next;
258 | }
259 |
260 | self->size = 0;
261 | self->head = NULL;
262 | self->tail = NULL;
263 | }
264 |
265 | akvcam_list_element_t akvcam_list_find(akvcam_list_ct self,
266 | const void *data,
267 | akvcam_are_equals_t equals)
268 | {
269 | akvcam_list_element_t it = NULL;
270 |
271 | if (!equals)
272 | return NULL;
273 |
274 | for (;;) {
275 | void *element_data = akvcam_list_next(self, &it);
276 |
277 | if (!it)
278 | break;
279 |
280 | if (equals(element_data, data))
281 | return it;
282 | }
283 |
284 | return NULL;
285 | }
286 |
287 | ssize_t akvcam_list_index_of(akvcam_list_ct self,
288 | const void *data,
289 | akvcam_are_equals_t equals)
290 | {
291 | akvcam_list_element_t it = NULL;
292 | ssize_t i;
293 |
294 | if (!equals)
295 | return -1;
296 |
297 | for (i = 0;; i++) {
298 | void *element_data = akvcam_list_next(self, &it);
299 |
300 | if (!it)
301 | break;
302 |
303 | if (equals(element_data, data))
304 | return i;
305 | }
306 |
307 | return -1;
308 | }
309 |
310 | bool akvcam_list_contains(akvcam_list_ct self,
311 | const void *data,
312 | akvcam_are_equals_t equals)
313 | {
314 | return akvcam_list_find(self, data, equals) != NULL;
315 | }
316 |
317 | void *akvcam_list_next(akvcam_list_ct self,
318 | akvcam_list_element_t *element)
319 | {
320 | if (!element)
321 | return NULL;
322 |
323 | if (!self) {
324 | *element = NULL;
325 |
326 | return NULL;
327 | }
328 |
329 | if (*element) {
330 | *element = (*element)->next;
331 |
332 | return *element? (*element)->data: NULL;
333 | }
334 |
335 | *element = self->head;
336 |
337 | return self->head? self->head->data: NULL;
338 | }
339 |
340 | void *akvcam_list_element_data(akvcam_list_element_ct element)
341 | {
342 | if (!element)
343 | return NULL;
344 |
345 | return element->data;
346 | }
347 |
348 | akvcam_copy_t akvcam_list_element_copier(akvcam_list_element_ct element)
349 | {
350 | if (!element)
351 | return NULL;
352 |
353 | return element->copier;
354 | }
355 |
356 | akvcam_delete_t akvcam_list_element_deleter(akvcam_list_element_ct element)
357 | {
358 | if (!element)
359 | return NULL;
360 |
361 | return element->deleter;
362 | }
363 |
364 | akvcam_matrix_t akvcam_matrix_combine(akvcam_matrix_ct matrix)
365 | {
366 | akvcam_list_t combined = akvcam_list_new();
367 | akvcam_matrix_t combinations = akvcam_list_new();
368 | akvcam_matrix_combine_p(matrix, 0, combined, combinations);
369 | akvcam_list_delete(combined);
370 |
371 | return combinations;
372 | }
373 |
374 | /* A matrix is a list of lists where each element in the main list is a row,
375 | * and each element in a row is a column. We combine each element in a row with
376 | * each element in the next rows.
377 | */
378 | void akvcam_matrix_combine_p(akvcam_matrix_ct matrix,
379 | size_t index,
380 | akvcam_list_t combined,
381 | akvcam_matrix_t combinations)
382 | {
383 | akvcam_list_t row;
384 | akvcam_list_element_t it = NULL;
385 |
386 | if (index >= akvcam_list_size(matrix)) {
387 | akvcam_list_push_back(combinations,
388 | combined,
389 | (akvcam_copy_t) akvcam_list_ref,
390 | (akvcam_delete_t) akvcam_list_delete);
391 |
392 | return;
393 | }
394 |
395 | row = akvcam_list_at(matrix, index);
396 |
397 | for (;;) {
398 | akvcam_list_t combined_p1;
399 | void *data = akvcam_list_next(row, &it);
400 |
401 | if (!it)
402 | break;
403 |
404 | combined_p1 = akvcam_list_new_copy(combined);
405 | akvcam_list_push_back(combined_p1,
406 | data,
407 | it->copier,
408 | it->deleter);
409 | akvcam_matrix_combine_p(matrix,
410 | index + 1,
411 | combined_p1,
412 | combinations);
413 | akvcam_list_delete(combined_p1);
414 | }
415 | }
416 |
--------------------------------------------------------------------------------
/src/list.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_LIST_H
20 | #define AKVCAM_LIST_H
21 |
22 | #include
23 |
24 | #include "list_types.h"
25 | #include "utils.h"
26 |
27 | // public
28 | akvcam_list_t akvcam_list_new(void);
29 | akvcam_list_t akvcam_list_new_copy(akvcam_list_ct other);
30 | void akvcam_list_delete(akvcam_list_t self);
31 | akvcam_list_t akvcam_list_ref(akvcam_list_t self);
32 |
33 | void akvcam_list_copy(akvcam_list_t self, akvcam_list_ct other);
34 | void akvcam_list_append(akvcam_list_t self, akvcam_list_ct other);
35 | size_t akvcam_list_size(akvcam_list_ct self);
36 | bool akvcam_list_empty(akvcam_list_ct self);
37 | void *akvcam_list_at(akvcam_list_ct self, size_t i);
38 | void *akvcam_list_front(akvcam_list_ct self);
39 | void *akvcam_list_back(akvcam_list_ct self);
40 | akvcam_list_element_t akvcam_list_push_back(akvcam_list_t self,
41 | void *data,
42 | akvcam_copy_t copier,
43 | akvcam_delete_t deleter);
44 | akvcam_list_element_t akvcam_list_it(akvcam_list_ct self, size_t i);
45 | void akvcam_list_erase(akvcam_list_t self, akvcam_list_element_ct element);
46 | void akvcam_list_clear(akvcam_list_t self);
47 | akvcam_list_element_t akvcam_list_find(akvcam_list_ct self,
48 | const void *data,
49 | akvcam_are_equals_t equals);
50 | ssize_t akvcam_list_index_of(akvcam_list_ct self,
51 | const void *data,
52 | akvcam_are_equals_t equals);
53 | bool akvcam_list_contains(akvcam_list_ct self,
54 | const void *data,
55 | akvcam_are_equals_t equals);
56 | void *akvcam_list_next(akvcam_list_ct self,
57 | akvcam_list_element_t *element);
58 | void *akvcam_list_element_data(akvcam_list_element_ct element);
59 | akvcam_copy_t akvcam_list_element_copier(akvcam_list_element_ct element);
60 | akvcam_delete_t akvcam_list_element_deleter(akvcam_list_element_ct element);
61 | akvcam_matrix_t akvcam_matrix_combine(akvcam_matrix_ct matrix);
62 |
63 | #endif // AKVCAM_LIST_H
64 |
--------------------------------------------------------------------------------
/src/list_types.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_LIST_TYPES_H
20 | #define AKVCAM_LIST_TYPES_H
21 |
22 | #define akvcam_list_tt(type) akvcam_list_t
23 | #define akvcam_list_ctt(type) akvcam_list_ct
24 |
25 | struct akvcam_list;
26 | typedef struct akvcam_list *akvcam_list_t;
27 | typedef const struct akvcam_list *akvcam_list_ct;
28 | struct akvcam_list_element;
29 | typedef struct akvcam_list_element *akvcam_list_element_t;
30 | typedef const struct akvcam_list_element *akvcam_list_element_ct;
31 | typedef akvcam_list_tt(char *) akvcam_string_list_t;
32 | typedef akvcam_list_ctt(char *) akvcam_string_list_ct;
33 | typedef akvcam_list_tt(akvcam_list_t) akvcam_matrix_t;
34 | typedef akvcam_list_ctt(akvcam_list_t) akvcam_matrix_ct;
35 | typedef akvcam_list_tt(akvcam_string_list_t) akvcam_string_matrix_t;
36 | typedef akvcam_list_ctt(akvcam_string_list_t) akvcam_string_matrix_ct;
37 |
38 | #endif // AKVCAM_LIST_TYPES_H
39 |
--------------------------------------------------------------------------------
/src/log.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include "log.h"
20 |
21 | static struct akvcam_log
22 | {
23 | int level;
24 | } akvcam_log_private;
25 |
26 | int akvcam_log_level(void)
27 | {
28 | return akvcam_log_private.level;
29 | }
30 |
31 | void akvcam_log_set_level(int level)
32 | {
33 | akvcam_log_private.level = level;
34 | }
35 |
--------------------------------------------------------------------------------
/src/log.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_LOG_H
20 | #define AKVCAM_LOG_H
21 |
22 | #include
23 |
24 | #define akpr_file_name (strrchr(__FILE__, '/') + 1)
25 | #define akpr_log_format "[akvcam] %s(%d): "
26 |
27 | #define akpr_err(fmt, ...) \
28 | do { \
29 | if (akvcam_log_level() >= LOGLEVEL_ERR) { \
30 | printk(KERN_ERR akpr_log_format fmt, \
31 | akpr_file_name, __LINE__, ##__VA_ARGS__); \
32 | } \
33 | } while (false)
34 |
35 | #define akpr_warning(fmt, ...) \
36 | do { \
37 | if (akvcam_log_level() >= LOGLEVEL_WARNING) { \
38 | printk(KERN_WARNING akpr_log_format fmt, \
39 | akpr_file_name, __LINE__, ##__VA_ARGS__); \
40 | } \
41 | } while (false)
42 |
43 | #define akpr_info(fmt, ...) \
44 | do { \
45 | if (akvcam_log_level() >= LOGLEVEL_INFO) { \
46 | printk(KERN_INFO akpr_log_format fmt, \
47 | akpr_file_name, __LINE__, ##__VA_ARGS__); \
48 | } \
49 | } while (false)
50 |
51 | #define akpr_debug(fmt, ...) \
52 | do { \
53 | if (akvcam_log_level() >= LOGLEVEL_DEBUG) { \
54 | printk(KERN_DEBUG akpr_log_format fmt, \
55 | akpr_file_name, __LINE__, ##__VA_ARGS__); \
56 | } \
57 | } while (false)
58 |
59 | #define akpr_function() \
60 | akpr_debug("%s()\n", __FUNCTION__)
61 |
62 | int akvcam_log_level(void);
63 | void akvcam_log_set_level(int level);
64 |
65 | #endif // AKVCAM_LOG_H
66 |
--------------------------------------------------------------------------------
/src/map.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 |
22 | #include "map.h"
23 | #include "list.h"
24 |
25 | typedef struct akvcam_map_element
26 | {
27 | char *key;
28 | void *value;
29 | akvcam_copy_t copier;
30 | akvcam_delete_t deleter;
31 | akvcam_list_element_t it;
32 | } akvcam_map_element, *akvcam_map_element_t;
33 | typedef const akvcam_map_element *akvcam_map_element_ct;
34 |
35 | struct akvcam_map
36 | {
37 | struct kref ref;
38 | akvcam_list_tt(akvcam_map_element_t) elements;
39 | };
40 |
41 | akvcam_map_t akvcam_map_new(void)
42 | {
43 | akvcam_map_t self = kzalloc(sizeof(struct akvcam_map), GFP_KERNEL);
44 | kref_init(&self->ref);
45 | self->elements = akvcam_list_new();
46 |
47 | return self;
48 | }
49 |
50 | akvcam_map_t akvcam_map_new_copy(akvcam_map_ct other)
51 | {
52 | akvcam_map_t self = kzalloc(sizeof(struct akvcam_map), GFP_KERNEL);
53 | kref_init(&self->ref);
54 | self->elements = akvcam_list_new();
55 | akvcam_map_update(self, other);
56 |
57 | return self;
58 | }
59 |
60 | static void akvcam_map_free(struct kref *ref)
61 | {
62 | akvcam_map_t self = container_of(ref, struct akvcam_map, ref);
63 | akvcam_map_clear(self);
64 | akvcam_list_delete(self->elements);
65 | kfree(self);
66 | }
67 |
68 | void akvcam_map_delete(akvcam_map_t self)
69 | {
70 | if (self)
71 | kref_put(&self->ref, akvcam_map_free);
72 | }
73 |
74 | akvcam_map_t akvcam_map_ref(akvcam_map_t self)
75 | {
76 | if (self)
77 | kref_get(&self->ref);
78 |
79 | return self;
80 | }
81 |
82 | void akvcam_map_copy(akvcam_map_t self, const akvcam_map_t other)
83 | {
84 | akvcam_map_clear(self);
85 | akvcam_map_update(self, other);
86 | }
87 |
88 | void akvcam_map_update(akvcam_map_t self, akvcam_map_ct other)
89 | {
90 | akvcam_map_element_t it = NULL;
91 |
92 | while (akvcam_map_next(other, &it)) {
93 | akvcam_map_set_value(self,
94 | it->key,
95 | it->value,
96 | it->copier,
97 | it->deleter);
98 | }
99 | }
100 |
101 | size_t akvcam_map_size(akvcam_map_ct self)
102 | {
103 | return akvcam_list_size(self->elements);
104 | }
105 |
106 | bool akvcam_map_empty(akvcam_map_ct self)
107 | {
108 | return akvcam_list_empty(self->elements);
109 | }
110 |
111 | void *akvcam_map_value(akvcam_map_ct self, const char *key)
112 | {
113 | akvcam_map_element_t element = akvcam_map_it(self, key);
114 |
115 | if (!element)
116 | return NULL;
117 |
118 | return element->value;
119 | }
120 |
121 | static bool akvcam_map_equals_keys(akvcam_map_element_ct element,
122 | const char *key)
123 | {
124 | return strcmp(element->key, key) == 0;
125 | }
126 |
127 | static akvcam_map_element_t akvcam_map_element_copy(akvcam_map_element_ct element)
128 | {
129 | return kmemdup(element, sizeof(akvcam_map_element), GFP_KERNEL);
130 | }
131 |
132 | akvcam_map_element_t akvcam_map_set_value(akvcam_map_t self,
133 | const char *key,
134 | void *value,
135 | akvcam_copy_t copier,
136 | akvcam_delete_t deleter)
137 | {
138 | akvcam_map_element element;
139 | akvcam_list_element_t it =
140 | akvcam_list_find(self->elements,
141 | key,
142 | (akvcam_are_equals_t) akvcam_map_equals_keys);
143 |
144 | if (it)
145 | akvcam_list_erase(self->elements, it);
146 |
147 | element.key = akvcam_strdup(key, AKVCAM_MEMORY_TYPE_KMALLOC);
148 | element.value = copier? copier(value): value;
149 | element.copier = copier;
150 | element.deleter = deleter;
151 | element.it = akvcam_list_push_back(self->elements,
152 | &element,
153 | (akvcam_copy_t) akvcam_map_element_copy,
154 | (akvcam_delete_t) kfree);
155 |
156 | return akvcam_list_back(self->elements);
157 | }
158 |
159 | bool akvcam_map_contains(akvcam_map_ct self, const char *key)
160 | {
161 | return akvcam_map_value(self, key) != NULL;
162 | }
163 |
164 | static char *akvcam_map_key_copy(const char *str)
165 | {
166 | return kstrdup(str, GFP_KERNEL);
167 | }
168 |
169 | akvcam_list_t akvcam_map_keys(akvcam_map_ct self)
170 | {
171 | akvcam_list_element_t element = NULL;
172 | akvcam_list_t keys = akvcam_list_new();
173 |
174 | for (;;) {
175 | akvcam_map_element_t map_element =
176 | akvcam_list_next(self->elements, &element);
177 |
178 | if (!element)
179 | break;
180 |
181 | akvcam_list_push_back(keys,
182 | map_element->key,
183 | (akvcam_copy_t) akvcam_map_key_copy,
184 | (akvcam_delete_t) kfree);
185 | }
186 |
187 | return keys;
188 | }
189 |
190 | akvcam_list_t akvcam_map_values(akvcam_map_ct self)
191 | {
192 | akvcam_list_element_t element = NULL;
193 | akvcam_list_t values = akvcam_list_new();
194 |
195 | for (;;) {
196 | akvcam_map_element_t map_element =
197 | akvcam_list_next(self->elements, &element);
198 |
199 | if (!element)
200 | break;
201 |
202 | akvcam_list_push_back(values,
203 | map_element->value,
204 | map_element->copier,
205 | map_element->deleter);
206 | }
207 |
208 | return values;
209 | }
210 |
211 | akvcam_map_element_t akvcam_map_it(akvcam_map_ct self, const char *key)
212 | {
213 | akvcam_list_element_t element = NULL;
214 |
215 | for (;;) {
216 | akvcam_map_element_t map_element =
217 | akvcam_list_next(self->elements, &element);
218 |
219 | if (!element)
220 | break;
221 |
222 | if (strcmp(map_element->key, key) == 0)
223 | return map_element;
224 | }
225 |
226 | return NULL;
227 | }
228 |
229 | void akvcam_map_erase(akvcam_map_t self, akvcam_map_element_ct element)
230 | {
231 | if (element->key)
232 | kfree(element->key);
233 |
234 | if (element->value && element->deleter)
235 | element->deleter(element->value);
236 |
237 | akvcam_list_erase(self->elements, element->it);
238 | }
239 |
240 | void akvcam_map_clear(akvcam_map_t self)
241 | {
242 | akvcam_list_element_t it = NULL;
243 |
244 | for (;;) {
245 | akvcam_map_element_t element = akvcam_list_next(self->elements, &it);
246 |
247 | if (!it)
248 | break;
249 |
250 | if (element->key)
251 | kfree(element->key);
252 |
253 | if (element->value && element->deleter)
254 | element->deleter(element->value);
255 | }
256 |
257 | akvcam_list_clear(self->elements);
258 | }
259 |
260 | bool akvcam_map_next(akvcam_map_ct self, akvcam_map_element_t *element)
261 | {
262 | akvcam_list_element_t it = *element? (*element)->it: NULL;
263 | akvcam_map_element_t next = akvcam_list_next(self->elements, &it);
264 |
265 | if (!it)
266 | return false;
267 |
268 | *element = next;
269 |
270 | return true;
271 | }
272 |
273 | char *akvcam_map_element_key(akvcam_map_element_ct element)
274 | {
275 | return element->key;
276 | }
277 |
278 | void *akvcam_map_element_value(akvcam_map_element_ct element)
279 | {
280 | return element->value;
281 | }
282 |
283 | akvcam_copy_t akvcam_map_element_copier(akvcam_map_element_ct element)
284 | {
285 | return element->copier;
286 | }
287 |
288 | akvcam_delete_t akvcam_map_element_deleter(akvcam_map_element_ct element)
289 | {
290 | return element->deleter;
291 | }
292 |
--------------------------------------------------------------------------------
/src/map.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_MAP_H
20 | #define AKVCAM_MAP_H
21 |
22 | #include
23 |
24 | #include "list_types.h"
25 | #include "utils.h"
26 |
27 | #define akvcam_map_tt(value_type) akvcam_map_t
28 | #define akvcam_map_ctt(value_type) akvcam_map_ct
29 |
30 | struct akvcam_map;
31 | typedef struct akvcam_map *akvcam_map_t;
32 | typedef const struct akvcam_map *akvcam_map_ct;
33 | struct akvcam_map_element;
34 | typedef struct akvcam_map_element *akvcam_map_element_t;
35 | typedef const struct akvcam_map_element *akvcam_map_element_ct;
36 | typedef akvcam_map_tt(char *) akvcam_string_map_t;
37 | typedef akvcam_map_ctt(char *) akvcam_string_map_ct;
38 |
39 | // public
40 | akvcam_map_t akvcam_map_new(void);
41 | akvcam_map_t akvcam_map_new_copy(akvcam_map_ct other);
42 | void akvcam_map_delete(akvcam_map_t self);
43 | akvcam_map_t akvcam_map_ref(akvcam_map_t self);
44 |
45 | void akvcam_map_copy(akvcam_map_t self, const akvcam_map_t other);
46 | void akvcam_map_update(akvcam_map_t self, akvcam_map_ct other);
47 | size_t akvcam_map_size(akvcam_map_ct self);
48 | bool akvcam_map_empty(akvcam_map_ct self);
49 | void *akvcam_map_value(akvcam_map_ct self, const char *key);
50 | akvcam_map_element_t akvcam_map_set_value(akvcam_map_t self,
51 | const char *key,
52 | void *value,
53 | akvcam_copy_t copier,
54 | akvcam_delete_t deleter);
55 | bool akvcam_map_contains(akvcam_map_ct self, const char *key);
56 | akvcam_list_t akvcam_map_keys(akvcam_map_ct self);
57 | akvcam_list_t akvcam_map_values(akvcam_map_ct self);
58 | akvcam_map_element_t akvcam_map_it(akvcam_map_ct self, const char *key);
59 | void akvcam_map_erase(akvcam_map_t self, akvcam_map_element_ct element);
60 | void akvcam_map_clear(akvcam_map_t self);
61 | bool akvcam_map_next(akvcam_map_ct self, akvcam_map_element_t *element);
62 | char *akvcam_map_element_key(akvcam_map_element_ct element);
63 | void *akvcam_map_element_value(akvcam_map_element_ct element);
64 | akvcam_copy_t akvcam_map_element_copier(akvcam_map_element_ct element);
65 | akvcam_delete_t akvcam_map_element_deleter(akvcam_map_element_ct element);
66 |
67 | #endif // AKVCAM_MAP_H
68 |
--------------------------------------------------------------------------------
/src/module.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "driver.h"
24 | #include "log.h"
25 | #include "settings.h"
26 |
27 | #define AKVCAM_DRIVER_NAME "akvcam"
28 | #define AKVCAM_DRIVER_DESCRIPTION "AkVCam Virtual Camera"
29 |
30 | static int loglevel = 0;
31 | module_param(loglevel, int, S_IRUGO | S_IWUSR);
32 | MODULE_PARM_DESC(loglevel, "Debug verbosity (-2 to 7)");
33 |
34 | static char config_file[4096] = "/etc/akvcam/config.ini";
35 | module_param_string(config_file, config_file, 4096, S_IRUGO | S_IWUSR);
36 | MODULE_PARM_DESC(config_file, "Full path to virtual cameras config file");
37 |
38 | static int __init akvcam_init(void)
39 | {
40 | akvcam_log_set_level(loglevel);
41 | akvcam_settings_set_file(config_file);
42 |
43 | return akvcam_driver_init(AKVCAM_DRIVER_NAME, AKVCAM_DRIVER_DESCRIPTION);
44 | }
45 |
46 | static void __exit akvcam_uninit(void)
47 | {
48 | akvcam_driver_uninit();
49 | }
50 |
51 | module_init(akvcam_init)
52 | module_exit(akvcam_uninit)
53 |
54 | MODULE_LICENSE("GPL");
55 | MODULE_AUTHOR("Gonzalo Exequiel Pedone");
56 | MODULE_DESCRIPTION(AKVCAM_DRIVER_DESCRIPTION);
57 | MODULE_VERSION("1.2.6");
58 |
--------------------------------------------------------------------------------
/src/rbuffer.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include "rbuffer.h"
25 | #include "utils.h"
26 |
27 | struct akvcam_rbuffer
28 | {
29 | struct kref ref;
30 | char *data;
31 | size_t size;
32 | size_t data_size;
33 | size_t read;
34 | size_t write;
35 | size_t step;
36 | AKVCAM_MEMORY_TYPE memory_type;
37 | };
38 |
39 | void *akvcam_rbuffer_alloc_data(AKVCAM_MEMORY_TYPE memory_type, size_t size);
40 | void akvcam_rbuffer_free_data(AKVCAM_MEMORY_TYPE memory_type, void *data);
41 |
42 | akvcam_rbuffer_t akvcam_rbuffer_new(void)
43 | {
44 | akvcam_rbuffer_t self = kzalloc(sizeof(struct akvcam_rbuffer), GFP_KERNEL);
45 | kref_init(&self->ref);
46 | self->memory_type = AKVCAM_MEMORY_TYPE_KMALLOC;
47 |
48 | return self;
49 | }
50 |
51 | akvcam_rbuffer_t akvcam_rbuffer_new_copy(akvcam_rbuffer_ct other)
52 | {
53 | akvcam_rbuffer_t self = kzalloc(sizeof(struct akvcam_rbuffer), GFP_KERNEL);
54 | kref_init(&self->ref);
55 | self->data = kzalloc(other->size, GFP_KERNEL);
56 | memcpy(self->data, other->data, other->size);
57 | self->size = other->size;
58 | self->data_size = other->data_size;
59 | self->read = other->read;
60 | self->write = other->write;
61 | self->step = other->step;
62 | self->memory_type = other->memory_type;
63 |
64 | return self;
65 | }
66 |
67 | static void akvcam_rbuffer_free(struct kref *ref)
68 | {
69 | akvcam_rbuffer_t self = container_of(ref, struct akvcam_rbuffer, ref);
70 |
71 | if (self->data)
72 | akvcam_rbuffer_free_data(self->memory_type, self->data);
73 |
74 | kfree(self);
75 | }
76 |
77 | void akvcam_rbuffer_delete(akvcam_rbuffer_t self)
78 | {
79 | if (self)
80 | kref_put(&self->ref, akvcam_rbuffer_free);
81 | }
82 |
83 | akvcam_rbuffer_t akvcam_rbuffer_ref(akvcam_rbuffer_t self)
84 | {
85 | if (self)
86 | kref_get(&self->ref);
87 |
88 | return self;
89 | }
90 |
91 | void akvcam_rbuffer_copy(akvcam_rbuffer_t self, akvcam_rbuffer_ct other)
92 | {
93 | if (self->data)
94 | akvcam_rbuffer_free_data(self->memory_type, self->data);
95 |
96 | self->data = kzalloc(other->size, GFP_KERNEL);
97 | memcpy(self->data, other->data, other->size);
98 | self->size = other->size;
99 | self->data_size = other->data_size;
100 | self->read = other->read;
101 | self->write = other->write;
102 | self->step = other->step;
103 | }
104 |
105 | void akvcam_rbuffer_resize(akvcam_rbuffer_t self,
106 | size_t n_elements,
107 | size_t element_size,
108 | AKVCAM_MEMORY_TYPE memory_type)
109 | {
110 | char *new_data;
111 | size_t new_size = n_elements * element_size;
112 | size_t data_size = akvcam_min(self->data_size, new_size);
113 |
114 | if (new_size == self->size)
115 | return;
116 |
117 | if (new_size < 1) {
118 | if (self->data) {
119 | akvcam_rbuffer_free_data(self->memory_type, self->data);
120 | self->data = NULL;
121 | }
122 |
123 | self->size = 0;
124 | self->read = 0;
125 | self->write = 0;
126 | self->step = 0;
127 | self->memory_type = memory_type;
128 |
129 | return;
130 | }
131 |
132 | new_data = akvcam_rbuffer_alloc_data(memory_type, new_size);
133 |
134 | if (self->data) {
135 | size_t left_size = akvcam_min(self->size - self->read, data_size);
136 |
137 | if (left_size > 0)
138 | memcpy(new_data, self->data + self->read, left_size);
139 |
140 | if (data_size > left_size)
141 | memcpy(new_data + left_size, self->data, data_size - left_size);
142 |
143 | akvcam_rbuffer_free_data(self->memory_type, self->data);
144 | }
145 |
146 | self->data = new_data;
147 | self->size = new_size;
148 | self->data_size = data_size;
149 | self->step = element_size;
150 | self->read = 0;
151 | self->write = data_size % new_size;
152 | self->memory_type = memory_type;
153 | }
154 |
155 | size_t akvcam_rbuffer_size(akvcam_rbuffer_ct self)
156 | {
157 | return self->size;
158 | }
159 |
160 | size_t akvcam_rbuffer_data_size(akvcam_rbuffer_ct self)
161 | {
162 | return self->data_size;
163 | }
164 |
165 | size_t akvcam_rbuffer_n_elements(akvcam_rbuffer_ct self)
166 | {
167 | if (self->step < 1)
168 | return self->size;
169 |
170 | return self->size / self->step;
171 | }
172 |
173 | size_t akvcam_rbuffer_element_size(akvcam_rbuffer_ct self)
174 | {
175 | return self->step;
176 | }
177 |
178 | size_t akvcam_rbuffer_n_data(akvcam_rbuffer_ct self)
179 | {
180 | if (self->step < 1)
181 | return self->data_size;
182 |
183 | return self->data_size / self->step;
184 | }
185 |
186 | ssize_t akvcam_rbuffer_available_data_size(akvcam_rbuffer_ct self)
187 | {
188 | return self->size - self->data_size;
189 | }
190 |
191 | bool akvcam_rbuffer_data_empty(akvcam_rbuffer_ct self)
192 | {
193 | return self->data_size < 1;
194 | }
195 |
196 | bool akvcam_rbuffer_elements_empty(akvcam_rbuffer_ct self)
197 | {
198 | return self->data_size < self->step;
199 | }
200 |
201 | bool akvcam_rbuffer_data_full(akvcam_rbuffer_ct self)
202 | {
203 | return self->data_size >= self->size;
204 | }
205 |
206 | bool akvcam_rbuffer_elements_full(akvcam_rbuffer_ct self)
207 | {
208 | return (self->step + self->data_size) > self->size;
209 | }
210 |
211 | void *akvcam_rbuffer_queue(akvcam_rbuffer_t self, const void *data)
212 | {
213 | return akvcam_rbuffer_queue_bytes(self, data, self->step);
214 | }
215 |
216 | void *akvcam_rbuffer_queue_bytes(akvcam_rbuffer_t self,
217 | const void *data,
218 | size_t size)
219 | {
220 | void *output_data;
221 | bool move_read;
222 |
223 | if (self->size < 1)
224 | return NULL;
225 |
226 | size = akvcam_min(size, self->size);
227 | output_data = self->data + self->write;
228 |
229 | if (data) {
230 | size_t right_size = akvcam_min(self->size - self->write, size);
231 |
232 | if (right_size > 0)
233 | memcpy(output_data, data, right_size);
234 |
235 | if (size > right_size)
236 | memcpy(self->data,
237 | (const char *) data + right_size,
238 | size - right_size);
239 | }
240 |
241 | move_read =
242 | akvcam_between(self->write, self->read, self->write + size - 1)
243 | && self->data_size > 0;
244 | self->write = (self->write + size) % self->size;
245 | self->data_size = akvcam_min(self->data_size + size, self->size);
246 |
247 | if (move_read)
248 | self->read = self->write;
249 |
250 | return output_data;
251 | }
252 |
253 | void *akvcam_rbuffer_dequeue(akvcam_rbuffer_t self,
254 | void *data,
255 | bool keep)
256 | {
257 | size_t size = self->step;
258 |
259 | return akvcam_rbuffer_dequeue_bytes(self, data, &size, keep);
260 | }
261 |
262 | void *akvcam_rbuffer_dequeue_bytes(akvcam_rbuffer_t self,
263 | void *data,
264 | size_t *size,
265 | bool keep)
266 | {
267 | void *input_data;
268 |
269 | if (self->data_size < 1)
270 | return NULL;
271 |
272 | *size = akvcam_min(*size, self->data_size);
273 | input_data = self->data + self->read;
274 |
275 | if (data) {
276 | size_t left_size = akvcam_min(self->size - self->read, *size);
277 |
278 | if (left_size > 0)
279 | memcpy(data, input_data, left_size);
280 |
281 | if (*size > left_size)
282 | memcpy((char *) data + left_size,
283 | self->data,
284 | *size - left_size);
285 | }
286 |
287 | self->read = (self->read + *size) % self->size;
288 |
289 | if (!keep)
290 | self->data_size -= *size;
291 |
292 | return input_data;
293 | }
294 |
295 | void akvcam_rbuffer_clear(akvcam_rbuffer_t self)
296 | {
297 | self->data_size = 0;
298 | self->read = 0;
299 | self->write = 0;
300 | }
301 |
302 | void *akvcam_rbuffer_ptr_at(akvcam_rbuffer_ct self, size_t i)
303 | {
304 | size_t offset = i * self->step;
305 |
306 | if (!self->data || offset >= self->size)
307 | return NULL;
308 |
309 | offset = (self->read + offset) % self->size;
310 |
311 | return self->data + offset;
312 | }
313 |
314 | void *akvcam_rbuffer_ptr_front(akvcam_rbuffer_ct self)
315 | {
316 | if (!self->data || self->data_size < 1)
317 | return NULL;
318 |
319 | return self->data + self->read;
320 | }
321 |
322 | void *akvcam_rbuffer_ptr_back(akvcam_rbuffer_ct self)
323 | {
324 | size_t offset;
325 |
326 | if (!self->data || self->size < 1)
327 | return NULL;
328 |
329 | offset = (self->read + self->size - self->step) % self->size;
330 |
331 | return self->data + offset;
332 | }
333 |
334 | void *akvcam_rbuffer_find(akvcam_rbuffer_ct self,
335 | const void *data,
336 | akvcam_are_equals_t equals,
337 | ssize_t *offset)
338 | {
339 | size_t i;
340 |
341 | if (offset)
342 | *offset = 0;
343 |
344 | for (i = 0; i < self->data_size; i += self->step) {
345 | size_t ioffset = (self->read + i) % self->size;
346 |
347 | if (equals) {
348 | if (equals(self->data + ioffset, data))
349 | return self->data + ioffset;
350 | } else {
351 | if (self->data + ioffset == data)
352 | return self->data + ioffset;
353 | }
354 |
355 | if (offset)
356 | (*offset)++;
357 | }
358 |
359 | if (offset)
360 | *offset = -1;
361 |
362 | return NULL;
363 | }
364 |
365 | void *akvcam_rbuffer_alloc_data(AKVCAM_MEMORY_TYPE memory_type, size_t size)
366 | {
367 | if (memory_type == AKVCAM_MEMORY_TYPE_KMALLOC)
368 | return kzalloc(size, GFP_KERNEL);
369 |
370 | return vzalloc(size);
371 | }
372 |
373 | void akvcam_rbuffer_free_data(AKVCAM_MEMORY_TYPE memory_type, void *data)
374 | {
375 | if (memory_type == AKVCAM_MEMORY_TYPE_KMALLOC)
376 | kfree(data);
377 | else
378 | vfree(data);
379 | }
380 |
--------------------------------------------------------------------------------
/src/rbuffer.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_RBUFFER_H
20 | #define AKVCAM_RBUFFER_H
21 |
22 | #include
23 |
24 | #include "utils.h"
25 |
26 | #define akvcam_rbuffer_tt(type) akvcam_rbuffer_t
27 | #define akvcam_rbuffer_ctt(type) akvcam_rbuffer_ct
28 |
29 | struct akvcam_rbuffer;
30 | typedef struct akvcam_rbuffer *akvcam_rbuffer_t;
31 | typedef const struct akvcam_rbuffer *akvcam_rbuffer_ct;
32 |
33 | akvcam_rbuffer_t akvcam_rbuffer_new(void);
34 | akvcam_rbuffer_t akvcam_rbuffer_new_copy(akvcam_rbuffer_ct other);
35 | void akvcam_rbuffer_delete(akvcam_rbuffer_t self);
36 | akvcam_rbuffer_t akvcam_rbuffer_ref(akvcam_rbuffer_t self);
37 |
38 | void akvcam_rbuffer_copy(akvcam_rbuffer_t self, akvcam_rbuffer_ct other);
39 | void akvcam_rbuffer_resize(akvcam_rbuffer_t self,
40 | size_t n_elements,
41 | size_t element_size,
42 | AKVCAM_MEMORY_TYPE memory_type);
43 | size_t akvcam_rbuffer_size(akvcam_rbuffer_ct self);
44 | size_t akvcam_rbuffer_data_size(akvcam_rbuffer_ct self);
45 | size_t akvcam_rbuffer_n_elements(akvcam_rbuffer_ct self);
46 | size_t akvcam_rbuffer_element_size(akvcam_rbuffer_ct self);
47 | size_t akvcam_rbuffer_n_data(akvcam_rbuffer_ct self);
48 | ssize_t akvcam_rbuffer_available_data_size(akvcam_rbuffer_ct self);
49 | bool akvcam_rbuffer_data_empty(akvcam_rbuffer_ct self);
50 | bool akvcam_rbuffer_elements_empty(akvcam_rbuffer_ct self);
51 | bool akvcam_rbuffer_data_full(akvcam_rbuffer_ct self);
52 | bool akvcam_rbuffer_elements_full(akvcam_rbuffer_ct self);
53 | void *akvcam_rbuffer_queue(akvcam_rbuffer_t self, const void *data);
54 | void *akvcam_rbuffer_queue_bytes(akvcam_rbuffer_t self,
55 | const void *data,
56 | size_t size);
57 | void *akvcam_rbuffer_dequeue(akvcam_rbuffer_t self,
58 | void *data,
59 | bool keep);
60 | void *akvcam_rbuffer_dequeue_bytes(akvcam_rbuffer_t self,
61 | void *data,
62 | size_t *size,
63 | bool keep);
64 | void akvcam_rbuffer_clear(akvcam_rbuffer_t self);
65 | void *akvcam_rbuffer_ptr_at(akvcam_rbuffer_ct self, size_t i);
66 | void *akvcam_rbuffer_ptr_front(akvcam_rbuffer_ct self);
67 | void *akvcam_rbuffer_ptr_back(akvcam_rbuffer_ct self);
68 | void *akvcam_rbuffer_find(akvcam_rbuffer_ct self,
69 | const void *data,
70 | const akvcam_are_equals_t equals,
71 | ssize_t *offset);
72 |
73 | #endif // AKVCAM_RBUFFER_H
74 |
--------------------------------------------------------------------------------
/src/settings.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_SETTINGS_H
20 | #define AKVCAM_SETTINGS_H
21 |
22 | #include
23 |
24 | #include "list_types.h"
25 |
26 | struct akvcam_settings;
27 | typedef struct akvcam_settings *akvcam_settings_t;
28 | typedef const struct akvcam_settings *akvcam_settings_ct;
29 | struct v4l2_fract;
30 |
31 | // public
32 | akvcam_settings_t akvcam_settings_new(void);
33 | void akvcam_settings_delete(akvcam_settings_t self);
34 | akvcam_settings_t akvcam_settings_ref(akvcam_settings_t self);
35 |
36 | bool akvcam_settings_load(akvcam_settings_t self, const char *file_name);
37 | void akvcam_settings_begin_group(akvcam_settings_t self, const char *prefix);
38 | void akvcam_settings_end_group(akvcam_settings_t self);
39 | size_t akvcam_settings_begin_array(akvcam_settings_t self, const char *prefix);
40 | void akvcam_settings_set_array_index(akvcam_settings_t self, size_t i);
41 | void akvcam_settings_end_array(akvcam_settings_t self);
42 | akvcam_string_list_t akvcam_settings_groups(akvcam_settings_ct self);
43 | akvcam_string_list_t akvcam_settings_keys(akvcam_settings_ct self);
44 | void akvcam_settings_clear(akvcam_settings_t self);
45 | bool akvcam_settings_contains(akvcam_settings_ct self, const char *key);
46 | char *akvcam_settings_value(akvcam_settings_ct self, const char *key);
47 | bool akvcam_settings_value_bool(akvcam_settings_ct self, const char *key);
48 | int32_t akvcam_settings_value_int32(akvcam_settings_ct self,
49 | const char *key);
50 | uint32_t akvcam_settings_value_uint32(akvcam_settings_ct self,
51 | const char *key);
52 | akvcam_string_list_t akvcam_settings_value_list(akvcam_settings_ct self,
53 | const char *key,
54 | const char *separators);
55 | struct v4l2_fract akvcam_settings_value_frac(akvcam_settings_ct self,
56 | const char *key);
57 |
58 | // public static
59 | bool akvcam_settings_to_bool(const char *value);
60 | int32_t akvcam_settings_to_int32(const char *value);
61 | uint32_t akvcam_settings_to_uint32(const char *value);
62 | akvcam_string_list_t akvcam_settings_to_list(const char *value,
63 | const char *separators);
64 | struct v4l2_fract akvcam_settings_to_frac(const char *value);
65 | const char *akvcam_settings_file(void);
66 | void akvcam_settings_set_file(const char *file_name);
67 |
68 | #endif // AKVCAM_SETTINGS_H
69 |
--------------------------------------------------------------------------------
/src/utils.c:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #include "utils.h"
26 |
27 | static struct akvcam_utils
28 | {
29 | uint64_t id;
30 | int last_error;
31 | } akvcam_utils_private;
32 |
33 | typedef struct
34 | {
35 | __u32 cmd;
36 | char str[32];
37 | } akvcam_utils_ioctl_strings, *akvcam_utils_ioctl_strings_t;
38 |
39 | typedef struct
40 | {
41 | int error;
42 | char str[32];
43 | char description[AKVCAM_MAX_STRING_SIZE];
44 | } akvcam_utils_error_strings, *akvcam_utils_error_strings_t;
45 |
46 | typedef struct
47 | {
48 | enum v4l2_buf_type type;
49 | char str[AKVCAM_MAX_STRING_SIZE];
50 | } akvcam_utils_buf_type_strings, *akvcam_utils_buf_type_strings_t;
51 |
52 | typedef struct
53 | {
54 | enum v4l2_field field;
55 | char str[AKVCAM_MAX_STRING_SIZE];
56 | } akvcam_utils_field_strings, *akvcam_utils_field_strings_t;
57 |
58 | typedef struct
59 | {
60 | enum v4l2_frmsizetypes type;
61 | char str[AKVCAM_MAX_STRING_SIZE];
62 | } akvcam_utils_frmsize_type_strings, *akvcam_utils_frmsize_type_strings_t;
63 |
64 | typedef struct
65 | {
66 | __u32 pixelformat;
67 | char str[AKVCAM_MAX_STRING_SIZE];
68 | } akvcam_utils_pixelformat_strings, *akvcam_utils_pixelformat_strings_t;
69 |
70 | typedef struct
71 | {
72 | enum v4l2_memory memory;
73 | char str[AKVCAM_MAX_STRING_SIZE];
74 | } akvcam_utils_v4l2_memory_strings, *akvcam_utils_v4l2_memory_strings_t;
75 |
76 | typedef struct
77 | {
78 | enum v4l2_colorspace colorspace;
79 | char str[AKVCAM_MAX_STRING_SIZE];
80 | } akvcam_utils_v4l2_colorspace_strings, *akvcam_utils_v4l2_colorspace_strings_t;
81 |
82 | typedef struct
83 | {
84 | AKVCAM_RW_MODE rw_mode;
85 | char str[AKVCAM_MAX_STRING_SIZE];
86 | } akvcam_utils_rw_mode_strings, *akvcam_utils_rw_mode_strings_t;
87 |
88 | typedef struct
89 | {
90 | __u32 flag;
91 | char str[AKVCAM_MAX_STRING_SIZE];
92 | } akvcam_utils_buffer_flags_strings, *akvcam_utils_buffer_flags_strings_t;
93 |
94 | typedef struct
95 | {
96 | __u32 flag;
97 | char str[AKVCAM_MAX_STRING_SIZE];
98 | } akvcam_utils_buffer_capabilities_strings, *akvcam_utils_buffer_capabilities_strings_t;
99 |
100 | typedef struct
101 | {
102 | __s32 ctrl_which;
103 | char str[AKVCAM_MAX_STRING_SIZE];
104 | } akvcam_utils_ctrl_which_class_strings, *akvcam_utils_ctrl_which_class_strings_t;
105 |
106 | uint64_t akvcam_id(void)
107 | {
108 | return akvcam_utils_private.id++;
109 | }
110 |
111 | int akvcam_get_last_error(void)
112 | {
113 | return akvcam_utils_private.last_error;
114 | }
115 |
116 | int akvcam_set_last_error(int error)
117 | {
118 | akvcam_utils_private.last_error = error;
119 |
120 | return error;
121 | }
122 |
123 | void akvcam_string_from_error(int error, char *str, size_t len)
124 | {
125 | size_t i;
126 | static const akvcam_utils_error_strings error_strings[] = {
127 | {EPERM , "EPERM" , "Operation not permitted" },
128 | {ENOENT , "ENOENT" , "No such file or directory" },
129 | {ESRCH , "ESRCH" , "No such process" },
130 | {EINTR , "EINTR" , "Interrupted system call" },
131 | {EIO , "EIO" , "I/O error" },
132 | {ENXIO , "ENXIO" , "No such device or address" },
133 | {E2BIG , "E2BIG" , "Argument list too long" },
134 | {ENOEXEC, "ENOEXEC", "Exec format error" },
135 | {EBADF , "EBADF" , "Bad file number" },
136 | {ECHILD , "ECHILD" , "No child processes" },
137 | {EAGAIN , "EAGAIN" , "Try again" },
138 | {ENOMEM , "ENOMEM" , "Out of memory" },
139 | {EACCES , "EACCES" , "Permission denied" },
140 | {EFAULT , "EFAULT" , "Bad address" },
141 | {ENOTBLK, "ENOTBLK", "Block device required" },
142 | {EBUSY , "EBUSY" , "Device or resource busy" },
143 | {EEXIST , "EEXIST" , "File exists" },
144 | {EXDEV , "EXDEV" , "Cross-device link" },
145 | {ENODEV , "ENODEV" , "No such device" },
146 | {ENOTDIR, "ENOTDIR", "Not a directory" },
147 | {EISDIR , "EISDIR" , "Is a directory" },
148 | {EINVAL , "EINVAL" , "Invalid argument" },
149 | {ENFILE , "ENFILE" , "File table overflow" },
150 | {EMFILE , "EMFILE" , "Too many open files" },
151 | {ENOTTY , "ENOTTY" , "Not a typewriter" },
152 | {ETXTBSY, "ETXTBSY", "Text file busy" },
153 | {EFBIG , "EFBIG" , "File too large" },
154 | {ENOSPC , "ENOSPC" , "No space left on device" },
155 | {ESPIPE , "ESPIPE" , "Illegal seek" },
156 | {EROFS , "EROFS" , "Read-only file system " },
157 | {EMLINK , "EMLINK" , "Too many links" },
158 | {EPIPE , "EPIPE" , "Broken pipe" },
159 | {EDOM , "EDOM" , "Math argument out of domain of func"},
160 | {ERANGE , "ERANGE" , "Math result not representable" },
161 | {0 , "" , "" },
162 | };
163 |
164 | memset(str, 0, len);
165 |
166 | for (i = 0; akvcam_strlen(error_strings[i].str) > 0; i++)
167 | if (error_strings[i].error == -error) {
168 | snprintf(str,
169 | len,
170 | "%s (%s)",
171 | error_strings[i].description,
172 | error_strings[i].str);
173 |
174 | return;
175 | }
176 |
177 | snprintf(str, len, "Unknown error (%d)", error);
178 | }
179 |
180 | void akvcam_string_from_rw_mode(AKVCAM_RW_MODE rw_mode, char *str, size_t len)
181 | {
182 | size_t i = 0;
183 | size_t j = 0;
184 | size_t n;
185 | static const akvcam_utils_rw_mode_strings rw_mode_strings[] = {
186 | {AKVCAM_RW_MODE_READWRITE, "rw" },
187 | {AKVCAM_RW_MODE_MMAP , "mmap" },
188 | {AKVCAM_RW_MODE_USERPTR , "userptr"},
189 | {AKVCAM_RW_MODE_DMABUF , "dmabuf" },
190 | {0 , "" },
191 | };
192 |
193 | memset(str, 0, len);
194 | n = snprintf(str, len, "AKVCAM_RW_MODE(");
195 |
196 | for (i = 0; akvcam_strlen(rw_mode_strings[i].str) > 0; i++)
197 | if (rw_mode_strings[i].rw_mode & rw_mode) {
198 | if (j > 0)
199 | n += snprintf(str + n, len - n, ", ");
200 |
201 | n += snprintf(str + n, len - n, "%s", rw_mode_strings[i].str);
202 | j++;
203 | }
204 |
205 | snprintf(str + n, len - n, ")");
206 | }
207 |
208 | char *akvcam_strdup(const char *str, AKVCAM_MEMORY_TYPE type)
209 | {
210 | char *str_dup;
211 | size_t len = akvcam_strlen(str);
212 |
213 | if (type == AKVCAM_MEMORY_TYPE_KMALLOC)
214 | str_dup = kmalloc(len + 1, GFP_KERNEL);
215 | else
216 | str_dup = vmalloc(len + 1);
217 |
218 | str_dup[len] = 0;
219 |
220 | if (str)
221 | memcpy(str_dup, str, len + 1);
222 |
223 | return str_dup;
224 | }
225 |
226 | char *akvcam_strip_str(const char *str, AKVCAM_MEMORY_TYPE type)
227 | {
228 | if (!str)
229 | return NULL;
230 |
231 | return akvcam_strip_str_sub(str,
232 | 0,
233 | akvcam_strlen(str),
234 | type);
235 | }
236 |
237 | char *akvcam_strip_str_sub(const char *str,
238 | size_t from,
239 | size_t size,
240 | AKVCAM_MEMORY_TYPE type)
241 | {
242 | char *stripped_str;
243 | ssize_t i;
244 | size_t len;
245 | size_t left;
246 | size_t stripped_len;
247 |
248 | len = akvcam_min(akvcam_strlen(str), from + size);
249 |
250 | for (i = (ssize_t) from; i < (ssize_t) len; i++)
251 | if (!isspace(str[i]))
252 | break;
253 |
254 | left = (size_t) i;
255 |
256 | if (left == len) {
257 | stripped_len = 0;
258 | } else {
259 | size_t right;
260 |
261 | for (i = (ssize_t) len - 1; i >= (ssize_t) from; i--)
262 | if (!isspace(str[i]))
263 | break;
264 |
265 | right = (size_t) i;
266 | stripped_len = right - left + 1;
267 | }
268 |
269 | if (type == AKVCAM_MEMORY_TYPE_KMALLOC)
270 | stripped_str = kmalloc(stripped_len + 1, GFP_KERNEL);
271 | else
272 | stripped_str = vmalloc(stripped_len + 1);
273 |
274 | stripped_str[stripped_len] = 0;
275 |
276 | if (stripped_len > 0)
277 | memcpy(stripped_str, str + left, stripped_len);
278 |
279 | return stripped_str;
280 | }
281 |
282 | void akvcam_replace(char *str, char from, char to)
283 | {
284 | if (!str)
285 | return;
286 |
287 | for (; *str; str++)
288 | if (*str == from)
289 | *str = to;
290 | }
291 |
--------------------------------------------------------------------------------
/src/utils.h:
--------------------------------------------------------------------------------
1 | /* akvcam, virtual camera for Linux.
2 | * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 | *
4 | * This program is free software; you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation; either version 2 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 | */
18 |
19 | #ifndef AKVCAM_UTILS_H
20 | #define AKVCAM_UTILS_H
21 |
22 | #include
23 | #include
24 |
25 | #include "device_types.h"
26 |
27 | #define UNUSED(x) (void)(x)
28 | #define AKVCAM_MAX_STRING_SIZE 1024
29 |
30 | #define akvcam_min(value1, value2) \
31 | ((value1) < (value2)? (value1): (value2))
32 |
33 | #define akvcam_max(value1, value2) \
34 | ((value1) > (value2)? (value1): (value2))
35 |
36 | #define akvcam_abs(value) \
37 | ((value) < 0? -(value): (value))
38 |
39 | #define akvcam_between(min, value, max) \
40 | ((value) >= (min) && (value) <= (max))
41 |
42 | #define akvcam_bound(min, value, max) \
43 | ((value) < (min)? (min): (value) > (max)? (max): (value))
44 |
45 | #define akvcam_align_up(value, align) \
46 | (((value) + (align) - 1) & ~((align) - 1))
47 |
48 | #define akvcam_align32(value) akvcam_align_up(value, 32)
49 |
50 | #define akvcam_mod(value, mod) \
51 | (((value) % (mod) + (mod)) % (mod))
52 |
53 | #define akvcam_signal(class, signal, ...) \
54 | typedef int (*akvcam_##class##_##signal##_proc)(void *user_data, __VA_ARGS__); \
55 | \
56 | typedef struct \
57 | { \
58 | void *user_data; \
59 | akvcam_##class##_##signal##_proc callback; \
60 | } akvcam_##class##_##signal##_callback, *akvcam_##class##_##signal##_callback_t; \
61 | \
62 | void akvcam_##class##_set_##signal##_callback(akvcam_##class##_t self, \
63 | const akvcam_##class##_##signal##_callback callback)
64 |
65 | #define akvcam_signal_no_args(class, signal) \
66 | typedef int (*akvcam_##class##_##signal##_proc)(void *user_data); \
67 | \
68 | typedef struct \
69 | { \
70 | void *user_data; \
71 | akvcam_##class##_##signal##_proc callback; \
72 | } akvcam_##class##_##signal##_callback, *akvcam_##class##_##signal##_callback_t; \
73 | \
74 | void akvcam_##class##_set_##signal##_callback(akvcam_##class##_t self, \
75 | const akvcam_##class##_##signal##_callback callback)
76 |
77 | #define akvcam_signal_callback(class, signal) \
78 | akvcam_##class##_##signal##_callback signal##_callback
79 |
80 | #define akvcam_signal_define(class, signal) \
81 | void akvcam_##class##_set_##signal##_callback(akvcam_##class##_t self, \
82 | const akvcam_##class##_##signal##_callback callback) \
83 | { \
84 | self->signal##_callback = callback; \
85 | }
86 |
87 | #define akvcam_connect(class, sender, signal, receiver, method) \
88 | do { \
89 | akvcam_##class##_##signal##_callback signal_callback; \
90 | signal_callback.user_data = receiver; \
91 | signal_callback.callback = (akvcam_##class##_##signal##_proc) method; \
92 | akvcam_##class##_set_##signal##_callback(sender, signal_callback); \
93 | } while (false)
94 |
95 | #define akvcam_emit(self, signal, ...) \
96 | do { \
97 | if ((self)->signal##_callback.callback) \
98 | (self)->signal##_callback.callback(self->signal##_callback.user_data, \
99 | __VA_ARGS__); \
100 | } while (false)
101 |
102 | #define akvcam_emit_no_args(self, signal) \
103 | do { \
104 | if ((self)->signal##_callback.callback) \
105 | (self)->signal##_callback.callback(self->signal##_callback.user_data); \
106 | } while (false)
107 |
108 | #define akvcam_call(self, signal, ...) \
109 | ({ \
110 | int result = 0; \
111 | \
112 | if ((self)->signal##_callback.callback) \
113 | result = (self)->signal##_callback.callback(self->signal##_callback.user_data, \
114 | __VA_ARGS__); \
115 | \
116 | result; \
117 | })
118 |
119 | #define akvcam_call_no_args(self, signal) \
120 | ({ \
121 | int result = 0; \
122 | \
123 | if ((self)->signal##_callback.callback) \
124 | result = (self)->signal##_callback.callback(self->signal##_callback.user_data); \
125 | \
126 | result; \
127 | })
128 |
129 | #define akvcam_init_field(v4l2_struct, field) \
130 | memset((v4l2_struct)->field, 0, sizeof((v4l2_struct)->field))
131 |
132 | #define akvcam_init_reserved(v4l2_struct) \
133 | akvcam_init_field(v4l2_struct, reserved)
134 |
135 | #define akvcam_wait_condition(wait_queue, condition, mtx, msecs) \
136 | ({ \
137 | int result; \
138 | int mutex_result; \
139 | \
140 | mutex_unlock(mtx); \
141 | result = wait_event_interruptible_timeout(wait_queue, \
142 | condition, \
143 | msecs_to_jiffies(msecs)); \
144 | mutex_result = mutex_lock_interruptible(mtx); \
145 | \
146 | if (mutex_result) \
147 | result = mutex_result; \
148 | \
149 | result; \
150 | })
151 |
152 | #define akvcam_strlen(str) \
153 | ({ \
154 | size_t len = 0; \
155 | \
156 | if (str) \
157 | len = strnlen(str, AKVCAM_MAX_STRING_SIZE); \
158 | \
159 | len; \
160 | })
161 |
162 | typedef enum
163 | {
164 | AKVCAM_MEMORY_TYPE_KMALLOC,
165 | AKVCAM_MEMORY_TYPE_VMALLOC,
166 | } AKVCAM_MEMORY_TYPE;
167 |
168 | typedef bool (*akvcam_are_equals_t)(const void *element_data, const void *data);
169 | typedef void *(*akvcam_copy_t)(void *data);
170 | typedef void (*akvcam_delete_t)(void *data);
171 |
172 | uint64_t akvcam_id(void);
173 | int akvcam_get_last_error(void);
174 | int akvcam_set_last_error(int error);
175 | void akvcam_string_from_error(int error, char *str, size_t len);
176 | void akvcam_string_from_rw_mode(AKVCAM_RW_MODE rw_mode, char *str, size_t len);
177 | char *akvcam_strdup(const char *str, AKVCAM_MEMORY_TYPE type);
178 | char *akvcam_strip_str(const char *str, AKVCAM_MEMORY_TYPE type);
179 | char *akvcam_strip_str_sub(const char *str,
180 | size_t from,
181 | size_t size,
182 | AKVCAM_MEMORY_TYPE type);
183 | void akvcam_replace(char *str, char from, char to);
184 |
185 | #endif // AKVCAM_UTILS_H
186 |
--------------------------------------------------------------------------------