Code forked from Webcamoid's virtual camera.
This commit is contained in:
parent
b3e906789f
commit
673ce425f2
132 changed files with 25205 additions and 42 deletions
152
.gitignore
vendored
152
.gitignore
vendored
|
@ -1,52 +1,128 @@
|
||||||
# C++ objects and libs
|
# Compiled source #
|
||||||
*.slo
|
###################
|
||||||
*.lo
|
*.com
|
||||||
|
*.class
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
*.o
|
*.o
|
||||||
*.a
|
|
||||||
*.la
|
|
||||||
*.lai
|
|
||||||
*.so
|
*.so
|
||||||
*.so.*
|
*.so.*
|
||||||
*.dll
|
*.so.debug
|
||||||
*.dylib
|
*.run
|
||||||
|
*.AppImage
|
||||||
|
*.framework
|
||||||
|
|
||||||
# Qt-es
|
# Packages #
|
||||||
object_script.*.Release
|
############
|
||||||
object_script.*.Debug
|
*.7z
|
||||||
*_plugin_import.cpp
|
*.dmg
|
||||||
/.qmake.cache
|
*.gz
|
||||||
/.qmake.stash
|
*.iso
|
||||||
*.pro.user
|
*.jar
|
||||||
*.pro.user.*
|
*.rar
|
||||||
*.qbs.user
|
*.tar
|
||||||
*.qbs.user.*
|
*.zip
|
||||||
|
*.xz
|
||||||
|
|
||||||
|
# Logs and databases #
|
||||||
|
######################
|
||||||
|
*.log
|
||||||
|
*.sql
|
||||||
|
*.sqlite
|
||||||
|
vgcore.*
|
||||||
|
|
||||||
|
# OS generated files #
|
||||||
|
######################
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
Icon?
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
*~
|
||||||
|
*_resource.rc
|
||||||
|
|
||||||
|
# Ignore files generated by Qt #
|
||||||
|
################################
|
||||||
|
*.a
|
||||||
*.moc
|
*.moc
|
||||||
moc_*.cpp
|
moc_*.cpp
|
||||||
moc_*.h
|
|
||||||
qrc_*.cpp
|
|
||||||
ui_*.h
|
ui_*.h
|
||||||
*.qmlc
|
*.obj
|
||||||
*.jsc
|
*.dylib
|
||||||
Makefile*
|
Makefile*
|
||||||
*build-*
|
|
||||||
*.qm
|
|
||||||
*.prl
|
*.prl
|
||||||
|
*.app
|
||||||
# Qt unit tests
|
*.pro.user*
|
||||||
target_wrapper.*
|
*.qmlproject.user*
|
||||||
|
|
||||||
# QtCreator
|
|
||||||
*.autosave
|
*.autosave
|
||||||
|
*.qmlc
|
||||||
|
.qmake.stash
|
||||||
|
.qmake.cache
|
||||||
|
callgrind.out.*
|
||||||
|
*.debug
|
||||||
|
*.plugin
|
||||||
|
*_qmlcache.qrc
|
||||||
|
test.o-*
|
||||||
|
object_script.*
|
||||||
|
|
||||||
# QtCreator Qml
|
# Ignore files generated by Python #
|
||||||
*.qmlproject.user
|
####################################
|
||||||
*.qmlproject.user.*
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
|
||||||
# QtCreator CMake
|
# Android files #
|
||||||
CMakeLists.txt.user*
|
#################
|
||||||
|
android-build
|
||||||
|
android-*-deployment-settings.json
|
||||||
|
|
||||||
# QtCreator 4.8< compilation database
|
# VIM temporary files #
|
||||||
compile_commands.json
|
#######################
|
||||||
|
.*.swp
|
||||||
|
|
||||||
# QtCreator local machine specific files for imported projects
|
# Kate temporary files #
|
||||||
*creator.user*
|
#######################
|
||||||
|
.*.kate-swp
|
||||||
|
|
||||||
|
# KDevelop generated files #
|
||||||
|
############################
|
||||||
|
.kdev4
|
||||||
|
*.kdev4
|
||||||
|
|
||||||
|
# MinGW files #
|
||||||
|
###############
|
||||||
|
*.Debug
|
||||||
|
*.Release
|
||||||
|
|
||||||
|
# MSVC files #
|
||||||
|
##############
|
||||||
|
*.exp
|
||||||
|
*.ilk
|
||||||
|
*.lib
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Failed patch #
|
||||||
|
################
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
|
||||||
|
# Project Files #
|
||||||
|
#################
|
||||||
|
AkVCamAssistant
|
||||||
|
|
||||||
|
# Ignore Directories #
|
||||||
|
######################
|
||||||
|
build
|
||||||
|
debug
|
||||||
|
release
|
||||||
|
|
||||||
|
# Ignore Auto Generated Files #
|
||||||
|
###############################
|
||||||
|
*_auto*
|
||||||
|
|
||||||
|
# Ignore Private Files and Folders #
|
||||||
|
####################################
|
||||||
|
*_priv
|
||||||
|
*_priv.*
|
||||||
|
|
81
CONTRIBUTING.md
Normal file
81
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
# akvcam Individual Contributor License Agreement #
|
||||||
|
|
||||||
|
Thank you for your interest in contributing to akvcam ("We" or "Us").
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
You are accepting this agreement by making a pull request to the repository.
|
||||||
|
|
||||||
|
## 1. Definitions ##
|
||||||
|
|
||||||
|
"You" means the individual who Submits a Contribution to Us.
|
||||||
|
|
||||||
|
"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.
|
||||||
|
|
||||||
|
"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.
|
||||||
|
|
||||||
|
"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.
|
||||||
|
|
||||||
|
"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."
|
||||||
|
|
||||||
|
"Submission Date" means the date on which You Submit a Contribution to Us.
|
||||||
|
|
||||||
|
"Effective Date" means the date You execute this Agreement or the date You first Submit a Contribution to Us, whichever is earlier.
|
||||||
|
|
||||||
|
"Media" means any portion of a Contribution which is not software.
|
||||||
|
|
||||||
|
## 2. Grant of Rights ##
|
||||||
|
|
||||||
|
### 2.1 Copyright License ###
|
||||||
|
|
||||||
|
(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.
|
||||||
|
|
||||||
|
(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.
|
||||||
|
|
||||||
|
### 2.2 Patent License ###
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
### 2.3 Outbound License ###
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
**2.6 Reservation of Rights.** Any rights not expressly licensed under this section are expressly reserved by You.
|
||||||
|
|
||||||
|
## 3. Agreement ##
|
||||||
|
|
||||||
|
You confirm that:
|
||||||
|
|
||||||
|
(a) You have the legal authority to enter into this Agreement.
|
||||||
|
|
||||||
|
(b) You own the Copyright and patent claims covering the Contribution which are required to grant the rights under Section 2.
|
||||||
|
|
||||||
|
(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.
|
||||||
|
|
||||||
|
(d) You have followed the instructions in CONTRIBUTING.md, if You do not own the Copyright in the entire work of authorship Submitted.
|
||||||
|
|
||||||
|
## 4. Disclaimer ##
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## 5. Consequential Damage Waiver ##
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## 6. Miscellaneous ##
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
|
@ -1,7 +1,7 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
<https://www.gnu.org/licenses/>.
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
The GNU General Public License does not permit incorporating your program
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
may consider it more useful to permit linking proprietary applications with
|
may consider it more useful to permit linking proprietary applications with
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
Public License instead of this License. But first, please read
|
Public License instead of this License. But first, please read
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
58
ISSUE_TEMPLATE.md
Normal file
58
ISSUE_TEMPLATE.md
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
# README
|
||||||
|
|
||||||
|
Some considerations before doing anything:
|
||||||
|
|
||||||
|
* Search the [issues list](https://github.com/webcamoid/akvirtualcamera/issues) for similar topics before opening a new one.
|
||||||
|
* If you know how to fix the problem, consider doing a [pull request](https://github.com/webcamoid/akvirtualcamera/pulls) instead of opening a new issue.
|
||||||
|
* Only report problems in [latest](https://github.com/webcamoid/akvirtualcamera/releases) and [development](https://github.com/webcamoid/akvirtualcamera/) version. Reporting issues related to older versions will be rejected.
|
||||||
|
* Use [gist](https://gist.github.com/) to post logs longer than 1024 characters.
|
||||||
|
* akvirtualcamera as project, is not affiliated or endorsed to any distribution, report packaging problems in their respective issue tracker.
|
||||||
|
* Respect the templates, we need as much information as possible.
|
||||||
|
* Don't open an issue and disappear, we need you at least the first week to clear up missing information.
|
||||||
|
* Missing information makes useless and unsolvable an issue report.
|
||||||
|
* You are our debbuger, eyes and hands, if an issue is not reproducible then you will be the only person able to solve it.
|
||||||
|
* Take a seat and wait for your turn, as many others that has their issues open, or much better try fixing it your self and collaborate with the solution :smile:
|
||||||
|
|
||||||
|
Choose one of the templates bellow that fit better your issue.
|
||||||
|
|
||||||
|
# Reporting a problem?
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Write here a brief description of the problem.
|
||||||
|
|
||||||
|
## Current Behavior
|
||||||
|
|
||||||
|
Describe the problem the best as you can, don't omit information.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
How it should have work?
|
||||||
|
|
||||||
|
## Steps to Reproduce
|
||||||
|
|
||||||
|
If akvirtualcamera crashed, try to reproduce the crash several times to be sure where is the problem. Write the steps to reproduce the issue bellow:
|
||||||
|
|
||||||
|
1. Open this
|
||||||
|
2. Click that
|
||||||
|
3. Drag those
|
||||||
|
4. ...
|
||||||
|
|
||||||
|
## Suggestions and tips
|
||||||
|
|
||||||
|
How would you solve the problem?
|
||||||
|
|
||||||
|
## Your Environment
|
||||||
|
|
||||||
|
* akvirtualcamera inormation: (version) (architecture)
|
||||||
|
* Operating System information: (name) (numeric version and codename if applied) (architecture)
|
||||||
|
* Any other useful information: (logs, gdb backtrace, valgrind logs, screenshots, hardware, etc.)
|
||||||
|
|
||||||
|
# Want a new feature?
|
||||||
|
|
||||||
|
Describe your idea the best as you can, include sketches, mockups and diagrams if required.
|
||||||
|
Be patient, take in mind that there may be other priorities. Your idea will be accepted if fit in project goals.
|
||||||
|
|
||||||
|
# Questinons and other matters?
|
||||||
|
|
||||||
|
Go ahead!
|
80
Manager/Manager.pro
Normal file
80
Manager/Manager.pro
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../commons.pri) {
|
||||||
|
include(../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
win32: include(../dshow/dshow.pri)
|
||||||
|
macx: include(../cmio/cmio.pri)
|
||||||
|
include(../VCamUtils/VCamUtils.pri)
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console link_prl
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
TARGET = manager
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
main.cpp
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
.. \
|
||||||
|
../..
|
||||||
|
|
||||||
|
win32: LIBS += \
|
||||||
|
-L$${OUT_PWD}/../dshow/VCamIPC/$${BIN_DIR} -lVCamIPC \
|
||||||
|
-L$${OUT_PWD}/../dshow/PlatformUtils/$${BIN_DIR} -lPlatformUtils \
|
||||||
|
-ladvapi32 \
|
||||||
|
-lgdi32 \
|
||||||
|
-lstrmiids \
|
||||||
|
-luuid \
|
||||||
|
-lole32 \
|
||||||
|
-loleaut32 \
|
||||||
|
-lshell32
|
||||||
|
macx: LIBS += \
|
||||||
|
-L$${OUT_PWD}/../cmio/VCamIPC/$${BIN_DIR} -lVCamIPC \
|
||||||
|
-framework CoreFoundation \
|
||||||
|
-framework CoreMedia \
|
||||||
|
-framework CoreMediaIO \
|
||||||
|
-framework CoreVideo \
|
||||||
|
-framework Foundation \
|
||||||
|
-framework IOKit \
|
||||||
|
-framework IOSurface
|
||||||
|
LIBS += \
|
||||||
|
-L$${OUT_PWD}/VCamUtils/$${BIN_DIR} -lVCamUtils
|
||||||
|
|
||||||
|
isEmpty(STATIC_BUILD) | isEqual(STATIC_BUILD, 0) {
|
||||||
|
win32-g++: QMAKE_LFLAGS = -static -static-libgcc -static-libstdc++
|
||||||
|
}
|
||||||
|
|
||||||
|
win32: QMAKE_POST_LINK = \
|
||||||
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/../dshow/VirtualCamera/$${DSHOW_PLUGIN_NAME}.plugin/$$normalizedArch(TARGET_ARCH))) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/$${TARGET}.exe) $$shell_path($${OUT_PWD}/../dshow/VirtualCamera/$${DSHOW_PLUGIN_NAME}.plugin/$$normalizedArch(TARGET_ARCH))
|
||||||
|
macx: QMAKE_POST_LINK = \
|
||||||
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/../cmio/VirtualCamera/$${CMIO_PLUGIN_NAME}.plugin/Contents/Resources)) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/$${TARGET}) $$shell_path($${OUT_PWD}/../cmio/VirtualCamera/$${CMIO_PLUGIN_NAME}.plugin/Contents/Resources)
|
25
Manager/main.cpp
Normal file
25
Manager/main.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <VCamUtils/src/ipcbridge.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
35
PULL_REQUEST_TEMPLATE.md
Normal file
35
PULL_REQUEST_TEMPLATE.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# README
|
||||||
|
|
||||||
|
Before contributing, please read [the contributing document](https://github.com/webcamoid/akvirtualcamera/blob/master/CONTRIBUTING.md), and the [coding style and conventions](https://github.com/webcamoid/webcamoid/wiki/Coding-style-and-conventions) guide.
|
||||||
|
Search the [pull request list](https://github.com/webcamoid/akvirtualcamera/pulls) for similar pulls before opening a new one.
|
||||||
|
Check your code doesn't throw any warning or error message while compiling, and doesn't give any warning in Clang static analyzer. Make sure your code is GCC, Clang, MinGW and MSVC compliant (use AppVeyor and Travis for that).
|
||||||
|
Check your code using GDB, Valgrind and similar tools to remove all possible memory leaks and segfaults.
|
||||||
|
|
||||||
|
# Pull request
|
||||||
|
|
||||||
|
## Type of change
|
||||||
|
|
||||||
|
Is your pull request a bug fix, new feature, code refactor, breaking change, etc.?
|
||||||
|
If your change is too big consider [discussing it](https://github.com/webcamoid/akvirtualcamera/issues) before pulling.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Describe your pull request the best as you can.
|
||||||
|
|
||||||
|
## Related Issue
|
||||||
|
|
||||||
|
Is this pull request related to some [issue](https://github.com/webcamoid/akvirtualcamera/issues)? Cite the issue as #NNN, where NNN is the number of issue.
|
||||||
|
|
||||||
|
## More info
|
||||||
|
|
||||||
|
Provide screenshots, logs, etc. if required.
|
||||||
|
|
||||||
|
## Added dependencies
|
||||||
|
|
||||||
|
Does your pull request add more dependencies to the project? This may require some discussion. Minimal dependencies is a requirement.
|
||||||
|
|
||||||
|
## Target Environment
|
||||||
|
|
||||||
|
Is this pull request specific to a target operating system?
|
||||||
|
|
||||||
|
* Operating System information: (name) (numeric version and codename if applied) (architecture)
|
10
SECURITY.md
Normal file
10
SECURITY.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Only report vulnerabilities in the [latest stable](https://github.com/webcamoid/akvirtualcamera/releases) version and the [master repository](https://github.com/webcamoid/akvirtualcamera) (that includes [daily build](https://bintray.com/webcamoid/webcamoid/akvirtualcamera/daily/link)).
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Report all vulnerabilities at the [issues section](https://github.com/webcamoid/akvirtualcamera/issues).
|
||||||
|
|
24
VCamUtils/VCamUtils.pri
Normal file
24
VCamUtils/VCamUtils.pri
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
DEFINES += \
|
||||||
|
QT_NAMESPACE=AkVCam
|
||||||
|
|
||||||
|
CONFIG(debug, debug|release) {
|
||||||
|
DEFINES += QT_DEBUG
|
||||||
|
}
|
65
VCamUtils/VCamUtils.pro
Normal file
65
VCamUtils/VCamUtils.pro
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../commons.pri) {
|
||||||
|
include(../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include(VCamUtils.pri)
|
||||||
|
|
||||||
|
CONFIG += \
|
||||||
|
staticlib \
|
||||||
|
create_prl \
|
||||||
|
no_install_prl
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
TARGET = VCamUtils
|
||||||
|
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
src/fraction.cpp \
|
||||||
|
src/image/videoformat.cpp \
|
||||||
|
src/image/videoframe.cpp \
|
||||||
|
src/logger/logger.cpp \
|
||||||
|
src/timer.cpp \
|
||||||
|
src/utils.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
src/fraction.h \
|
||||||
|
src/image/color.h \
|
||||||
|
src/image/videoformat.h \
|
||||||
|
src/image/videoframe.h \
|
||||||
|
src/image/videoframetypes.h \
|
||||||
|
src/image/videoformattypes.h \
|
||||||
|
src/ipcbridge.h \
|
||||||
|
src/logger/logger.h \
|
||||||
|
src/timer.h \
|
||||||
|
src/utils.h
|
||||||
|
|
||||||
|
isEmpty(STATIC_BUILD) | isEqual(STATIC_BUILD, 0) {
|
||||||
|
win32-g++: QMAKE_LFLAGS = -static -static-libgcc -static-libstdc++
|
||||||
|
}
|
178
VCamUtils/src/fraction.cpp
Normal file
178
VCamUtils/src/fraction.cpp
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "fraction.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class FractionPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int64_t m_num;
|
||||||
|
int64_t m_den;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Fraction::Fraction()
|
||||||
|
{
|
||||||
|
this->d = new FractionPrivate;
|
||||||
|
this->d->m_num = 0;
|
||||||
|
this->d->m_den = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Fraction::Fraction(int64_t num, int64_t den)
|
||||||
|
{
|
||||||
|
this->d = new FractionPrivate;
|
||||||
|
this->d->m_num = num;
|
||||||
|
this->d->m_den = den;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Fraction::Fraction(const std::string &str)
|
||||||
|
{
|
||||||
|
this->d = new FractionPrivate;
|
||||||
|
this->d->m_num = 0;
|
||||||
|
this->d->m_den = 1;
|
||||||
|
auto pos = str.find('/');
|
||||||
|
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
auto strCpy = trimmed(str);
|
||||||
|
this->d->m_num = uint32_t(strtol(strCpy.c_str(), nullptr, 10));
|
||||||
|
} else {
|
||||||
|
auto numStr = trimmed(str.substr(0, pos));
|
||||||
|
auto denStr = trimmed(str.substr(pos + 1));
|
||||||
|
|
||||||
|
this->d->m_num = uint32_t(strtol(numStr.c_str(), nullptr, 10));
|
||||||
|
this->d->m_den = uint32_t(strtol(denStr.c_str(), nullptr, 10));
|
||||||
|
|
||||||
|
if (this->d->m_den < 1) {
|
||||||
|
this->d->m_num = 0;
|
||||||
|
this->d->m_den = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Fraction::Fraction(const std::wstring &str)
|
||||||
|
{
|
||||||
|
this->d = new FractionPrivate;
|
||||||
|
this->d->m_num = 0;
|
||||||
|
this->d->m_den = 1;
|
||||||
|
auto pos = str.find(L'/');
|
||||||
|
|
||||||
|
if (pos == std::wstring::npos) {
|
||||||
|
auto strCpy = trimmed(str);
|
||||||
|
|
||||||
|
this->d->m_num = uint32_t(wcstol(strCpy.c_str(), nullptr, 10));
|
||||||
|
} else {
|
||||||
|
auto numStr = trimmed(str.substr(0, pos));
|
||||||
|
auto denStr = trimmed(str.substr(pos + 1));
|
||||||
|
|
||||||
|
this->d->m_num = uint32_t(wcstol(numStr.c_str(), nullptr, 10));
|
||||||
|
this->d->m_den = uint32_t(wcstol(denStr.c_str(), nullptr, 10));
|
||||||
|
|
||||||
|
if (this->d->m_den < 1) {
|
||||||
|
this->d->m_num = 0;
|
||||||
|
this->d->m_den = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Fraction::Fraction(const Fraction &other)
|
||||||
|
{
|
||||||
|
this->d = new FractionPrivate;
|
||||||
|
this->d->m_num = other.d->m_num;
|
||||||
|
this->d->m_den = other.d->m_den;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Fraction::~Fraction()
|
||||||
|
{
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Fraction &AkVCam::Fraction::operator =(const Fraction &other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
this->d->m_num = other.d->m_num;
|
||||||
|
this->d->m_den = other.d->m_den;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::Fraction::operator ==(const Fraction &other) const
|
||||||
|
{
|
||||||
|
if (this->d->m_den == 0 && other.d->m_den != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this->d->m_den != 0 && other.d->m_den == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return this->d->m_num * other.d->m_den == this->d->m_den * other.d->m_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::Fraction::operator <(const Fraction &other) const
|
||||||
|
{
|
||||||
|
return this->d->m_num * other.d->m_den < this->d->m_den * other.d->m_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t AkVCam::Fraction::num() const
|
||||||
|
{
|
||||||
|
return this->d->m_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t &AkVCam::Fraction::num()
|
||||||
|
{
|
||||||
|
return this->d->m_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t AkVCam::Fraction::den() const
|
||||||
|
{
|
||||||
|
return this->d->m_den;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t &AkVCam::Fraction::den()
|
||||||
|
{
|
||||||
|
return this->d->m_den;
|
||||||
|
}
|
||||||
|
|
||||||
|
double AkVCam::Fraction::value() const
|
||||||
|
{
|
||||||
|
return double(this->d->m_num) / this->d->m_den;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::Fraction::toString() const
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << this->d->m_num << '/' << this->d->m_den;
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring AkVCam::Fraction::toWString() const
|
||||||
|
{
|
||||||
|
std::wstringstream ss;
|
||||||
|
ss << this->d->m_num << L'/' << this->d->m_den;
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
58
VCamUtils/src/fraction.h
Normal file
58
VCamUtils/src/fraction.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FRACTION_H
|
||||||
|
#define FRACTION_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class Fraction;
|
||||||
|
class FractionPrivate;
|
||||||
|
using FractionRange = std::pair<Fraction, Fraction>;
|
||||||
|
|
||||||
|
class Fraction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Fraction();
|
||||||
|
Fraction(int64_t num, int64_t den);
|
||||||
|
Fraction(const std::string &str);
|
||||||
|
Fraction(const std::wstring &str);
|
||||||
|
Fraction(const Fraction &other);
|
||||||
|
virtual ~Fraction();
|
||||||
|
Fraction &operator =(const Fraction &other);
|
||||||
|
bool operator ==(const Fraction &other) const;
|
||||||
|
bool operator <(const Fraction &other) const;
|
||||||
|
|
||||||
|
int64_t num() const;
|
||||||
|
int64_t &num();
|
||||||
|
int64_t den() const;
|
||||||
|
int64_t &den();
|
||||||
|
double value() const;
|
||||||
|
std::string toString() const;
|
||||||
|
std::wstring toWString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FractionPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FRACTION_H
|
56
VCamUtils/src/image/color.h
Normal file
56
VCamUtils/src/image/color.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AKVCAMUTILS_COLOR_H
|
||||||
|
#define AKVCAMUTILS_COLOR_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
namespace Color
|
||||||
|
{
|
||||||
|
inline uint32_t rgb(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
|
||||||
|
{
|
||||||
|
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t red(uint32_t rgba)
|
||||||
|
{
|
||||||
|
return (rgba >> 16) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t green(uint32_t rgba)
|
||||||
|
{
|
||||||
|
return (rgba >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t blue(uint32_t rgba)
|
||||||
|
{
|
||||||
|
return rgba & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t alpha(uint32_t rgba)
|
||||||
|
{
|
||||||
|
return rgba >> 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // AKVCAMUTILS_COLOR_H
|
430
VCamUtils/src/image/videoformat.cpp
Normal file
430
VCamUtils/src/image/videoformat.cpp
Normal file
|
@ -0,0 +1,430 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "videoformat.h"
|
||||||
|
#include "../utils.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class VideoFormatPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FourCC m_fourcc {0};
|
||||||
|
int m_width {0};
|
||||||
|
int m_height {0};
|
||||||
|
std::vector<Fraction> m_frameRates;
|
||||||
|
|
||||||
|
VideoFormatPrivate() = default;
|
||||||
|
VideoFormatPrivate(FourCC fourcc,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
const std::vector<Fraction> &frameRates);
|
||||||
|
};
|
||||||
|
|
||||||
|
using PlaneOffsetFunc = size_t (*)(size_t plane, size_t width, size_t height);
|
||||||
|
using ByplFunc = size_t (*)(size_t plane, size_t width);
|
||||||
|
|
||||||
|
class VideoFormatGlobals
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PixelFormat format;
|
||||||
|
size_t bpp;
|
||||||
|
size_t planes;
|
||||||
|
PlaneOffsetFunc planeOffset;
|
||||||
|
ByplFunc bypl;
|
||||||
|
std::string str;
|
||||||
|
|
||||||
|
inline static const std::vector<VideoFormatGlobals> &formats();
|
||||||
|
static inline const VideoFormatGlobals *byPixelFormat(PixelFormat pixelFormat);
|
||||||
|
static inline const VideoFormatGlobals *byStr(const std::string &str);
|
||||||
|
static size_t offsetNV(size_t plane, size_t width, size_t height);
|
||||||
|
static size_t byplNV(size_t plane, size_t width);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline T alignUp(const T &value, const T &align)
|
||||||
|
{
|
||||||
|
return (value + align - 1) & ~(align - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline T align32(const T &value)
|
||||||
|
{
|
||||||
|
return alignUp<T>(value, 32);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormat::VideoFormat()
|
||||||
|
{
|
||||||
|
this->d = new VideoFormatPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormat::VideoFormat(FourCC fourcc,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
const std::vector<Fraction> &frameRates)
|
||||||
|
{
|
||||||
|
this->d = new VideoFormatPrivate(fourcc, width, height, frameRates);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormat::VideoFormat(const VideoFormat &other)
|
||||||
|
{
|
||||||
|
this->d = new VideoFormatPrivate(other.d->m_fourcc,
|
||||||
|
other.d->m_width,
|
||||||
|
other.d->m_height,
|
||||||
|
other.d->m_frameRates);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormat::~VideoFormat()
|
||||||
|
{
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormat &AkVCam::VideoFormat::operator =(const VideoFormat &other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
this->d->m_fourcc = other.d->m_fourcc;
|
||||||
|
this->d->m_width = other.d->m_width;
|
||||||
|
this->d->m_height = other.d->m_height;
|
||||||
|
this->d->m_frameRates = other.d->m_frameRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::VideoFormat::operator ==(const AkVCam::VideoFormat &other) const
|
||||||
|
{
|
||||||
|
return this->d->m_fourcc == other.d->m_fourcc
|
||||||
|
&& this->d->m_width == other.d->m_width
|
||||||
|
&& this->d->m_height == other.d->m_height
|
||||||
|
&& this->d->m_frameRates == other.d->m_frameRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::VideoFormat::operator !=(const AkVCam::VideoFormat &other) const
|
||||||
|
{
|
||||||
|
return this->d->m_fourcc != other.d->m_fourcc
|
||||||
|
|| this->d->m_width != other.d->m_width
|
||||||
|
|| this->d->m_height != other.d->m_height
|
||||||
|
|| this->d->m_frameRates != other.d->m_frameRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormat::operator bool() const
|
||||||
|
{
|
||||||
|
return this->isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::FourCC AkVCam::VideoFormat::fourcc() const
|
||||||
|
{
|
||||||
|
return this->d->m_fourcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::FourCC &AkVCam::VideoFormat::fourcc()
|
||||||
|
{
|
||||||
|
return this->d->m_fourcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::VideoFormat::width() const
|
||||||
|
{
|
||||||
|
return this->d->m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int &AkVCam::VideoFormat::width()
|
||||||
|
{
|
||||||
|
return this->d->m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::VideoFormat::height() const
|
||||||
|
{
|
||||||
|
return this->d->m_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int &AkVCam::VideoFormat::height()
|
||||||
|
{
|
||||||
|
return this->d->m_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AkVCam::Fraction> AkVCam::VideoFormat::frameRates() const
|
||||||
|
{
|
||||||
|
return this->d->m_frameRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AkVCam::Fraction> &AkVCam::VideoFormat::frameRates()
|
||||||
|
{
|
||||||
|
return this->d->m_frameRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AkVCam::FractionRange> AkVCam::VideoFormat::frameRateRanges() const
|
||||||
|
{
|
||||||
|
std::vector<FractionRange> ranges;
|
||||||
|
|
||||||
|
if (!this->d->m_frameRates.empty()) {
|
||||||
|
auto min = *std::min_element(this->d->m_frameRates.begin(),
|
||||||
|
this->d->m_frameRates.end());
|
||||||
|
auto max = *std::max_element(this->d->m_frameRates.begin(),
|
||||||
|
this->d->m_frameRates.end());
|
||||||
|
ranges.emplace_back(FractionRange {min, max});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Fraction AkVCam::VideoFormat::minimumFrameRate() const
|
||||||
|
{
|
||||||
|
if (this->d->m_frameRates.empty())
|
||||||
|
return {0, 0};
|
||||||
|
|
||||||
|
return *std::min_element(this->d->m_frameRates.begin(),
|
||||||
|
this->d->m_frameRates.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::VideoFormat::bpp() const
|
||||||
|
{
|
||||||
|
auto vf = VideoFormatGlobals::byPixelFormat(PixelFormat(this->d->m_fourcc));
|
||||||
|
|
||||||
|
return vf? vf->bpp: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::VideoFormat::bypl(size_t plane) const
|
||||||
|
{
|
||||||
|
auto vf = VideoFormatGlobals::byPixelFormat(PixelFormat(this->d->m_fourcc));
|
||||||
|
|
||||||
|
if (!vf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (vf->bypl)
|
||||||
|
return vf->bypl(plane, size_t(this->d->m_width));
|
||||||
|
|
||||||
|
return VideoFormatGlobals::align32(size_t(this->d->m_width) * vf->bpp) / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::VideoFormat::size() const
|
||||||
|
{
|
||||||
|
auto vf = VideoFormatGlobals::byPixelFormat(PixelFormat(this->d->m_fourcc));
|
||||||
|
|
||||||
|
if (!vf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (vf->planeOffset)
|
||||||
|
return vf->planeOffset(vf->planes,
|
||||||
|
size_t(this->d->m_width),
|
||||||
|
size_t(this->d->m_height));
|
||||||
|
|
||||||
|
return size_t(this->d->m_height)
|
||||||
|
* VideoFormatGlobals::align32(size_t(this->d->m_width)
|
||||||
|
* vf->bpp) / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::VideoFormat::planes() const
|
||||||
|
{
|
||||||
|
auto vf = VideoFormatGlobals::byPixelFormat(PixelFormat(this->d->m_fourcc));
|
||||||
|
|
||||||
|
return vf? vf->planes: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::VideoFormat::offset(size_t plane) const
|
||||||
|
{
|
||||||
|
auto vf = VideoFormatGlobals::byPixelFormat(PixelFormat(this->d->m_fourcc));
|
||||||
|
|
||||||
|
if (!vf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (vf->planeOffset)
|
||||||
|
return vf->planeOffset(plane,
|
||||||
|
size_t(this->d->m_width),
|
||||||
|
size_t(this->d->m_height));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::VideoFormat::planeSize(size_t plane) const
|
||||||
|
{
|
||||||
|
return size_t(this->d->m_height) * this->bypl(plane);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::VideoFormat::isValid() const
|
||||||
|
{
|
||||||
|
if (this->size() <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this->d->m_frameRates.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto &fps: this->d->m_frameRates)
|
||||||
|
if (fps.num() < 1 || fps.den() < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::VideoFormat::clear()
|
||||||
|
{
|
||||||
|
this->d->m_fourcc = 0;
|
||||||
|
this->d->m_width = 0;
|
||||||
|
this->d->m_height = 0;
|
||||||
|
this->d->m_frameRates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormat AkVCam::VideoFormat::nearest(const std::vector<VideoFormat> &formats) const
|
||||||
|
{
|
||||||
|
VideoFormat nearestFormat;
|
||||||
|
auto q = std::numeric_limits<uint64_t>::max();
|
||||||
|
auto svf = VideoFormatGlobals::byPixelFormat(PixelFormat(this->d->m_fourcc));
|
||||||
|
|
||||||
|
for (auto &format: formats) {
|
||||||
|
auto vf = VideoFormatGlobals::byPixelFormat(PixelFormat(format.d->m_fourcc));
|
||||||
|
uint64_t diffFourcc = format.d->m_fourcc == this->d->m_fourcc? 0: 1;
|
||||||
|
auto diffWidth = format.d->m_width - this->d->m_width;
|
||||||
|
auto diffHeight = format.d->m_height - this->d->m_height;
|
||||||
|
auto diffBpp = vf->bpp - svf->bpp;
|
||||||
|
auto diffPlanes = vf->planes - svf->planes;
|
||||||
|
|
||||||
|
uint64_t k = diffFourcc
|
||||||
|
+ uint64_t(diffWidth * diffWidth)
|
||||||
|
+ uint64_t(diffHeight * diffHeight)
|
||||||
|
+ diffBpp * diffBpp
|
||||||
|
+ diffPlanes * diffPlanes;
|
||||||
|
|
||||||
|
if (k < q) {
|
||||||
|
nearestFormat = format;
|
||||||
|
q = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nearestFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::VideoFormat::roundNearest(int width, int height,
|
||||||
|
int *owidth, int *oheight,
|
||||||
|
int align)
|
||||||
|
{
|
||||||
|
/* Explanation:
|
||||||
|
*
|
||||||
|
* When 'align' is a power of 2, the left most bit will be 1 (the pivot),
|
||||||
|
* while all other bits be 0, if destination width is multiple of 'align'
|
||||||
|
* all bits after pivot position will be 0, then we create a mask
|
||||||
|
* substracting 1 to the align, so all bits after pivot position in the
|
||||||
|
* mask will 1.
|
||||||
|
* Then we negate all bits in the mask so all bits from pivot to the left
|
||||||
|
* will be 1, and then we use that mask to get a width multiple of align.
|
||||||
|
* This give us the lower (floor) width nearest to the original 'width' and
|
||||||
|
* multiple of align. To get the rounded nearest value we add align / 2 to
|
||||||
|
* 'width'.
|
||||||
|
* This is the equivalent of:
|
||||||
|
*
|
||||||
|
* align * round(width / align)
|
||||||
|
*/
|
||||||
|
*owidth = (width + (align >> 1)) & ~(align - 1);
|
||||||
|
|
||||||
|
/* Find the nearest width:
|
||||||
|
*
|
||||||
|
* round(height * owidth / width)
|
||||||
|
*/
|
||||||
|
*oheight = (2 * height * *owidth + width) / (2 * width);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::FourCC AkVCam::VideoFormat::fourccFromString(const std::string &fourccStr)
|
||||||
|
{
|
||||||
|
auto vf = VideoFormatGlobals::byStr(fourccStr);
|
||||||
|
|
||||||
|
return vf? vf->format: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::VideoFormat::stringFromFourcc(AkVCam::FourCC fourcc)
|
||||||
|
{
|
||||||
|
auto vf = VideoFormatGlobals::byPixelFormat(PixelFormat(fourcc));
|
||||||
|
|
||||||
|
return vf? vf->str: std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring AkVCam::VideoFormat::wstringFromFourcc(AkVCam::FourCC fourcc)
|
||||||
|
{
|
||||||
|
auto str = stringFromFourcc(fourcc);
|
||||||
|
|
||||||
|
return std::wstring(str.begin(), str.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormatPrivate::VideoFormatPrivate(FourCC fourcc,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
const std::vector<Fraction> &frameRates):
|
||||||
|
m_fourcc(fourcc),
|
||||||
|
m_width(width),
|
||||||
|
m_height(height),
|
||||||
|
m_frameRates(frameRates)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<AkVCam::VideoFormatGlobals> &AkVCam::VideoFormatGlobals::formats()
|
||||||
|
{
|
||||||
|
static const std::vector<VideoFormatGlobals> formats {
|
||||||
|
{PixelFormatRGB32, 32, 1, nullptr, nullptr, "RGB32"},
|
||||||
|
{PixelFormatRGB24, 24, 1, nullptr, nullptr, "RGB24"},
|
||||||
|
{PixelFormatRGB16, 16, 1, nullptr, nullptr, "RGB16"},
|
||||||
|
{PixelFormatRGB15, 16, 1, nullptr, nullptr, "RGB15"},
|
||||||
|
{PixelFormatBGR32, 32, 1, nullptr, nullptr, "BGR32"},
|
||||||
|
{PixelFormatBGR24, 24, 1, nullptr, nullptr, "BGR24"},
|
||||||
|
{PixelFormatBGR16, 16, 1, nullptr, nullptr, "BGR16"},
|
||||||
|
{PixelFormatBGR15, 16, 1, nullptr, nullptr, "BGR15"},
|
||||||
|
{PixelFormatUYVY , 16, 1, nullptr, nullptr, "UYVY"},
|
||||||
|
{PixelFormatYUY2 , 16, 1, nullptr, nullptr, "YUY2"},
|
||||||
|
{PixelFormatNV12 , 12, 2, offsetNV, byplNV, "NV12"},
|
||||||
|
{PixelFormatNV21 , 12, 2, offsetNV, byplNV, "NV21"}
|
||||||
|
};
|
||||||
|
|
||||||
|
return formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AkVCam::VideoFormatGlobals *AkVCam::VideoFormatGlobals::byPixelFormat(PixelFormat pixelFormat)
|
||||||
|
{
|
||||||
|
for (auto &format: formats())
|
||||||
|
if (format.format == pixelFormat)
|
||||||
|
return &format;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AkVCam::VideoFormatGlobals *AkVCam::VideoFormatGlobals::byStr(const std::string &str)
|
||||||
|
{
|
||||||
|
for (auto &format: formats())
|
||||||
|
if (format.str == str)
|
||||||
|
return &format;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::VideoFormatGlobals::offsetNV(size_t plane, size_t width, size_t height)
|
||||||
|
{
|
||||||
|
size_t offset[] = {
|
||||||
|
0,
|
||||||
|
align32(size_t(width)) * height,
|
||||||
|
5 * align32(size_t(width)) * height / 4
|
||||||
|
};
|
||||||
|
|
||||||
|
return offset[plane];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::VideoFormatGlobals::byplNV(size_t plane, size_t width)
|
||||||
|
{
|
||||||
|
UNUSED(plane)
|
||||||
|
|
||||||
|
return align32(size_t(width));
|
||||||
|
}
|
80
VCamUtils/src/image/videoformat.h
Normal file
80
VCamUtils/src/image/videoformat.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AKVCAMUTILS_VIDEOFORMAT_H
|
||||||
|
#define AKVCAMUTILS_VIDEOFORMAT_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "videoformattypes.h"
|
||||||
|
#include "../fraction.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class VideoFormatPrivate;
|
||||||
|
|
||||||
|
class VideoFormat
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VideoFormat();
|
||||||
|
VideoFormat(FourCC fourcc,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
const std::vector<Fraction> &frameRates={});
|
||||||
|
VideoFormat(const VideoFormat &other);
|
||||||
|
~VideoFormat();
|
||||||
|
VideoFormat &operator =(const VideoFormat &other);
|
||||||
|
bool operator ==(const VideoFormat &other) const;
|
||||||
|
bool operator !=(const VideoFormat &other) const;
|
||||||
|
operator bool() const;
|
||||||
|
|
||||||
|
FourCC fourcc() const;
|
||||||
|
FourCC &fourcc();
|
||||||
|
int width() const;
|
||||||
|
int &width();
|
||||||
|
int height() const;
|
||||||
|
int &height();
|
||||||
|
std::vector<Fraction> frameRates() const;
|
||||||
|
std::vector<Fraction> &frameRates();
|
||||||
|
std::vector<FractionRange> frameRateRanges() const;
|
||||||
|
Fraction minimumFrameRate() const;
|
||||||
|
size_t bpp() const;
|
||||||
|
size_t bypl(size_t plane) const;
|
||||||
|
size_t size() const;
|
||||||
|
size_t planes() const;
|
||||||
|
size_t offset(size_t plane) const;
|
||||||
|
size_t planeSize(size_t plane) const;
|
||||||
|
bool isValid() const;
|
||||||
|
void clear();
|
||||||
|
VideoFormat nearest(const std::vector<VideoFormat> &formats) const;
|
||||||
|
|
||||||
|
static void roundNearest(int width, int height,
|
||||||
|
int *owidth, int *oheight,
|
||||||
|
int align=32);
|
||||||
|
static FourCC fourccFromString(const std::string &fourccStr);
|
||||||
|
static std::string stringFromFourcc(FourCC fourcc);
|
||||||
|
static std::wstring wstringFromFourcc(FourCC fourcc);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VideoFormatPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // AKVCAMUTILS_VIDEOFORMAT_H
|
59
VCamUtils/src/image/videoformattypes.h
Normal file
59
VCamUtils/src/image/videoformattypes.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VIDEOFORMATTYPES_H
|
||||||
|
#define VIDEOFORMATTYPES_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#define MKFOURCC(a, b, c, d) \
|
||||||
|
(((uint32_t(a) & 0xff) << 24) \
|
||||||
|
| ((uint32_t(b) & 0xff) << 16) \
|
||||||
|
| ((uint32_t(c) & 0xff) << 8) \
|
||||||
|
| (uint32_t(d) & 0xff))
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
using FourCC = uint32_t;
|
||||||
|
|
||||||
|
enum PixelFormat
|
||||||
|
{
|
||||||
|
// RGB formats
|
||||||
|
PixelFormatRGB32 = MKFOURCC('R', 'G', 'B', 32),
|
||||||
|
PixelFormatRGB24 = MKFOURCC('R', 'G', 'B', 24),
|
||||||
|
PixelFormatRGB16 = MKFOURCC('R', 'G', 'B', 16),
|
||||||
|
PixelFormatRGB15 = MKFOURCC('R', 'G', 'B', 15),
|
||||||
|
|
||||||
|
// BGR formats
|
||||||
|
PixelFormatBGR32 = MKFOURCC('B', 'G', 'R', 32),
|
||||||
|
PixelFormatBGR24 = MKFOURCC('B', 'G', 'R', 24),
|
||||||
|
PixelFormatBGR16 = MKFOURCC('B', 'G', 'R', 16),
|
||||||
|
PixelFormatBGR15 = MKFOURCC('B', 'G', 'R', 15),
|
||||||
|
|
||||||
|
// Luminance+Chrominance formats
|
||||||
|
PixelFormatUYVY = MKFOURCC('U', 'Y', 'V', 'Y'),
|
||||||
|
PixelFormatYUY2 = MKFOURCC('Y', 'U', 'Y', '2'),
|
||||||
|
|
||||||
|
// two planes -- one Y, one Cr + Cb interleaved
|
||||||
|
PixelFormatNV12 = MKFOURCC('N', 'V', '1', '2'),
|
||||||
|
PixelFormatNV21 = MKFOURCC('N', 'V', '2', '1')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VIDEOFORMATTYPES_H
|
1724
VCamUtils/src/image/videoframe.cpp
Normal file
1724
VCamUtils/src/image/videoframe.cpp
Normal file
File diff suppressed because it is too large
Load diff
82
VCamUtils/src/image/videoframe.h
Normal file
82
VCamUtils/src/image/videoframe.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VIDEOFRAME_H
|
||||||
|
#define VIDEOFRAME_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "videoframetypes.h"
|
||||||
|
#include "videoformattypes.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class VideoFramePrivate;
|
||||||
|
class VideoFormat;
|
||||||
|
using VideoData = std::vector<uint8_t>;
|
||||||
|
|
||||||
|
class VideoFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VideoFrame();
|
||||||
|
VideoFrame(const std::string &fileName);
|
||||||
|
VideoFrame(const VideoFormat &format);
|
||||||
|
VideoFrame(const VideoFrame &other);
|
||||||
|
VideoFrame &operator =(const VideoFrame &other);
|
||||||
|
~VideoFrame();
|
||||||
|
|
||||||
|
bool load(const std::string &fileName);
|
||||||
|
VideoFormat format() const;
|
||||||
|
VideoFormat &format();
|
||||||
|
VideoData data() const;
|
||||||
|
VideoData &data();
|
||||||
|
uint8_t *line(size_t plane, size_t y) const;
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
VideoFrame mirror(bool horizontalMirror, bool verticalMirror) const;
|
||||||
|
VideoFrame scaled(int width,
|
||||||
|
int height,
|
||||||
|
Scaling mode=ScalingFast,
|
||||||
|
AspectRatio aspectRatio=AspectRatioIgnore) const;
|
||||||
|
VideoFrame scaled(size_t maxArea,
|
||||||
|
Scaling mode=ScalingFast,
|
||||||
|
int align=32) const;
|
||||||
|
VideoFrame swapRgb(bool swap) const;
|
||||||
|
VideoFrame swapRgb() const;
|
||||||
|
bool canConvert(FourCC input, FourCC output) const;
|
||||||
|
VideoFrame convert(FourCC fourcc) const;
|
||||||
|
VideoFrame adjustHsl(int hue, int saturation, int luminance);
|
||||||
|
VideoFrame adjustGamma(int gamma);
|
||||||
|
VideoFrame adjustContrast(int contrast);
|
||||||
|
VideoFrame toGrayScale();
|
||||||
|
VideoFrame adjust(int hue,
|
||||||
|
int saturation,
|
||||||
|
int luminance,
|
||||||
|
int gamma,
|
||||||
|
int contrast,
|
||||||
|
bool gray);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VideoFramePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VIDEOFRAME_H
|
39
VCamUtils/src/image/videoframetypes.h
Normal file
39
VCamUtils/src/image/videoframetypes.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VIDEOFRAMETYPES_H
|
||||||
|
#define VIDEOFRAMETYPES_H
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
enum Scaling
|
||||||
|
{
|
||||||
|
ScalingFast,
|
||||||
|
ScalingLinear
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AspectRatio
|
||||||
|
{
|
||||||
|
AspectRatioIgnore,
|
||||||
|
AspectRatioKeep,
|
||||||
|
AspectRatioExpanding
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VIDEOFRAMETYPES_H
|
236
VCamUtils/src/ipcbridge.h
Normal file
236
VCamUtils/src/ipcbridge.h
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IPCBRIDGE_H
|
||||||
|
#define IPCBRIDGE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "image/videoformattypes.h"
|
||||||
|
#include "image/videoframetypes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class IpcBridgePrivate;
|
||||||
|
class VideoFormat;
|
||||||
|
class VideoFrame;
|
||||||
|
|
||||||
|
class IpcBridge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ServerState
|
||||||
|
{
|
||||||
|
ServerStateAvailable,
|
||||||
|
ServerStateGone
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Operation
|
||||||
|
{
|
||||||
|
OperationCreate,
|
||||||
|
OperationEdit,
|
||||||
|
OperationDestroy,
|
||||||
|
OperationDestroyAll
|
||||||
|
};
|
||||||
|
|
||||||
|
AKVCAM_SIGNAL(ServerStateChanged,
|
||||||
|
ServerState state)
|
||||||
|
AKVCAM_SIGNAL(FrameReady,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const VideoFrame &frame)
|
||||||
|
AKVCAM_SIGNAL(DeviceAdded,
|
||||||
|
const std::string &deviceId)
|
||||||
|
AKVCAM_SIGNAL(DeviceRemoved,
|
||||||
|
const std::string &deviceId)
|
||||||
|
AKVCAM_SIGNAL(ListenerAdded,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const std::string &listener)
|
||||||
|
AKVCAM_SIGNAL(ListenerRemoved,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const std::string &listener)
|
||||||
|
AKVCAM_SIGNAL(BroadcastingChanged,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const std::string &broadcaster)
|
||||||
|
AKVCAM_SIGNAL(MirrorChanged,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool horizontalMirror,
|
||||||
|
bool verticalMirror)
|
||||||
|
AKVCAM_SIGNAL(ScalingChanged,
|
||||||
|
const std::string &deviceId,
|
||||||
|
Scaling scaling)
|
||||||
|
AKVCAM_SIGNAL(AspectRatioChanged,
|
||||||
|
const std::string &deviceId,
|
||||||
|
AspectRatio aspectRatio)
|
||||||
|
AKVCAM_SIGNAL(SwapRgbChanged,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool swap)
|
||||||
|
|
||||||
|
public:
|
||||||
|
IpcBridge();
|
||||||
|
~IpcBridge();
|
||||||
|
|
||||||
|
/* Server & Client */
|
||||||
|
|
||||||
|
// Get the last error message.
|
||||||
|
std::wstring errorMessage() const;
|
||||||
|
|
||||||
|
// Pass extra options to the bridge.
|
||||||
|
void setOption(const std::string &key, const std::string &value);
|
||||||
|
|
||||||
|
// Driver search paths.
|
||||||
|
std::vector<std::wstring> driverPaths() const;
|
||||||
|
|
||||||
|
// Set driver search paths.
|
||||||
|
void setDriverPaths(const std::vector<std::wstring> &driverPaths);
|
||||||
|
|
||||||
|
// Driver configuration.
|
||||||
|
std::vector<std::string> availableDrivers() const;
|
||||||
|
std::string driver() const;
|
||||||
|
bool setDriver(const std::string &driver);
|
||||||
|
|
||||||
|
// Configure method to be used for executing commands with elevated
|
||||||
|
// privileges.
|
||||||
|
std::vector<std::string> availableRootMethods() const;
|
||||||
|
std::string rootMethod() const;
|
||||||
|
bool setRootMethod(const std::string &rootMethod);
|
||||||
|
|
||||||
|
// Manage main service connection.
|
||||||
|
void connectService(bool asClient);
|
||||||
|
void disconnectService();
|
||||||
|
|
||||||
|
// Register the peer to the global server.
|
||||||
|
bool registerPeer(bool asClient);
|
||||||
|
|
||||||
|
// Unregister the peer to the global server.
|
||||||
|
void unregisterPeer();
|
||||||
|
|
||||||
|
// List available devices.
|
||||||
|
std::vector<std::string> listDevices() const;
|
||||||
|
|
||||||
|
// Return human readable description of the device.
|
||||||
|
std::wstring description(const std::string &deviceId) const;
|
||||||
|
|
||||||
|
// Output pixel formats supported by the driver.
|
||||||
|
std::vector<PixelFormat> supportedOutputPixelFormats() const;
|
||||||
|
|
||||||
|
// Default output pixel format of the driver.
|
||||||
|
PixelFormat defaultOutputPixelFormat() const;
|
||||||
|
|
||||||
|
// Return supported formats for the device.
|
||||||
|
std::vector<VideoFormat> formats(const std::string &deviceId) const;
|
||||||
|
|
||||||
|
// Return return the status of the device.
|
||||||
|
std::string broadcaster(const std::string &deviceId) const;
|
||||||
|
|
||||||
|
// Device is horizontal mirrored,
|
||||||
|
bool isHorizontalMirrored(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Device is vertical mirrored,
|
||||||
|
bool isVerticalMirrored(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Scaling mode for frames shown in clients.
|
||||||
|
Scaling scalingMode(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Aspect ratio mode for frames shown in clients.
|
||||||
|
AspectRatio aspectRatioMode(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Check if red and blue channels are swapped.
|
||||||
|
bool swapRgb(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Returns the clients that are capturing from a virtual camera.
|
||||||
|
std::vector<std::string> listeners(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Returns clients PIDs using the virtual devices.
|
||||||
|
std::vector<uint64_t> clientsPids() const;
|
||||||
|
|
||||||
|
// Returns client executable from PID.
|
||||||
|
std::string clientExe(uint64_t pid) const;
|
||||||
|
|
||||||
|
// Returns 'true' if the application needs to be restarted before
|
||||||
|
// creating, editing, or removing the virtual devices.
|
||||||
|
bool needsRestart(Operation operation) const;
|
||||||
|
|
||||||
|
// Can create, edit, or remove virtual devices?
|
||||||
|
bool canApply(Operation operation) const;
|
||||||
|
|
||||||
|
/* Server */
|
||||||
|
|
||||||
|
// Create a device definition.
|
||||||
|
std::string deviceCreate(const std::wstring &description,
|
||||||
|
const std::vector<VideoFormat> &formats);
|
||||||
|
|
||||||
|
// Edit a device definition.
|
||||||
|
bool deviceEdit(const std::string &deviceId,
|
||||||
|
const std::wstring &description,
|
||||||
|
const std::vector<VideoFormat> &formats);
|
||||||
|
|
||||||
|
// Change device description.
|
||||||
|
bool changeDescription(const std::string &deviceId,
|
||||||
|
const std::wstring &description);
|
||||||
|
|
||||||
|
// Remove a device definition.
|
||||||
|
bool deviceDestroy(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Remove all device definitions.
|
||||||
|
bool destroyAllDevices();
|
||||||
|
|
||||||
|
// Start frame transfer to the device.
|
||||||
|
bool deviceStart(const std::string &deviceId,
|
||||||
|
const VideoFormat &format);
|
||||||
|
|
||||||
|
// Stop frame transfer to the device.
|
||||||
|
void deviceStop(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Transfer a frame to the device.
|
||||||
|
bool write(const std::string &deviceId,
|
||||||
|
const VideoFrame &frame);
|
||||||
|
|
||||||
|
// Set mirroring options for device,
|
||||||
|
void setMirroring(const std::string &deviceId,
|
||||||
|
bool horizontalMirrored,
|
||||||
|
bool verticalMirrored);
|
||||||
|
|
||||||
|
// Set scaling options for device.
|
||||||
|
void setScaling(const std::string &deviceId,
|
||||||
|
Scaling scaling);
|
||||||
|
|
||||||
|
// Set aspect ratio options for device.
|
||||||
|
void setAspectRatio(const std::string &deviceId,
|
||||||
|
AspectRatio aspectRatio);
|
||||||
|
|
||||||
|
// Swap red and blue channels.
|
||||||
|
void setSwapRgb(const std::string &deviceId, bool swap);
|
||||||
|
|
||||||
|
/* Client */
|
||||||
|
|
||||||
|
// Increment the count of device listeners
|
||||||
|
bool addListener(const std::string &deviceId);
|
||||||
|
|
||||||
|
// Decrement the count of device listeners
|
||||||
|
bool removeListener(const std::string &deviceId);
|
||||||
|
|
||||||
|
private:
|
||||||
|
IpcBridgePrivate *d;
|
||||||
|
|
||||||
|
friend class IpcBridgePrivate;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IPCBRIDGE_H
|
143
VCamUtils/src/logger/logger.cpp
Normal file
143
VCamUtils/src/logger/logger.cpp
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
#include "../utils.h"
|
||||||
|
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class LoggerPrivate: public std::streambuf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::ostream *outs;
|
||||||
|
std::string fileName;
|
||||||
|
std::fstream logFile;
|
||||||
|
Logger::LogCallback logCallback;
|
||||||
|
|
||||||
|
LoggerPrivate();
|
||||||
|
~LoggerPrivate() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::streamsize xsputn(const char *s, std::streamsize n) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline LoggerPrivate *loggerPrivate()
|
||||||
|
{
|
||||||
|
static LoggerPrivate logger;
|
||||||
|
|
||||||
|
return &logger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Logger::start(const std::string &fileName,
|
||||||
|
const std::string &extension)
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
loggerPrivate()->fileName =
|
||||||
|
fileName + "-" + timeStamp() + "." + extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Logger::start(LogCallback callback)
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
loggerPrivate()->logCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::Logger::header()
|
||||||
|
{
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto nowMSecs = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
|
||||||
|
char timeStamp[256];
|
||||||
|
auto time = std::chrono::system_clock::to_time_t(now);
|
||||||
|
strftime(timeStamp, 256, "%Y-%m-%d %H:%M:%S", std::localtime(&time));
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "["
|
||||||
|
<< timeStamp
|
||||||
|
<< "." << nowMSecs.count() % 1000 << ", " << std::this_thread::get_id() << "] ";
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &AkVCam::Logger::out()
|
||||||
|
{
|
||||||
|
if (loggerPrivate()->logCallback.second)
|
||||||
|
return *loggerPrivate()->outs;
|
||||||
|
|
||||||
|
if (loggerPrivate()->fileName.empty())
|
||||||
|
return std::cout;
|
||||||
|
|
||||||
|
if (!loggerPrivate()->logFile.is_open())
|
||||||
|
loggerPrivate()->logFile.open(loggerPrivate()->fileName,
|
||||||
|
std::ios_base::out
|
||||||
|
| std::ios_base::app);
|
||||||
|
|
||||||
|
if (!loggerPrivate()->logFile.is_open())
|
||||||
|
return std::cout;
|
||||||
|
|
||||||
|
return loggerPrivate()->logFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Logger::log()
|
||||||
|
{
|
||||||
|
tlog(header());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Logger::tlog()
|
||||||
|
{
|
||||||
|
out() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Logger::stop()
|
||||||
|
{
|
||||||
|
loggerPrivate()->fileName = {};
|
||||||
|
|
||||||
|
if (loggerPrivate()->logFile.is_open())
|
||||||
|
loggerPrivate()->logFile.close();
|
||||||
|
|
||||||
|
loggerPrivate()->logCallback = {nullptr, nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::LoggerPrivate::LoggerPrivate():
|
||||||
|
outs(new std::ostream(this)),
|
||||||
|
logCallback({nullptr, nullptr})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::LoggerPrivate::~LoggerPrivate()
|
||||||
|
{
|
||||||
|
delete this->outs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize AkVCam::LoggerPrivate::xsputn(const char *s, std::streamsize n)
|
||||||
|
{
|
||||||
|
if (this->logCallback.second)
|
||||||
|
this->logCallback.second(this->logCallback.first, s, size_t(n));
|
||||||
|
|
||||||
|
return std::streambuf::xsputn(s, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
67
VCamUtils/src/logger/logger.h
Normal file
67
VCamUtils/src/logger/logger.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AKVCAMUTILS_LOGGER_H
|
||||||
|
#define AKVCAMUTILS_LOGGER_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "../utils.h"
|
||||||
|
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
#define AkLoggerStart(...) AkVCam::Logger::start(__VA_ARGS__)
|
||||||
|
#define AkLoggerLog(...) AkVCam::Logger::log(__VA_ARGS__)
|
||||||
|
#define AkLoggerStop() AkVCam::Logger::stop()
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
namespace Logger
|
||||||
|
{
|
||||||
|
AKVCAM_CALLBACK(Log, const char *data, size_t size)
|
||||||
|
|
||||||
|
void start(const std::string &fileName=std::string(),
|
||||||
|
const std::string &extension=std::string());
|
||||||
|
void start(LogCallback callback);
|
||||||
|
std::string header();
|
||||||
|
std::ostream &out();
|
||||||
|
void log();
|
||||||
|
void tlog();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
template<typename First, typename... Next>
|
||||||
|
void tlog(const First &first, const Next &... next)
|
||||||
|
{
|
||||||
|
out() << first;
|
||||||
|
tlog(next...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Param>
|
||||||
|
void log(const Param &... param)
|
||||||
|
{
|
||||||
|
tlog(header(), " ", param...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define AkLoggerStart(...)
|
||||||
|
#define AkLoggerLog(...)
|
||||||
|
#define AkLoggerStop()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // AKVCAMUTILS_LOGGER_H
|
98
VCamUtils/src/timer.cpp
Normal file
98
VCamUtils/src/timer.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class TimerPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Timer *self;
|
||||||
|
std::thread m_thread;
|
||||||
|
int m_interval;
|
||||||
|
bool m_running;
|
||||||
|
|
||||||
|
explicit TimerPrivate(Timer *self);
|
||||||
|
void timerLoop();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Timer::Timer()
|
||||||
|
{
|
||||||
|
this->d = new TimerPrivate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Timer::~Timer()
|
||||||
|
{
|
||||||
|
this->stop();
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::Timer::interval() const
|
||||||
|
{
|
||||||
|
return this->d->m_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int &AkVCam::Timer::interval()
|
||||||
|
{
|
||||||
|
return this->d->m_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Timer::setInterval(int msec)
|
||||||
|
{
|
||||||
|
this->d->m_interval = msec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Timer::start()
|
||||||
|
{
|
||||||
|
this->stop();
|
||||||
|
this->d->m_running = true;
|
||||||
|
this->d->m_thread = std::thread(&TimerPrivate::timerLoop, this->d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Timer::stop()
|
||||||
|
{
|
||||||
|
if (!this->d->m_running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_running = false;
|
||||||
|
this->d->m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::TimerPrivate::TimerPrivate(AkVCam::Timer *self):
|
||||||
|
self(self),
|
||||||
|
m_interval(0),
|
||||||
|
m_running(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::TimerPrivate::timerLoop()
|
||||||
|
{
|
||||||
|
while (this->m_running) {
|
||||||
|
if (this->m_interval)
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(this->m_interval));
|
||||||
|
|
||||||
|
AKVCAM_EMIT_NOARGS(this->self, Timeout);
|
||||||
|
}
|
||||||
|
}
|
50
VCamUtils/src/timer.h
Normal file
50
VCamUtils/src/timer.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TIMER_H
|
||||||
|
#define TIMER_H
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class TimerPrivate;
|
||||||
|
|
||||||
|
class Timer
|
||||||
|
{
|
||||||
|
AKVCAM_SIGNAL_NOARGS(Timeout)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Timer();
|
||||||
|
Timer(const Timer &other) = delete;
|
||||||
|
~Timer();
|
||||||
|
|
||||||
|
int interval() const;
|
||||||
|
int &interval();
|
||||||
|
void setInterval(int msec);
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimerPrivate *d;
|
||||||
|
friend class TimerPrivate;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TIMER_H
|
158
VCamUtils/src/utils.cpp
Normal file
158
VCamUtils/src/utils.cpp
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
uint64_t AkVCam::id()
|
||||||
|
{
|
||||||
|
static uint64_t id = 0;
|
||||||
|
|
||||||
|
return id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::timeStamp()
|
||||||
|
{
|
||||||
|
char ts[256];
|
||||||
|
auto time = std::time(nullptr);
|
||||||
|
strftime(ts, 256, "%Y%m%d%H%M%S", std::localtime(&time));
|
||||||
|
|
||||||
|
return std::string(ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::replace(const std::string &str,
|
||||||
|
const std::string &from,
|
||||||
|
const std::string &to)
|
||||||
|
{
|
||||||
|
auto newStr = str;
|
||||||
|
|
||||||
|
for (auto pos = newStr.find(from);
|
||||||
|
pos != std::string::npos;
|
||||||
|
pos = newStr.find(from))
|
||||||
|
newStr.replace(pos, from.size(), to);
|
||||||
|
|
||||||
|
return newStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring AkVCam::replace(const std::wstring &str,
|
||||||
|
const std::wstring &from,
|
||||||
|
const std::wstring &to)
|
||||||
|
{
|
||||||
|
auto newStr = str;
|
||||||
|
|
||||||
|
for (auto pos = newStr.find(from);
|
||||||
|
pos != std::wstring::npos;
|
||||||
|
pos = newStr.find(from))
|
||||||
|
newStr.replace(pos, from.size(), to);
|
||||||
|
|
||||||
|
return newStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::isEqualFile(const std::wstring &file1, const std::wstring &file2)
|
||||||
|
{
|
||||||
|
if (file1 == file2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::fstream f1;
|
||||||
|
std::fstream f2;
|
||||||
|
f1.open(std::string(file1.begin(), file1.end()), std::ios_base::in);
|
||||||
|
f2.open(std::string(file2.begin(), file2.end()), std::ios_base::in);
|
||||||
|
|
||||||
|
if (!f1.is_open() || !f2.is_open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const size_t bufferSize = 1024;
|
||||||
|
char buffer1[bufferSize];
|
||||||
|
char buffer2[bufferSize];
|
||||||
|
memset(buffer1, 0, bufferSize);
|
||||||
|
memset(buffer2, 0, bufferSize);
|
||||||
|
|
||||||
|
while (!f1.eof() && !f2.eof()) {
|
||||||
|
f1.read(buffer1, bufferSize);
|
||||||
|
f2.read(buffer2, bufferSize);
|
||||||
|
|
||||||
|
if (memcmp(buffer1, buffer2, bufferSize) != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::trimmed(const std::string &str)
|
||||||
|
{
|
||||||
|
auto left = uint64_t(str.size());
|
||||||
|
auto right = uint64_t(str.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < str.size(); i++)
|
||||||
|
if (!isspace(str[i])) {
|
||||||
|
left = uint64_t(i);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto strippedLen = str.size();
|
||||||
|
|
||||||
|
if (left == str.size()) {
|
||||||
|
strippedLen = 0;
|
||||||
|
} else {
|
||||||
|
for (int64_t i = str.size() - 1; i >= 0; i--)
|
||||||
|
if (!isspace(str[size_t(i)])) {
|
||||||
|
right = uint64_t(i);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strippedLen = size_t(right - left + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.substr(size_t(left), strippedLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring AkVCam::trimmed(const std::wstring &str)
|
||||||
|
{
|
||||||
|
auto left = uint64_t(str.size());
|
||||||
|
auto right = uint64_t(str.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < str.size(); i++)
|
||||||
|
if (!iswspace(str[i])) {
|
||||||
|
left = uint64_t(i);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto strippedLen = str.size();
|
||||||
|
|
||||||
|
if (left == str.size()) {
|
||||||
|
strippedLen = 0;
|
||||||
|
} else {
|
||||||
|
for (int64_t i = str.size() - 1; i >= 0; i--)
|
||||||
|
if (!iswspace(str[size_t(i)])) {
|
||||||
|
right = uint64_t(i);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strippedLen = size_t(right - left + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.substr(size_t(left), strippedLen);
|
||||||
|
}
|
158
VCamUtils/src/utils.h
Normal file
158
VCamUtils/src/utils.h
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AKVCAMUTILS_UTILS_H
|
||||||
|
#define AKVCAMUTILS_UTILS_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifndef UNUSED
|
||||||
|
#define UNUSED(x) (void)(x);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GLOBAL_STATIC(type, variableName) \
|
||||||
|
type *variableName() \
|
||||||
|
{ \
|
||||||
|
static type _##variableName; \
|
||||||
|
\
|
||||||
|
return &_##variableName; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GLOBAL_STATIC_WITH_ARGS(type, variableName, ...) \
|
||||||
|
type *variableName() \
|
||||||
|
{ \
|
||||||
|
static type _##variableName {__VA_ARGS__}; \
|
||||||
|
\
|
||||||
|
return &_##variableName; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AKVCAM_CALLBACK(CallbackName, ...) \
|
||||||
|
using CallbackName##CallbackT = void (*)(void *userData, __VA_ARGS__); \
|
||||||
|
using CallbackName##Callback = std::pair<void *, CallbackName##CallbackT>;
|
||||||
|
|
||||||
|
#define AKVCAM_CALLBACK_NOARGS(CallbackName) \
|
||||||
|
using CallbackName##CallbackT = void (*)(void *userData); \
|
||||||
|
using CallbackName##Callback = std::pair<void *, CallbackName##CallbackT>;
|
||||||
|
|
||||||
|
#define AKVCAM_SIGNAL(CallbackName, ...) \
|
||||||
|
public: \
|
||||||
|
using CallbackName##CallbackT = void (*)(void *userData, __VA_ARGS__); \
|
||||||
|
using CallbackName##Callback = std::pair<void *, CallbackName##CallbackT>; \
|
||||||
|
\
|
||||||
|
void connect##CallbackName(void *userData, \
|
||||||
|
CallbackName##CallbackT callback) \
|
||||||
|
{ \
|
||||||
|
if (!callback) \
|
||||||
|
return; \
|
||||||
|
\
|
||||||
|
for (auto &func: this->m_##CallbackName##Callback) \
|
||||||
|
if (func.first == userData \
|
||||||
|
&& func.second == callback) \
|
||||||
|
return; \
|
||||||
|
\
|
||||||
|
this->m_##CallbackName##Callback.push_back({userData, callback});\
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void disconnect##CallbackName(void *userData, \
|
||||||
|
CallbackName##CallbackT callback) \
|
||||||
|
{ \
|
||||||
|
if (!callback) \
|
||||||
|
return; \
|
||||||
|
\
|
||||||
|
for (auto it = this->m_##CallbackName##Callback.begin(); \
|
||||||
|
it != this->m_##CallbackName##Callback.end(); \
|
||||||
|
it++) \
|
||||||
|
if (it->first == userData \
|
||||||
|
&& it->second == callback) { \
|
||||||
|
this->m_##CallbackName##Callback.erase(it); \
|
||||||
|
\
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
std::vector<CallbackName##Callback> m_##CallbackName##Callback;
|
||||||
|
|
||||||
|
#define AKVCAM_SIGNAL_NOARGS(CallbackName) \
|
||||||
|
public: \
|
||||||
|
using CallbackName##CallbackT = void (*)(void *userData); \
|
||||||
|
using CallbackName##Callback = std::pair<void *, CallbackName##CallbackT>; \
|
||||||
|
\
|
||||||
|
void connect##CallbackName(void *userData, \
|
||||||
|
CallbackName##CallbackT callback) \
|
||||||
|
{ \
|
||||||
|
if (!callback) \
|
||||||
|
return; \
|
||||||
|
\
|
||||||
|
for (auto &func: this->m_##CallbackName##Callback) \
|
||||||
|
if (func.first == userData \
|
||||||
|
&& func.second == callback) \
|
||||||
|
return; \
|
||||||
|
\
|
||||||
|
this->m_##CallbackName##Callback.push_back({userData, callback});\
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void disconnect##CallbackName(void *userData, \
|
||||||
|
CallbackName##CallbackT callback) \
|
||||||
|
{ \
|
||||||
|
if (!callback) \
|
||||||
|
return; \
|
||||||
|
\
|
||||||
|
for (auto it = this->m_##CallbackName##Callback.begin(); \
|
||||||
|
it != this->m_##CallbackName##Callback.end(); \
|
||||||
|
it++) \
|
||||||
|
if (it->first == userData \
|
||||||
|
&& it->second == callback) { \
|
||||||
|
this->m_##CallbackName##Callback.erase(it); \
|
||||||
|
\
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
std::vector<CallbackName##Callback> m_##CallbackName##Callback;
|
||||||
|
|
||||||
|
#define AKVCAM_EMIT(owner, CallbackName, ...) \
|
||||||
|
for (auto &callback: owner->m_##CallbackName##Callback) \
|
||||||
|
if (callback.second) \
|
||||||
|
callback.second(callback.first, __VA_ARGS__); \
|
||||||
|
|
||||||
|
#define AKVCAM_EMIT_NOARGS(owner, CallbackName) \
|
||||||
|
for (auto &callback: owner->m_##CallbackName##Callback) \
|
||||||
|
if (callback.second) \
|
||||||
|
callback.second(callback.first); \
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
uint64_t id();
|
||||||
|
std::string timeStamp();
|
||||||
|
std::string replace(const std::string &str,
|
||||||
|
const std::string &from,
|
||||||
|
const std::string &to);
|
||||||
|
std::wstring replace(const std::wstring &str,
|
||||||
|
const std::wstring &from,
|
||||||
|
const std::wstring &to);
|
||||||
|
bool isEqualFile(const std::wstring &file1, const std::wstring &file2);
|
||||||
|
std::string trimmed(const std::string &str);
|
||||||
|
std::wstring trimmed(const std::wstring &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // AKVCAMUTILS_UTILS_H
|
25
akvirtualcamera.pro
Normal file
25
akvirtualcamera.pro
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
TEMPLATE = subdirs
|
||||||
|
CONFIG += ordered
|
||||||
|
|
||||||
|
SUBDIRS = VCamUtils
|
||||||
|
macx: SUBDIRS += cmio
|
||||||
|
win32: SUBDIRS += dshow
|
||||||
|
SUBDIRS += Manager
|
59
cmio/Assistant/Assistant.pro
Normal file
59
cmio/Assistant/Assistant.pro
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../../commons.pri) {
|
||||||
|
include(../../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include(../cmio.pri)
|
||||||
|
include(../../VCamUtils/VCamUtils.pri)
|
||||||
|
|
||||||
|
CONFIG += console link_prl
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
TARGET = $${CMIO_PLUGIN_ASSISTANT_NAME}
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
src/main.cpp \
|
||||||
|
src/assistant.cpp
|
||||||
|
|
||||||
|
LIBS += \
|
||||||
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
|
-framework CoreFoundation
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
src/assistantglobals.h \
|
||||||
|
src/assistant.h
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
../..
|
||||||
|
|
||||||
|
QMAKE_POST_LINK = \
|
||||||
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/../VirtualCamera/$${CMIO_PLUGIN_NAME}.plugin/Contents/Resources)) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/$${CMIO_PLUGIN_ASSISTANT_NAME}) $$shell_path($${OUT_PWD}/../VirtualCamera/$${CMIO_PLUGIN_NAME}.plugin/Contents/Resources)
|
1469
cmio/Assistant/src/assistant.cpp
Normal file
1469
cmio/Assistant/src/assistant.cpp
Normal file
File diff suppressed because it is too large
Load diff
45
cmio/Assistant/src/assistant.h
Normal file
45
cmio/Assistant/src/assistant.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASSISTANT_H
|
||||||
|
#define ASSISTANT_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <xpc/xpc.h>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class AssistantPrivate;
|
||||||
|
|
||||||
|
class Assistant
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Assistant();
|
||||||
|
Assistant(const Assistant &other) = delete;
|
||||||
|
~Assistant();
|
||||||
|
|
||||||
|
void setTimeout(double timeout);
|
||||||
|
void messageReceived(xpc_connection_t client, xpc_object_t event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AssistantPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASSISTANT_H
|
69
cmio/Assistant/src/assistantglobals.h
Normal file
69
cmio/Assistant/src/assistantglobals.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASSISTANTGLOBALS_H
|
||||||
|
#define ASSISTANTGLOBALS_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <xpc/xpc.h>
|
||||||
|
|
||||||
|
#define AKVCAM_ASSISTANT_NAME "org.webcamoid.cmio.AkVCam.Assistant"
|
||||||
|
#define AKVCAM_ASSISTANT_CLIENT_NAME "org.webcamoid.cmio.AkVCam.Client"
|
||||||
|
#define AKVCAM_ASSISTANT_SERVER_NAME "org.webcamoid.cmio.AkVCam.Server"
|
||||||
|
|
||||||
|
// General messages
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_ISALIVE 0x000
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_FRAME_READY 0x001
|
||||||
|
|
||||||
|
// Assistant messages
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_REQUEST_PORT 0x100
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_ADD_PORT 0x101
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_REMOVE_PORT 0x102
|
||||||
|
|
||||||
|
// Device control and information
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICES 0x200
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_CREATE 0x201
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY 0x202
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION 0x203
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS 0x204
|
||||||
|
|
||||||
|
// Device listeners controls
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS 0x300
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER 0x301
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD 0x302
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE 0x303
|
||||||
|
|
||||||
|
// Device dynamic properties
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING 0x400
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING 0x402
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING 0x403
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SCALING 0x404
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING 0x405
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO 0x406
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO 0x407
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB 0x408
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB 0x409
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
using XpcMessage = std::function<void (xpc_connection_t, xpc_object_t)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASSISTANTGLOBALS_H
|
74
cmio/Assistant/src/main.cpp
Normal file
74
cmio/Assistant/src/main.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <CoreFoundation/CFRunLoop.h>
|
||||||
|
#include <xpc/xpc.h>
|
||||||
|
#include <xpc/connection.h>
|
||||||
|
|
||||||
|
#include "assistant.h"
|
||||||
|
#include "assistantglobals.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
GLOBAL_STATIC(AkVCam::Assistant, assistant)
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
auto server =
|
||||||
|
xpc_connection_create_mach_service(AKVCAM_ASSISTANT_NAME,
|
||||||
|
NULL,
|
||||||
|
XPC_CONNECTION_MACH_SERVICE_LISTENER);
|
||||||
|
|
||||||
|
if (!server)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
for (int i = 0; i < argc; i++)
|
||||||
|
if (strcmp(argv[i], "--timeout") == 0 && i + 1 < argc) {
|
||||||
|
auto timeout = strtod(argv[i + 1], nullptr);
|
||||||
|
AkLoggerLog("Set timeout: ", timeout);
|
||||||
|
assistant()->setTimeout(timeout);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xpc_connection_set_event_handler(server, ^(xpc_object_t event) {
|
||||||
|
auto type = xpc_get_type(event);
|
||||||
|
|
||||||
|
if (type == XPC_TYPE_ERROR) {
|
||||||
|
auto description = xpc_copy_description(event);
|
||||||
|
AkLoggerLog("ERROR: ", description);
|
||||||
|
free(description);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto client = reinterpret_cast<xpc_connection_t>(event);
|
||||||
|
|
||||||
|
xpc_connection_set_event_handler(client, ^(xpc_object_t event) {
|
||||||
|
assistant()->messageReceived(client, event);
|
||||||
|
});
|
||||||
|
|
||||||
|
xpc_connection_resume(client);
|
||||||
|
});
|
||||||
|
|
||||||
|
xpc_connection_resume(server);
|
||||||
|
CFRunLoopRun();
|
||||||
|
xpc_release(server);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
55
cmio/VCamIPC/VCamIPC.pro
Normal file
55
cmio/VCamIPC/VCamIPC.pro
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../../commons.pri) {
|
||||||
|
include(../../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include(../cmio.pri)
|
||||||
|
|
||||||
|
CONFIG += \
|
||||||
|
staticlib \
|
||||||
|
create_prl \
|
||||||
|
no_install_prl
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
TARGET = VCamIPC
|
||||||
|
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
LIBS = \
|
||||||
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
|
-framework Foundation
|
||||||
|
|
||||||
|
OBJECTIVE_SOURCES = \
|
||||||
|
src/ipcbridge.mm
|
||||||
|
|
||||||
|
HEADERS = \
|
||||||
|
../../ipcbridge.h
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
.. \
|
||||||
|
../..
|
1748
cmio/VCamIPC/src/ipcbridge.mm
Normal file
1748
cmio/VCamIPC/src/ipcbridge.mm
Normal file
File diff suppressed because it is too large
Load diff
46
cmio/VirtualCamera/Info.plist
Normal file
46
cmio/VirtualCamera/Info.plist
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>AkVirtualCamera</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string></string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>org.webcamoid.cmio.DAL.VirtualCamera</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>AkVirtualCamera</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>BNDL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>8.7.1</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>8.7.1</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFPlugInFactories</key>
|
||||||
|
<dict>
|
||||||
|
<key>41764B79-7320-5643-616D-363462697473</key>
|
||||||
|
<string>akPluginMain</string>
|
||||||
|
</dict>
|
||||||
|
<key>CFPlugInTypes</key>
|
||||||
|
<dict>
|
||||||
|
<key>30010C1C-93BF-11D8-8B5B-000A95AF9C6A</key>
|
||||||
|
<array>
|
||||||
|
<string>41764B79-7320-5643-616D-363462697473</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<key>CMIOHardwareAssistantServiceNames</key>
|
||||||
|
<array>
|
||||||
|
<string>org.webcamoid.cmio.AkVCam.Assistant</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
93
cmio/VirtualCamera/VirtualCamera.pro
Normal file
93
cmio/VirtualCamera/VirtualCamera.pro
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../../commons.pri) {
|
||||||
|
include(../../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include(../cmio.pri)
|
||||||
|
include(../../VCamUtils/VCamUtils.pri)
|
||||||
|
|
||||||
|
CONFIG -= qt link_prl
|
||||||
|
CONFIG += \
|
||||||
|
unversioned_libname \
|
||||||
|
unversioned_soname
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
.. \
|
||||||
|
../..
|
||||||
|
|
||||||
|
LIBS = \
|
||||||
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
|
-L$${OUT_PWD}/../VCamIPC/$${BIN_DIR} -lVCamIPC \
|
||||||
|
-framework CoreFoundation \
|
||||||
|
-framework CoreMedia \
|
||||||
|
-framework CoreMediaIO \
|
||||||
|
-framework CoreVideo \
|
||||||
|
-framework Foundation \
|
||||||
|
-framework IOKit \
|
||||||
|
-framework IOSurface
|
||||||
|
|
||||||
|
TARGET = $${CMIO_PLUGIN_NAME}
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
src/plugin.h \
|
||||||
|
src/plugininterface.h \
|
||||||
|
src/utils.h \
|
||||||
|
src/device.h \
|
||||||
|
src/object.h \
|
||||||
|
src/stream.h \
|
||||||
|
src/objectinterface.h \
|
||||||
|
src/objectproperties.h \
|
||||||
|
src/clock.h \
|
||||||
|
src/queue.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
src/plugin.cpp \
|
||||||
|
src/plugininterface.cpp \
|
||||||
|
src/utils.cpp \
|
||||||
|
src/device.cpp \
|
||||||
|
src/object.cpp \
|
||||||
|
src/stream.cpp \
|
||||||
|
src/objectinterface.cpp \
|
||||||
|
src/objectproperties.cpp \
|
||||||
|
src/clock.cpp
|
||||||
|
|
||||||
|
OTHER_FILES = \
|
||||||
|
Info.plist
|
||||||
|
|
||||||
|
INSTALLS += vcam
|
||||||
|
vcam.files = $${OUT_PWD}/$${TARGET}.plugin
|
||||||
|
vcam.path = $${DATAROOTDIR}
|
||||||
|
vcam.CONFIG += no_check_exist
|
||||||
|
|
||||||
|
QMAKE_POST_LINK = \
|
||||||
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/MacOS)) $${CMD_SEP} \
|
||||||
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/Resources)) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${PWD}/Info.plist) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/lib$${TARGET}.dylib) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/MacOS/$${TARGET}) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${PWD}/../../share/TestFrame/TestFrame.bmp) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/Contents/Resources)
|
73
cmio/VirtualCamera/src/clock.cpp
Normal file
73
cmio/VirtualCamera/src/clock.cpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <CoreMediaIO/CMIOHardwareStream.h>
|
||||||
|
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
|
AkVCam::Clock::Clock(const std::string& name,
|
||||||
|
const CMTime getTimeCallMinimumInterval,
|
||||||
|
UInt32 numberOfEventsForRateSmoothing,
|
||||||
|
UInt32 numberOfAveragesForRateSmoothing,
|
||||||
|
void *parent):
|
||||||
|
m_parent(parent),
|
||||||
|
m_clock(nullptr)
|
||||||
|
{
|
||||||
|
auto nameRef =
|
||||||
|
CFStringCreateWithCString(kCFAllocatorDefault,
|
||||||
|
name.c_str(),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
auto status =
|
||||||
|
CMIOStreamClockCreate(kCFAllocatorDefault,
|
||||||
|
nameRef,
|
||||||
|
this->m_parent,
|
||||||
|
getTimeCallMinimumInterval,
|
||||||
|
numberOfEventsForRateSmoothing,
|
||||||
|
numberOfAveragesForRateSmoothing,
|
||||||
|
&this->m_clock);
|
||||||
|
|
||||||
|
if (status != noErr)
|
||||||
|
this->m_clock = nullptr;
|
||||||
|
|
||||||
|
CFRelease(nameRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Clock::~Clock()
|
||||||
|
{
|
||||||
|
if (this->m_clock) {
|
||||||
|
CMIOStreamClockInvalidate(this->m_clock);
|
||||||
|
CFRelease(this->m_clock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFTypeRef AkVCam::Clock::ref() const
|
||||||
|
{
|
||||||
|
return this->m_clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Clock::postTimingEvent(CMTime eventTime,
|
||||||
|
UInt64 hostTime,
|
||||||
|
Boolean resynchronize)
|
||||||
|
{
|
||||||
|
return CMIOStreamClockPostTimingEvent(eventTime,
|
||||||
|
hostTime,
|
||||||
|
resynchronize,
|
||||||
|
this->m_clock);
|
||||||
|
}
|
53
cmio/VirtualCamera/src/clock.h
Normal file
53
cmio/VirtualCamera/src/clock.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLOCK_H
|
||||||
|
#define CLOCK_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <CoreMedia/CMTime.h>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class Clock;
|
||||||
|
typedef std::shared_ptr<Clock> ClockPtr;
|
||||||
|
|
||||||
|
class Clock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Clock(const std::string& name,
|
||||||
|
const CMTime getTimeCallMinimumInterval,
|
||||||
|
UInt32 numberOfEventsForRateSmoothing,
|
||||||
|
UInt32 numberOfAveragesForRateSmoothing,
|
||||||
|
void *parent=nullptr);
|
||||||
|
~Clock();
|
||||||
|
|
||||||
|
CFTypeRef ref() const;
|
||||||
|
OSStatus postTimingEvent(CMTime eventTime,
|
||||||
|
UInt64 hostTime,
|
||||||
|
Boolean resynchronize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *m_parent;
|
||||||
|
CFTypeRef m_clock;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CLOCK_H
|
339
cmio/VirtualCamera/src/device.cpp
Normal file
339
cmio/VirtualCamera/src/device.cpp
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
AkVCam::Device::Device(CMIOHardwarePlugInRef pluginInterface,
|
||||||
|
bool registerObject):
|
||||||
|
AkVCam::Object(pluginInterface)
|
||||||
|
{
|
||||||
|
this->m_className = "Device";
|
||||||
|
this->m_classID = kCMIODeviceClassID;
|
||||||
|
|
||||||
|
if (registerObject) {
|
||||||
|
this->createObject();
|
||||||
|
this->registerObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Device::~Device()
|
||||||
|
{
|
||||||
|
this->registerStreams(false);
|
||||||
|
this->registerObject(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::createObject()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (!this->m_pluginInterface
|
||||||
|
|| !*this->m_pluginInterface)
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
CMIOObjectID deviceID = 0;
|
||||||
|
|
||||||
|
auto status =
|
||||||
|
CMIOObjectCreate(this->m_pluginInterface,
|
||||||
|
kCMIOObjectSystemObject,
|
||||||
|
this->m_classID,
|
||||||
|
&deviceID);
|
||||||
|
|
||||||
|
if (status == kCMIOHardwareNoError) {
|
||||||
|
this->m_isCreated = true;
|
||||||
|
this->m_objectID = deviceID;
|
||||||
|
AkLoggerLog("Created device: ", this->m_objectID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::registerObject(bool regist)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!this->m_isCreated
|
||||||
|
|| !this->m_pluginInterface
|
||||||
|
|| !*this->m_pluginInterface)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (regist) {
|
||||||
|
status = CMIOObjectsPublishedAndDied(this->m_pluginInterface,
|
||||||
|
kCMIOObjectSystemObject,
|
||||||
|
1,
|
||||||
|
&this->m_objectID,
|
||||||
|
0,
|
||||||
|
nullptr);
|
||||||
|
} else {
|
||||||
|
status = CMIOObjectsPublishedAndDied(this->m_pluginInterface,
|
||||||
|
kCMIOObjectSystemObject,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
1,
|
||||||
|
&this->m_objectID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::StreamPtr AkVCam::Device::addStream()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
auto stream = StreamPtr(new Stream(false, this));
|
||||||
|
|
||||||
|
if (stream->createObject() == kCMIOHardwareNoError) {
|
||||||
|
this->m_streams[stream->objectID()] = stream;
|
||||||
|
this->updateStreamsProperty();
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
return StreamPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<AkVCam::StreamPtr> AkVCam::Device::addStreams(int n)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
std::list<StreamPtr> streams;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
auto stream = StreamPtr(new Stream(false, this));
|
||||||
|
|
||||||
|
if (stream->createObject() != kCMIOHardwareNoError)
|
||||||
|
return std::list<StreamPtr>();
|
||||||
|
|
||||||
|
streams.push_back(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &stream: streams) {
|
||||||
|
this->m_streams[stream->objectID()] = stream;
|
||||||
|
this->updateStreamsProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::registerStreams(bool regist)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!this->m_isCreated
|
||||||
|
|| !this->m_pluginInterface
|
||||||
|
|| !*this->m_pluginInterface
|
||||||
|
|| this->m_streams.empty())
|
||||||
|
return status;
|
||||||
|
|
||||||
|
std::vector<CMIOObjectID> streams;
|
||||||
|
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
streams.push_back(stream.first);
|
||||||
|
|
||||||
|
if (regist) {
|
||||||
|
status = CMIOObjectsPublishedAndDied(this->m_pluginInterface,
|
||||||
|
kCMIOObjectSystemObject,
|
||||||
|
UInt32(streams.size()),
|
||||||
|
streams.data(),
|
||||||
|
0,
|
||||||
|
nullptr);
|
||||||
|
} else {
|
||||||
|
status = CMIOObjectsPublishedAndDied(this->m_pluginInterface,
|
||||||
|
kCMIOObjectSystemObject,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
UInt32(streams.size()),
|
||||||
|
streams.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::Device::deviceId() const
|
||||||
|
{
|
||||||
|
return this->m_deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::setDeviceId(const std::string &deviceId)
|
||||||
|
{
|
||||||
|
this->m_deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::stopStreams()
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::serverStateChanged(IpcBridge::ServerState state)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->serverStateChanged(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::frameReady(const AkVCam::VideoFrame &frame)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->frameReady(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::setBroadcasting(const std::string &broadcaster)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->setBroadcasting(broadcaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::setMirror(bool horizontalMirror, bool verticalMirror)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->setMirror(horizontalMirror, verticalMirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::setScaling(Scaling scaling)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->setScaling(scaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::setAspectRatio(AspectRatio aspectRatio)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->setAspectRatio(aspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::setSwapRgb(bool swap)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->setSwapRgb(swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::suspend()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::resume()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::startStream(CMIOStreamID stream)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
UInt32 isRunning = 0;
|
||||||
|
this->m_properties.getProperty(kCMIODevicePropertyDeviceIsRunning,
|
||||||
|
&isRunning);
|
||||||
|
|
||||||
|
if (isRunning)
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!this->m_streams.count(stream))
|
||||||
|
return kCMIOHardwareNotRunningError;
|
||||||
|
|
||||||
|
if (!this->m_streams[stream]->start())
|
||||||
|
return kCMIOHardwareNotRunningError;
|
||||||
|
|
||||||
|
bool deviceRunning = true;
|
||||||
|
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
deviceRunning &= stream.second->running();
|
||||||
|
|
||||||
|
if (deviceRunning) {
|
||||||
|
this->m_properties.setProperty(kCMIODevicePropertyDeviceIsRunning,
|
||||||
|
UInt32(1));
|
||||||
|
auto address = this->address(kCMIODevicePropertyDeviceIsRunning);
|
||||||
|
this->propertyChanged(1, &address);
|
||||||
|
}
|
||||||
|
|
||||||
|
AKVCAM_EMIT(this, AddListener, this->m_deviceId)
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::stopStream(CMIOStreamID stream)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
UInt32 isRunning = 0;
|
||||||
|
this->m_properties.getProperty(kCMIODevicePropertyDeviceIsRunning,
|
||||||
|
&isRunning);
|
||||||
|
|
||||||
|
if (!isRunning)
|
||||||
|
return kCMIOHardwareNotRunningError;
|
||||||
|
|
||||||
|
if (!this->m_streams.count(stream))
|
||||||
|
return kCMIOHardwareNotRunningError;
|
||||||
|
|
||||||
|
this->m_streams[stream]->stop();
|
||||||
|
bool deviceRunning = false;
|
||||||
|
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
deviceRunning |= stream.second->running();
|
||||||
|
|
||||||
|
if (!deviceRunning) {
|
||||||
|
this->m_properties.setProperty(kCMIODevicePropertyDeviceIsRunning,
|
||||||
|
UInt32(0));
|
||||||
|
auto address = this->address(kCMIODevicePropertyDeviceIsRunning);
|
||||||
|
this->propertyChanged(1, &address);
|
||||||
|
}
|
||||||
|
|
||||||
|
AKVCAM_EMIT(this, RemoveListener, this->m_deviceId)
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::processAVCCommand(CMIODeviceAVCCommand *ioAVCCommand)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
UNUSED(ioAVCCommand)
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Device::processRS422Command(CMIODeviceRS422Command *ioRS422Command)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
UNUSED(ioRS422Command)
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::updateStreamsProperty()
|
||||||
|
{
|
||||||
|
std::vector<ObjectPtr> streams;
|
||||||
|
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
streams.push_back(stream.second);
|
||||||
|
|
||||||
|
this->m_properties.setProperty(kCMIODevicePropertyStreams, streams);
|
||||||
|
}
|
77
cmio/VirtualCamera/src/device.h
Normal file
77
cmio/VirtualCamera/src/device.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEVICE_H
|
||||||
|
#define DEVICE_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class Device;
|
||||||
|
typedef std::shared_ptr<Device> DevicePtr;
|
||||||
|
|
||||||
|
class Device: public Object
|
||||||
|
{
|
||||||
|
AKVCAM_SIGNAL(AddListener, const std::string &deviceId)
|
||||||
|
AKVCAM_SIGNAL(RemoveListener, const std::string &deviceId)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Device(CMIOHardwarePlugInRef pluginInterface,
|
||||||
|
bool createObject=false);
|
||||||
|
~Device();
|
||||||
|
|
||||||
|
OSStatus createObject();
|
||||||
|
OSStatus registerObject(bool regist=true);
|
||||||
|
StreamPtr addStream();
|
||||||
|
std::list<StreamPtr> addStreams(int n);
|
||||||
|
OSStatus registerStreams(bool regist=true);
|
||||||
|
std::string deviceId() const;
|
||||||
|
void setDeviceId(const std::string &deviceId);
|
||||||
|
void stopStreams();
|
||||||
|
|
||||||
|
void serverStateChanged(IpcBridge::ServerState state);
|
||||||
|
void frameReady(const VideoFrame &frame);
|
||||||
|
void setBroadcasting(const std::string &broadcaster);
|
||||||
|
void setMirror(bool horizontalMirror, bool verticalMirror);
|
||||||
|
void setScaling(Scaling scaling);
|
||||||
|
void setAspectRatio(AspectRatio aspectRatio);
|
||||||
|
void setSwapRgb(bool swap);
|
||||||
|
|
||||||
|
// Device Interface
|
||||||
|
OSStatus suspend();
|
||||||
|
OSStatus resume();
|
||||||
|
OSStatus startStream(CMIOStreamID stream);
|
||||||
|
OSStatus stopStream(CMIOStreamID stream);
|
||||||
|
OSStatus processAVCCommand(CMIODeviceAVCCommand *ioAVCCommand);
|
||||||
|
OSStatus processRS422Command(CMIODeviceRS422Command *ioRS422Command);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_deviceId;
|
||||||
|
std::map<CMIOObjectID, StreamPtr> m_streams;
|
||||||
|
|
||||||
|
void updateStreamsProperty();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_H
|
142
cmio/VirtualCamera/src/object.cpp
Normal file
142
cmio/VirtualCamera/src/object.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "object.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
AkVCam::Object::Object(CMIOHardwarePlugInRef pluginInterface,
|
||||||
|
Object *parent):
|
||||||
|
ObjectInterface(),
|
||||||
|
m_pluginInterface(pluginInterface),
|
||||||
|
m_parent(parent),
|
||||||
|
m_isCreated(false)
|
||||||
|
{
|
||||||
|
this->m_className = "Object";
|
||||||
|
this->m_properties.setProperty(kCMIOObjectPropertyOwnedObjects,
|
||||||
|
std::vector<Object *>());
|
||||||
|
this->m_properties.setProperty(kCMIOObjectPropertyListenerAdded,
|
||||||
|
this->address());
|
||||||
|
this->m_properties.setProperty(kCMIOObjectPropertyListenerRemoved,
|
||||||
|
this->address());
|
||||||
|
|
||||||
|
if (this->m_parent) {
|
||||||
|
this->m_parent->m_childs.push_back(this);
|
||||||
|
this->m_parent->childsUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Object::Object(Object *parent):
|
||||||
|
ObjectInterface(),
|
||||||
|
m_pluginInterface(parent? parent->m_pluginInterface: nullptr),
|
||||||
|
m_parent(parent),
|
||||||
|
m_isCreated(false)
|
||||||
|
{
|
||||||
|
this->m_className = "Object";
|
||||||
|
this->m_properties.setProperty(kCMIOObjectPropertyOwnedObjects,
|
||||||
|
std::vector<Object *>());
|
||||||
|
this->m_properties.setProperty(kCMIOObjectPropertyListenerAdded,
|
||||||
|
this->address());
|
||||||
|
this->m_properties.setProperty(kCMIOObjectPropertyListenerRemoved,
|
||||||
|
this->address());
|
||||||
|
|
||||||
|
if (this->m_parent) {
|
||||||
|
this->m_parent->m_childs.push_back(this);
|
||||||
|
this->m_parent->childsUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Object::~Object()
|
||||||
|
{
|
||||||
|
if (this->m_parent) {
|
||||||
|
this->m_parent->m_childs.remove(this);
|
||||||
|
this->m_parent->childsUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CMIOObjectID AkVCam::Object::objectID() const
|
||||||
|
{
|
||||||
|
return this->m_objectID;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32 AkVCam::Object::classID() const
|
||||||
|
{
|
||||||
|
return this->m_classID;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Object::createObject()
|
||||||
|
{
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Object::registerObject(bool regist)
|
||||||
|
{
|
||||||
|
UNUSED(regist)
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Object *AkVCam::Object::findObject(CMIOObjectID objectID)
|
||||||
|
{
|
||||||
|
if (this->m_objectID == objectID)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
for (auto child: this->m_childs)
|
||||||
|
if (auto object = child->findObject(objectID))
|
||||||
|
return object;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Object::propertyChanged(UInt32 numberAddresses,
|
||||||
|
const CMIOObjectPropertyAddress *addresses)
|
||||||
|
{
|
||||||
|
return CMIOObjectPropertiesChanged(this->m_pluginInterface,
|
||||||
|
this->m_objectID,
|
||||||
|
numberAddresses,
|
||||||
|
addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Object::setPropertyData(const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
auto status =
|
||||||
|
ObjectInterface::setPropertyData(address,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
dataSize,
|
||||||
|
data);
|
||||||
|
|
||||||
|
if (status == kCMIOHardwareUnspecifiedError)
|
||||||
|
status = this->propertyChanged(1, address);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Object::childsUpdate()
|
||||||
|
{
|
||||||
|
std::vector<Object *> objects;
|
||||||
|
|
||||||
|
for (auto &object: this->m_childs)
|
||||||
|
objects.push_back(object);
|
||||||
|
|
||||||
|
this->m_properties.setProperty(kCMIOObjectPropertyOwnedObjects, objects);
|
||||||
|
}
|
65
cmio/VirtualCamera/src/object.h
Normal file
65
cmio/VirtualCamera/src/object.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OBJECT_H
|
||||||
|
#define OBJECT_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "objectinterface.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class Object;
|
||||||
|
typedef std::shared_ptr<Object> ObjectPtr;
|
||||||
|
|
||||||
|
class Object: public ObjectInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Object(CMIOHardwarePlugInRef m_pluginInterface,
|
||||||
|
Object *m_parent=nullptr);
|
||||||
|
Object(Object *m_parent=nullptr);
|
||||||
|
virtual ~Object();
|
||||||
|
|
||||||
|
CMIOObjectID objectID() const;
|
||||||
|
UInt32 classID() const;
|
||||||
|
virtual OSStatus createObject();
|
||||||
|
virtual OSStatus registerObject(bool regist);
|
||||||
|
Object *findObject(CMIOObjectID objectID);
|
||||||
|
OSStatus propertyChanged(UInt32 numberAddresses,
|
||||||
|
const CMIOObjectPropertyAddress *addresses);
|
||||||
|
|
||||||
|
OSStatus setPropertyData(const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
const void *data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void childsUpdate();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CMIOHardwarePlugInRef m_pluginInterface;
|
||||||
|
Object *m_parent;
|
||||||
|
std::list<Object *> m_childs;
|
||||||
|
bool m_isCreated;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OBJECT_H
|
174
cmio/VirtualCamera/src/objectinterface.cpp
Normal file
174
cmio/VirtualCamera/src/objectinterface.cpp
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "objectinterface.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
AkVCam::ObjectInterface::ObjectInterface():
|
||||||
|
m_objectID(0),
|
||||||
|
m_classID(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ObjectInterface::~ObjectInterface()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ObjectProperties AkVCam::ObjectInterface::properties() const
|
||||||
|
{
|
||||||
|
return this->m_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ObjectProperties &AkVCam::ObjectInterface::properties()
|
||||||
|
{
|
||||||
|
return this->m_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ObjectInterface::setProperties(const ObjectProperties &properties)
|
||||||
|
{
|
||||||
|
this->m_properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ObjectInterface::updateProperties(const ObjectProperties &properties)
|
||||||
|
{
|
||||||
|
this->m_properties.update(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMIOObjectPropertyAddress AkVCam::ObjectInterface::address(CMIOObjectPropertySelector selector,
|
||||||
|
CMIOObjectPropertyScope scope,
|
||||||
|
CMIOObjectPropertyElement element)
|
||||||
|
{
|
||||||
|
return CMIOObjectPropertyAddress {selector, scope, element};
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ObjectInterface::show()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean AkVCam::ObjectInterface::hasProperty(const CMIOObjectPropertyAddress *address)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (!this->m_properties.getProperty(address->mSelector)) {
|
||||||
|
AkLoggerLog("Unknown property ", enumToString(address->mSelector));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkLoggerLog("Found property ", enumToString(address->mSelector));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::ObjectInterface::isPropertySettable(const CMIOObjectPropertyAddress *address,
|
||||||
|
Boolean *isSettable)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (!this->m_properties.getProperty(address->mSelector)) {
|
||||||
|
AkLoggerLog("Unknown property ", enumToString(address->mSelector));
|
||||||
|
|
||||||
|
return kCMIOHardwareUnknownPropertyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool settable = this->m_properties.isSettable(address->mSelector);
|
||||||
|
|
||||||
|
if (isSettable)
|
||||||
|
*isSettable = settable;
|
||||||
|
|
||||||
|
AkLoggerLog("Is property ",
|
||||||
|
enumToString(address->mSelector),
|
||||||
|
" settable? ",
|
||||||
|
(settable? "YES": "NO"));
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::ObjectInterface::getPropertyDataSize(const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 *dataSize)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
AkLoggerLog("Getting property size ", enumToString(address->mSelector));
|
||||||
|
|
||||||
|
if (!this->m_properties.getProperty(address->mSelector,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
0,
|
||||||
|
dataSize)) {
|
||||||
|
AkLoggerLog("Unknown property ", enumToString(address->mSelector));
|
||||||
|
|
||||||
|
return kCMIOHardwareUnknownPropertyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::ObjectInterface::getPropertyData(const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
UInt32 *dataUsed,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
AkLoggerLog("Getting property ", enumToString(address->mSelector));
|
||||||
|
|
||||||
|
if (!this->m_properties.getProperty(address->mSelector,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
dataSize,
|
||||||
|
dataUsed,
|
||||||
|
data)) {
|
||||||
|
AkLoggerLog("Unknown property ", enumToString(address->mSelector));
|
||||||
|
|
||||||
|
return kCMIOHardwareUnknownPropertyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::ObjectInterface::setPropertyData(const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
AkLoggerLog("Setting property ", enumToString(address->mSelector));
|
||||||
|
UNUSED(qualifierDataSize)
|
||||||
|
UNUSED(qualifierData)
|
||||||
|
|
||||||
|
if (!this->m_properties.setProperty(address->mSelector,
|
||||||
|
dataSize,
|
||||||
|
data)) {
|
||||||
|
AkLoggerLog("Unknown property ", enumToString(address->mSelector));
|
||||||
|
|
||||||
|
return kCMIOHardwareUnknownPropertyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
81
cmio/VirtualCamera/src/objectinterface.h
Normal file
81
cmio/VirtualCamera/src/objectinterface.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OBJECTINTERFACE_H
|
||||||
|
#define OBJECTINTERFACE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <CoreMediaIO/CMIOHardwarePlugIn.h>
|
||||||
|
|
||||||
|
#include "objectproperties.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AkObjectLogMethod() \
|
||||||
|
AkLoggerLog(this->m_className, \
|
||||||
|
"(", \
|
||||||
|
this->m_objectID, \
|
||||||
|
")::", \
|
||||||
|
__FUNCTION__, \
|
||||||
|
"()")
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class ObjectInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObjectInterface();
|
||||||
|
virtual ~ObjectInterface();
|
||||||
|
|
||||||
|
ObjectProperties properties() const;
|
||||||
|
ObjectProperties &properties();
|
||||||
|
void setProperties(const ObjectProperties &properties);
|
||||||
|
void updateProperties(const ObjectProperties &properties);
|
||||||
|
static CMIOObjectPropertyAddress address(CMIOObjectPropertySelector selector=0,
|
||||||
|
CMIOObjectPropertyScope scope=kCMIOObjectPropertyScopeGlobal,
|
||||||
|
CMIOObjectPropertyElement element=kCMIOObjectPropertyElementMaster);
|
||||||
|
|
||||||
|
virtual void show();
|
||||||
|
virtual Boolean hasProperty(const CMIOObjectPropertyAddress *address);
|
||||||
|
virtual OSStatus isPropertySettable(const CMIOObjectPropertyAddress *address,
|
||||||
|
Boolean *isSettable);
|
||||||
|
virtual OSStatus getPropertyDataSize(const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 *dataSize);
|
||||||
|
virtual OSStatus getPropertyData(const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
UInt32 *dataUsed,
|
||||||
|
void *data);
|
||||||
|
virtual OSStatus setPropertyData(const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
const void *data);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CMIOObjectID m_objectID;
|
||||||
|
std::string m_className;
|
||||||
|
UInt32 m_classID;
|
||||||
|
ObjectProperties m_properties;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OBJECTINTERFACE_H
|
743
cmio/VirtualCamera/src/objectproperties.cpp
Normal file
743
cmio/VirtualCamera/src/objectproperties.cpp
Normal file
|
@ -0,0 +1,743 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "object.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
enum PropertyType
|
||||||
|
{
|
||||||
|
PropertyTypeUInt32,
|
||||||
|
PropertyTypeFloat64,
|
||||||
|
PropertyTypePidT,
|
||||||
|
PropertyTypeString,
|
||||||
|
PropertyTypeWString,
|
||||||
|
PropertyTypeObjectVector,
|
||||||
|
PropertyTypeObjectPtrVector,
|
||||||
|
PropertyTypeVideoFormat,
|
||||||
|
PropertyTypeVideoFormatVector,
|
||||||
|
PropertyTypeFloat64Vector,
|
||||||
|
PropertyTypeAudioValueRangeVector,
|
||||||
|
PropertyTypeClock,
|
||||||
|
PropertyTypeAddress
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PropertyValue
|
||||||
|
{
|
||||||
|
PropertyType type;
|
||||||
|
bool isSettable;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
UInt32 uint32;
|
||||||
|
Float64 float64;
|
||||||
|
pid_t pidT;
|
||||||
|
} num;
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
std::wstring wstr;
|
||||||
|
std::vector<Object *> objects;
|
||||||
|
std::vector<ObjectPtr> objectsPtr;
|
||||||
|
std::vector<VideoFormat> videoFormats;
|
||||||
|
std::vector<Float64> float64Vector;
|
||||||
|
std::vector<AudioValueRange> audioValueRangeVector;
|
||||||
|
VideoFormat videoFormat;
|
||||||
|
ClockPtr clock;
|
||||||
|
CMIOObjectPropertyAddress address;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectPropertiesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::map<UInt32, PropertyValue> m_properties;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ObjectProperties::ObjectProperties()
|
||||||
|
{
|
||||||
|
this->d = new ObjectPropertiesPrivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ObjectProperties::ObjectProperties(const ObjectProperties &other)
|
||||||
|
{
|
||||||
|
this->d = new ObjectPropertiesPrivate();
|
||||||
|
this->d->m_properties = other.d->m_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ObjectProperties &AkVCam::ObjectProperties::operator =(const ObjectProperties &other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
this->d->m_properties = other.d->m_properties;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ObjectProperties::~ObjectProperties()
|
||||||
|
{
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<UInt32> AkVCam::ObjectProperties::properties() const
|
||||||
|
{
|
||||||
|
std::vector<UInt32> properties;
|
||||||
|
|
||||||
|
for (auto &property: this->d->m_properties)
|
||||||
|
properties.push_back(property.first);
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::string &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeString;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].str = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::wstring &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeWString;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].wstr = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
UInt32 value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeUInt32;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].num.uint32 = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
Float64 value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeFloat64;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].num.float64 = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
pid_t value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypePidT;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].num.pidT = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::vector<Object *> &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeObjectVector;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].objects = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::vector<ObjectPtr> &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeObjectPtrVector;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].objectsPtr = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const VideoFormat &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeVideoFormat;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].videoFormat = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::vector<VideoFormat> &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeVideoFormatVector;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].videoFormats = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::vector<Float64> &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeFloat64Vector;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].float64Vector = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::vector<Fraction> &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
std::vector<Float64> fvalue;
|
||||||
|
|
||||||
|
for (auto &v: value)
|
||||||
|
fvalue.push_back(v.value());
|
||||||
|
|
||||||
|
this->d->m_properties[property].type = PropertyTypeFloat64Vector;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].float64Vector = fvalue;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::vector<AudioValueRange> &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeAudioValueRangeVector;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].audioValueRangeVector = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const std::vector<FractionRange> &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
std::vector<AudioValueRange> valueRanges;
|
||||||
|
|
||||||
|
for (auto &range: value)
|
||||||
|
valueRanges.push_back({range.first.value(), range.second.value()});
|
||||||
|
|
||||||
|
return this->setProperty(property, valueRanges, isSettable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const ClockPtr &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeClock;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].clock = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
const CMIOObjectPropertyAddress &value,
|
||||||
|
bool isSettable)
|
||||||
|
{
|
||||||
|
this->d->m_properties[property].type = PropertyTypeAddress;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].address = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::setProperty(UInt32 property,
|
||||||
|
UInt32 dataSize,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
if (!this->d->m_properties.count(property))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool isSettable = this->d->m_properties[property].isSettable;
|
||||||
|
|
||||||
|
if (!isSettable)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto propertyType = this->d->m_properties[property].type;
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
switch (propertyType) {
|
||||||
|
case PropertyTypeAddress:
|
||||||
|
if (dataSize == sizeof(CMIOObjectPropertyAddress)) {
|
||||||
|
this->d->m_properties[property].type = PropertyTypeAddress;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].address =
|
||||||
|
*static_cast<const CMIOObjectPropertyAddress *>(data);
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypeVideoFormat:
|
||||||
|
if (dataSize == sizeof(CMFormatDescriptionRef)) {
|
||||||
|
this->d->m_properties[property].type = PropertyTypeVideoFormat;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
auto videoDescription =
|
||||||
|
*static_cast<const CMFormatDescriptionRef *>(data);
|
||||||
|
auto mediaType = CMFormatDescriptionGetMediaSubType(videoDescription);
|
||||||
|
auto dimensions = CMVideoFormatDescriptionGetDimensions(videoDescription);
|
||||||
|
this->d->m_properties[property].videoFormat =
|
||||||
|
VideoFormat(formatFromCM(mediaType),
|
||||||
|
dimensions.width,
|
||||||
|
dimensions.height);
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypeUInt32:
|
||||||
|
if (dataSize == sizeof(UInt32)) {
|
||||||
|
this->d->m_properties[property].type = PropertyTypeUInt32;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].num.uint32 =
|
||||||
|
*static_cast<const UInt32 *>(data);
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypeFloat64:
|
||||||
|
if (dataSize == sizeof(Float64)) {
|
||||||
|
this->d->m_properties[property].type = PropertyTypeFloat64;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].num.float64 =
|
||||||
|
*static_cast<const Float64 *>(data);
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypePidT:
|
||||||
|
if (dataSize == sizeof(pid_t)) {
|
||||||
|
this->d->m_properties[property].type = PropertyTypePidT;
|
||||||
|
this->d->m_properties[property].isSettable = isSettable;
|
||||||
|
this->d->m_properties[property].num.pidT =
|
||||||
|
*static_cast<const pid_t *>(data);
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::getProperty(UInt32 property, UInt32 *value)
|
||||||
|
{
|
||||||
|
if (!value || !this->d->m_properties.count(property))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto propertyType = this->d->m_properties[property].type;
|
||||||
|
|
||||||
|
if (propertyType != PropertyTypeUInt32)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*value = this->d->m_properties[property].num.uint32;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::getProperty(UInt32 property, Float64 *value)
|
||||||
|
{
|
||||||
|
if (!value || !this->d->m_properties.count(property))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto propertyType = this->d->m_properties[property].type;
|
||||||
|
|
||||||
|
if (propertyType != PropertyTypeFloat64)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*value = this->d->m_properties[property].num.float64;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::getProperty(UInt32 property, std::string *value)
|
||||||
|
{
|
||||||
|
if (!value || !this->d->m_properties.count(property))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto propertyType = this->d->m_properties[property].type;
|
||||||
|
|
||||||
|
if (propertyType != PropertyTypeString)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*value = this->d->m_properties[property].str;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::getProperty(UInt32 property,
|
||||||
|
AkVCam::VideoFormat *value)
|
||||||
|
{
|
||||||
|
if (!value || !this->d->m_properties.count(property))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto propertyType = this->d->m_properties[property].type;
|
||||||
|
|
||||||
|
if (propertyType != PropertyTypeVideoFormat)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*value = this->d->m_properties[property].videoFormat;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::getProperty(UInt32 property,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
UInt32 *dataUsed,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
if (!this->d->m_properties.count(property))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
auto propertyType = this->d->m_properties[property].type;
|
||||||
|
|
||||||
|
switch (propertyType) {
|
||||||
|
case PropertyTypeString:
|
||||||
|
if (dataUsed) {
|
||||||
|
*dataUsed = sizeof(CFStringRef);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
ok = dataSize == *dataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && data) {
|
||||||
|
auto value = this->d->m_properties[property].str;
|
||||||
|
*static_cast<CFStringRef *>(data) =
|
||||||
|
CFStringCreateWithCString(kCFAllocatorDefault,
|
||||||
|
value.c_str(),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypeWString:
|
||||||
|
if (dataUsed) {
|
||||||
|
*dataUsed = sizeof(CFStringRef);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
ok = dataSize == *dataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && data) {
|
||||||
|
auto value = this->d->m_properties[property].wstr;
|
||||||
|
*static_cast<CFStringRef *>(data) =
|
||||||
|
CFStringCreateWithBytes(kCFAllocatorDefault,
|
||||||
|
reinterpret_cast<const UInt8 *>(value.c_str()),
|
||||||
|
CFIndex(value.size() * sizeof(wchar_t)),
|
||||||
|
kCFStringEncodingUTF32LE,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypeObjectVector: {
|
||||||
|
auto &objects = this->d->m_properties[property].objects;
|
||||||
|
auto objectList = static_cast<CMIOObjectID *>(data);
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (auto &object: objects) {
|
||||||
|
if (qualify(property,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
object)) {
|
||||||
|
if (data)
|
||||||
|
objectList[i] = object->objectID();
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataUsed)
|
||||||
|
*dataUsed = UInt32(i * sizeof(CMIOObjectID));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PropertyTypeObjectPtrVector: {
|
||||||
|
auto &objects = this->d->m_properties[property].objectsPtr;
|
||||||
|
auto objectList = static_cast<CMIOObjectID *>(data);
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (auto &object: objects) {
|
||||||
|
if (qualify(property,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
&object)) {
|
||||||
|
if (data)
|
||||||
|
objectList[i] = object->objectID();
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataUsed)
|
||||||
|
*dataUsed = UInt32(i * sizeof(CMIOObjectID));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PropertyTypeVideoFormat: {
|
||||||
|
if (dataUsed) {
|
||||||
|
*dataUsed = sizeof(CMFormatDescriptionRef);
|
||||||
|
ok = dataSize == *dataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && data) {
|
||||||
|
auto videoFormat = this->d->m_properties[property].videoFormat;
|
||||||
|
auto status =
|
||||||
|
CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
|
||||||
|
formatToCM(PixelFormat(videoFormat.fourcc())),
|
||||||
|
videoFormat.width(),
|
||||||
|
videoFormat.height(),
|
||||||
|
nullptr,
|
||||||
|
static_cast<CMFormatDescriptionRef *>(data));
|
||||||
|
|
||||||
|
if (status != noErr)
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PropertyTypeVideoFormatVector: {
|
||||||
|
if (dataUsed) {
|
||||||
|
*dataUsed = sizeof(CFArrayRef);
|
||||||
|
ok = dataSize == *dataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && data) {
|
||||||
|
auto videoFormats = this->d->m_properties[property].videoFormats;
|
||||||
|
std::vector<CMFormatDescriptionRef> formats;
|
||||||
|
|
||||||
|
for (auto &format: videoFormats) {
|
||||||
|
CMFormatDescriptionRef formatRef = nullptr;
|
||||||
|
auto status =
|
||||||
|
CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
|
||||||
|
formatToCM(PixelFormat(format.fourcc())),
|
||||||
|
format.width(),
|
||||||
|
format.height(),
|
||||||
|
nullptr,
|
||||||
|
&formatRef);
|
||||||
|
|
||||||
|
if (status == noErr)
|
||||||
|
formats.push_back(formatRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFArrayRef array = nullptr;
|
||||||
|
|
||||||
|
if (!formats.empty())
|
||||||
|
array = CFArrayCreate(kCFAllocatorDefault,
|
||||||
|
reinterpret_cast<const void **>(formats.data()),
|
||||||
|
UInt32(formats.size()),
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
*static_cast<CFArrayRef *>(data) = array;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PropertyTypeFloat64Vector: {
|
||||||
|
auto &values = this->d->m_properties[property].float64Vector;
|
||||||
|
auto valueList = static_cast<Float64 *>(data);
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (auto &value: values) {
|
||||||
|
if (qualify(property,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
&value)) {
|
||||||
|
if (data)
|
||||||
|
valueList[i] = value;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataUsed)
|
||||||
|
*dataUsed = UInt32(i * sizeof(Float64));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PropertyTypeAudioValueRangeVector: {
|
||||||
|
auto &values = this->d->m_properties[property].audioValueRangeVector;
|
||||||
|
auto valueList = static_cast<AudioValueRange *>(data);
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (auto &value: values) {
|
||||||
|
if (qualify(property,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
&value)) {
|
||||||
|
if (data)
|
||||||
|
valueList[i] = value;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataUsed)
|
||||||
|
*dataUsed = UInt32(i * sizeof(AudioValueRange));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PropertyTypeClock:
|
||||||
|
if (dataUsed) {
|
||||||
|
*dataUsed = sizeof(CFTypeRef);
|
||||||
|
ok = dataSize == *dataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && data) {
|
||||||
|
auto value = this->d->m_properties[property].clock;
|
||||||
|
*static_cast<CFTypeRef *>(data) = value->ref();
|
||||||
|
CFRetain(value->ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypeUInt32:
|
||||||
|
if (dataUsed) {
|
||||||
|
*dataUsed = sizeof(UInt32);
|
||||||
|
ok = dataSize == *dataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && data) {
|
||||||
|
auto value = this->d->m_properties[property].num.uint32;
|
||||||
|
*static_cast<UInt32 *>(data) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypeFloat64:
|
||||||
|
if (dataUsed) {
|
||||||
|
*dataUsed = sizeof(Float64);
|
||||||
|
ok = dataSize == *dataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && data) {
|
||||||
|
auto value = this->d->m_properties[property].num.float64;
|
||||||
|
*static_cast<Float64 *>(data) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyTypePidT:
|
||||||
|
if (dataUsed) {
|
||||||
|
*dataUsed = sizeof(pid_t);
|
||||||
|
ok = dataSize == *dataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && data) {
|
||||||
|
auto value = this->d->m_properties[property].num.pidT;
|
||||||
|
*static_cast<pid_t *>(data) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ObjectProperties::removeProperty(UInt32 property)
|
||||||
|
{
|
||||||
|
this->d->m_properties.erase(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ObjectProperties::update(const ObjectProperties &other)
|
||||||
|
{
|
||||||
|
for (auto &property: other.d->m_properties)
|
||||||
|
this->d->m_properties[property.first] = property.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::isSettable(UInt32 property)
|
||||||
|
{
|
||||||
|
if (this->d->m_properties.count(property))
|
||||||
|
return this->d->m_properties[property].isSettable;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ObjectProperties::qualify(UInt32 property,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
if (qualifierDataSize && qualifierData && data)
|
||||||
|
switch (property) {
|
||||||
|
case kCMIOObjectPropertyOwnedObjects: {
|
||||||
|
auto object = static_cast<const Object *>(data);
|
||||||
|
auto qualifier = static_cast<const UInt32 *>(qualifierData);
|
||||||
|
|
||||||
|
for (UInt32 i = 0; i < qualifierDataSize; i++)
|
||||||
|
if (qualifier[i] == object->classID())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case kCMIOStreamPropertyFrameRates:
|
||||||
|
case kCMIOStreamPropertyFrameRateRanges:
|
||||||
|
// Not implemented.
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
129
cmio/VirtualCamera/src/objectproperties.h
Normal file
129
cmio/VirtualCamera/src/objectproperties.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OBJECTPROPERTIES_H
|
||||||
|
#define OBJECTPROPERTIES_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <CoreMediaIO/CMIOHardwareObject.h>
|
||||||
|
#include <CoreAudio/CoreAudioTypes.h>
|
||||||
|
|
||||||
|
#include "clock.h"
|
||||||
|
#include "VCamUtils/src/fraction.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class ObjectPropertiesPrivate;
|
||||||
|
class Object;
|
||||||
|
class VideoFormat;
|
||||||
|
typedef std::shared_ptr<Object> ObjectPtr;
|
||||||
|
|
||||||
|
class ObjectProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObjectProperties();
|
||||||
|
ObjectProperties(const ObjectProperties &other);
|
||||||
|
ObjectProperties &operator =(const ObjectProperties &other);
|
||||||
|
virtual ~ObjectProperties();
|
||||||
|
|
||||||
|
std::vector<UInt32> properties() const;
|
||||||
|
|
||||||
|
// Set properties
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::string &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::wstring &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
UInt32 value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
Float64 value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
pid_t value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::vector<Object *> &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::vector<ObjectPtr> &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const VideoFormat &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::vector<VideoFormat> &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::vector<Float64> &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::vector<Fraction> &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::vector<AudioValueRange> &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const std::vector<FractionRange> &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const ClockPtr &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
const CMIOObjectPropertyAddress &value,
|
||||||
|
bool isSettable=true);
|
||||||
|
bool setProperty(UInt32 property,
|
||||||
|
UInt32 dataSize,
|
||||||
|
const void *data);
|
||||||
|
|
||||||
|
// Get properties
|
||||||
|
bool getProperty(UInt32 property,
|
||||||
|
UInt32 *value);
|
||||||
|
bool getProperty(UInt32 property,
|
||||||
|
Float64 *value);
|
||||||
|
bool getProperty(UInt32 property,
|
||||||
|
std::string *value);
|
||||||
|
bool getProperty(UInt32 property,
|
||||||
|
VideoFormat *value);
|
||||||
|
bool getProperty(UInt32 property,
|
||||||
|
UInt32 qualifierDataSize=0,
|
||||||
|
const void *qualifierData=nullptr,
|
||||||
|
UInt32 dataSize=0,
|
||||||
|
UInt32 *dataUsed=nullptr,
|
||||||
|
void *data=nullptr);
|
||||||
|
|
||||||
|
void removeProperty(UInt32 property);
|
||||||
|
void update(const ObjectProperties &other);
|
||||||
|
bool isSettable(UInt32 property);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ObjectPropertiesPrivate *d;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool qualify(UInt32 property,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
const void *data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OBJECTPROPERTIES_H
|
42
cmio/VirtualCamera/src/plugin.cpp
Normal file
42
cmio/VirtualCamera/src/plugin.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
extern "C" void *akPluginMain(CFAllocatorRef allocator,
|
||||||
|
CFUUIDRef requestedTypeUUID)
|
||||||
|
{
|
||||||
|
UNUSED(allocator)
|
||||||
|
|
||||||
|
#if defined(QT_DEBUG) && 0
|
||||||
|
// Turn on lights
|
||||||
|
freopen("/dev/tty", "a", stdout);
|
||||||
|
freopen("/dev/tty", "a", stderr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AkLoggerStart("/tmp/" CMIO_PLUGIN_NAME, "log");
|
||||||
|
|
||||||
|
if (!CFEqual(requestedTypeUUID, kCMIOHardwarePlugInTypeID))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return AkVCam::PluginInterface::create();
|
||||||
|
}
|
25
cmio/VirtualCamera/src/plugin.h
Normal file
25
cmio/VirtualCamera/src/plugin.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLUGIN_H
|
||||||
|
#define PLUGIN_H
|
||||||
|
|
||||||
|
#include "plugininterface.h"
|
||||||
|
|
||||||
|
#endif // PLUGIN_H
|
972
cmio/VirtualCamera/src/plugininterface.cpp
Normal file
972
cmio/VirtualCamera/src/plugininterface.cpp
Normal file
|
@ -0,0 +1,972 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <IOKit/audio/IOAudioTypes.h>
|
||||||
|
|
||||||
|
#include "plugininterface.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "Assistant/src/assistantglobals.h"
|
||||||
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
#define AkPluginPrivateIntefaceLog() \
|
||||||
|
AkLoggerLog("PluginInterfacePrivate::", __FUNCTION__, "()")
|
||||||
|
|
||||||
|
#define AkPluginPrivateIntefaceLogID(x) \
|
||||||
|
AkLoggerLog("PluginInterfacePrivate::", __FUNCTION__, "(id = ", x, ")")
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
struct PluginInterfacePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CMIOHardwarePlugInInterface *pluginInterface;
|
||||||
|
PluginInterface *self;
|
||||||
|
ULONG m_ref;
|
||||||
|
ULONG m_reserved;
|
||||||
|
IpcBridge m_ipcBridge;
|
||||||
|
|
||||||
|
void updateDevices();
|
||||||
|
static HRESULT QueryInterface(void *self,
|
||||||
|
REFIID uuid,
|
||||||
|
LPVOID *interface);
|
||||||
|
static ULONG AddRef(void *self);
|
||||||
|
static ULONG Release(void *self);
|
||||||
|
static OSStatus Initialize(CMIOHardwarePlugInRef self);
|
||||||
|
static OSStatus InitializeWithObjectID(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID);
|
||||||
|
static OSStatus Teardown(CMIOHardwarePlugInRef self);
|
||||||
|
static void ObjectShow(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID);
|
||||||
|
static Boolean ObjectHasProperty(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address);
|
||||||
|
static OSStatus ObjectIsPropertySettable(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address,
|
||||||
|
Boolean *isSettable);
|
||||||
|
static OSStatus ObjectGetPropertyDataSize(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 *dataSize);
|
||||||
|
static OSStatus ObjectGetPropertyData(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
UInt32 *dataUsed,
|
||||||
|
void *data);
|
||||||
|
static OSStatus ObjectSetPropertyData(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
const void *data);
|
||||||
|
static OSStatus DeviceSuspend(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device);
|
||||||
|
static OSStatus DeviceResume(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device);
|
||||||
|
static OSStatus DeviceStartStream(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device,
|
||||||
|
CMIOStreamID stream);
|
||||||
|
static OSStatus DeviceStopStream(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device,
|
||||||
|
CMIOStreamID stream);
|
||||||
|
static OSStatus DeviceProcessAVCCommand(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device,
|
||||||
|
CMIODeviceAVCCommand *ioAVCCommand);
|
||||||
|
static OSStatus DeviceProcessRS422Command(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device,
|
||||||
|
CMIODeviceRS422Command *ioRS422Command);
|
||||||
|
static OSStatus StreamCopyBufferQueue(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream,
|
||||||
|
CMIODeviceStreamQueueAlteredProc queueAlteredProc,
|
||||||
|
void *queueAlteredRefCon,
|
||||||
|
CMSimpleQueueRef *queue);
|
||||||
|
static OSStatus StreamDeckPlay(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream);
|
||||||
|
static OSStatus StreamDeckStop(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream);
|
||||||
|
static OSStatus StreamDeckJog(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream,
|
||||||
|
SInt32 speed);
|
||||||
|
static OSStatus StreamDeckCueTo(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream,
|
||||||
|
Float64 frameNumber,
|
||||||
|
Boolean playOnCue);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::PluginInterface::PluginInterface():
|
||||||
|
ObjectInterface(),
|
||||||
|
m_objectID(0)
|
||||||
|
{
|
||||||
|
this->m_className = "PluginInterface";
|
||||||
|
this->d = new PluginInterfacePrivate;
|
||||||
|
this->d->self = this;
|
||||||
|
this->d->pluginInterface = new CMIOHardwarePlugInInterface {
|
||||||
|
// Padding for COM
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
// IUnknown Routines
|
||||||
|
PluginInterfacePrivate::QueryInterface,
|
||||||
|
PluginInterfacePrivate::AddRef,
|
||||||
|
PluginInterfacePrivate::Release,
|
||||||
|
|
||||||
|
// DAL Plug-In Routines
|
||||||
|
PluginInterfacePrivate::Initialize,
|
||||||
|
PluginInterfacePrivate::InitializeWithObjectID,
|
||||||
|
PluginInterfacePrivate::Teardown,
|
||||||
|
PluginInterfacePrivate::ObjectShow,
|
||||||
|
PluginInterfacePrivate::ObjectHasProperty,
|
||||||
|
PluginInterfacePrivate::ObjectIsPropertySettable,
|
||||||
|
PluginInterfacePrivate::ObjectGetPropertyDataSize,
|
||||||
|
PluginInterfacePrivate::ObjectGetPropertyData,
|
||||||
|
PluginInterfacePrivate::ObjectSetPropertyData,
|
||||||
|
PluginInterfacePrivate::DeviceSuspend,
|
||||||
|
PluginInterfacePrivate::DeviceResume,
|
||||||
|
PluginInterfacePrivate::DeviceStartStream,
|
||||||
|
PluginInterfacePrivate::DeviceStopStream,
|
||||||
|
PluginInterfacePrivate::DeviceProcessAVCCommand,
|
||||||
|
PluginInterfacePrivate::DeviceProcessRS422Command,
|
||||||
|
PluginInterfacePrivate::StreamCopyBufferQueue,
|
||||||
|
PluginInterfacePrivate::StreamDeckPlay,
|
||||||
|
PluginInterfacePrivate::StreamDeckStop,
|
||||||
|
PluginInterfacePrivate::StreamDeckJog,
|
||||||
|
PluginInterfacePrivate::StreamDeckCueTo
|
||||||
|
};
|
||||||
|
this->d->m_ref = 0;
|
||||||
|
this->d->m_reserved = 0;
|
||||||
|
|
||||||
|
auto homePath = std::string("/Users/") + getenv("USER");
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << CMIO_DAEMONS_PATH << "/" << AKVCAM_ASSISTANT_NAME << ".plist";
|
||||||
|
auto daemon = ss.str();
|
||||||
|
|
||||||
|
if (daemon[0] == '~')
|
||||||
|
daemon.replace(0, 1, homePath);
|
||||||
|
|
||||||
|
struct stat fileInfo;
|
||||||
|
|
||||||
|
if (stat(daemon.c_str(), &fileInfo) == 0)
|
||||||
|
this->d->m_ipcBridge.connectService(true);
|
||||||
|
|
||||||
|
this->d->m_ipcBridge.connectServerStateChanged(this, &PluginInterface::serverStateChanged);
|
||||||
|
this->d->m_ipcBridge.connectDeviceAdded(this, &PluginInterface::deviceAdded);
|
||||||
|
this->d->m_ipcBridge.connectDeviceRemoved(this, &PluginInterface::deviceRemoved);
|
||||||
|
this->d->m_ipcBridge.connectFrameReady(this, &PluginInterface::frameReady);
|
||||||
|
this->d->m_ipcBridge.connectBroadcastingChanged(this, &PluginInterface::setBroadcasting);
|
||||||
|
this->d->m_ipcBridge.connectMirrorChanged(this, &PluginInterface::setMirror);
|
||||||
|
this->d->m_ipcBridge.connectScalingChanged(this, &PluginInterface::setScaling);
|
||||||
|
this->d->m_ipcBridge.connectAspectRatioChanged(this, &PluginInterface::setAspectRatio);
|
||||||
|
this->d->m_ipcBridge.connectSwapRgbChanged(this, &PluginInterface::setSwapRgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::PluginInterface::~PluginInterface()
|
||||||
|
{
|
||||||
|
this->d->m_ipcBridge.disconnectService();
|
||||||
|
delete this->d->pluginInterface;
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMIOObjectID AkVCam::PluginInterface::objectID() const
|
||||||
|
{
|
||||||
|
return this->m_objectID;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMIOHardwarePlugInRef AkVCam::PluginInterface::create()
|
||||||
|
{
|
||||||
|
AkLoggerLog("Creating plugin interface.");
|
||||||
|
|
||||||
|
auto pluginInterface = new PluginInterface();
|
||||||
|
pluginInterface->d->AddRef(pluginInterface->d);
|
||||||
|
|
||||||
|
return reinterpret_cast<CMIOHardwarePlugInRef>(pluginInterface->d);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Object *AkVCam::PluginInterface::findObject(CMIOObjectID objectID)
|
||||||
|
{
|
||||||
|
for (auto device: this->m_devices)
|
||||||
|
if (auto object = device->findObject(objectID))
|
||||||
|
return object;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::PluginInterface::QueryInterface(REFIID uuid, LPVOID *interface)
|
||||||
|
{
|
||||||
|
if (!interface)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::QueryInterface");
|
||||||
|
|
||||||
|
if (uuidEqual(uuid, kCMIOHardwarePlugInInterfaceID)
|
||||||
|
|| uuidEqual(uuid, IUnknownUUID)) {
|
||||||
|
AkLoggerLog("Found plugin interface.");
|
||||||
|
this->d->AddRef(this->d);
|
||||||
|
*interface = this->d;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterface::Initialize()
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::Initialize");
|
||||||
|
|
||||||
|
return this->InitializeWithObjectID(kCMIOObjectUnknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterface::InitializeWithObjectID(CMIOObjectID objectID)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::InitializeWithObjectID: ", objectID);
|
||||||
|
|
||||||
|
this->m_objectID = objectID;
|
||||||
|
|
||||||
|
#if defined(QT_DEBUG) && 0
|
||||||
|
std::vector<VideoFormat> formats {
|
||||||
|
{PixelFormatRGB32, 640, 480, {30.0}}
|
||||||
|
};
|
||||||
|
|
||||||
|
this->createDevice("org.webcamoid.cmio.AkVCam.Driver.Debug",
|
||||||
|
"Virtual Debug Camera (driver side)",
|
||||||
|
formats);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (auto deviceId: this->d->m_ipcBridge.listDevices())
|
||||||
|
this->deviceAdded(this, deviceId);
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterface::Teardown()
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::Teardown");
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::serverStateChanged(void *userData,
|
||||||
|
IpcBridge::ServerState state)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::frameReady");
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
|
for (auto device: self->m_devices)
|
||||||
|
device->serverStateChanged(state);
|
||||||
|
|
||||||
|
if (state == IpcBridge::ServerStateAvailable)
|
||||||
|
self->d->updateDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::deviceAdded(void *userData,
|
||||||
|
const std::string &deviceId)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::deviceAdded");
|
||||||
|
AkLoggerLog("Device Added: ", deviceId);
|
||||||
|
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
auto description = self->d->m_ipcBridge.description(deviceId);
|
||||||
|
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
||||||
|
|
||||||
|
self->createDevice(deviceId, description, formats);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::deviceRemoved(void *userData,
|
||||||
|
const std::string &deviceId)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::deviceRemoved");
|
||||||
|
AkLoggerLog("Device Removed: ", deviceId);
|
||||||
|
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
self->destroyDevice(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::frameReady(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const VideoFrame &frame)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::frameReady");
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
|
for (auto device: self->m_devices)
|
||||||
|
if (device->deviceId() == deviceId)
|
||||||
|
device->frameReady(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::setBroadcasting(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const std::string &broadcaster)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::setBroadcasting");
|
||||||
|
AkLoggerLog("Device: ", deviceId);
|
||||||
|
AkLoggerLog("Broadcaster: ", broadcaster);
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
|
for (auto device: self->m_devices)
|
||||||
|
if (device->deviceId() == deviceId)
|
||||||
|
device->setBroadcasting(broadcaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::setMirror(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool horizontalMirror,
|
||||||
|
bool verticalMirror)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::setMirror");
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
|
for (auto device: self->m_devices)
|
||||||
|
if (device->deviceId() == deviceId)
|
||||||
|
device->setMirror(horizontalMirror, verticalMirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::setScaling(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
Scaling scaling)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::setScaling");
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
|
for (auto device: self->m_devices)
|
||||||
|
if (device->deviceId() == deviceId)
|
||||||
|
device->setScaling(scaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::setAspectRatio(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
AspectRatio aspectRatio)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::setAspectRatio");
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
|
for (auto device: self->m_devices)
|
||||||
|
if (device->deviceId() == deviceId)
|
||||||
|
device->setAspectRatio(aspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::setSwapRgb(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool swap)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::setSwapRgb");
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
|
for (auto device: self->m_devices)
|
||||||
|
if (device->deviceId() == deviceId)
|
||||||
|
device->setSwapRgb(swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::addListener(void *userData,
|
||||||
|
const std::string &deviceId)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::addListener");
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
self->d->m_ipcBridge.addListener(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::removeListener(void *userData,
|
||||||
|
const std::string &deviceId)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::removeListener");
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
self->d->m_ipcBridge.removeListener(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::PluginInterface::createDevice(const std::string &deviceId,
|
||||||
|
const std::wstring &description,
|
||||||
|
const std::vector<VideoFormat> &formats)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::createDevice");
|
||||||
|
|
||||||
|
StreamPtr stream;
|
||||||
|
|
||||||
|
// Create one device.
|
||||||
|
auto pluginRef = reinterpret_cast<CMIOHardwarePlugInRef>(this->d);
|
||||||
|
auto device = std::make_shared<Device>(pluginRef);
|
||||||
|
device->setDeviceId(deviceId);
|
||||||
|
device->connectAddListener(this, &PluginInterface::addListener);
|
||||||
|
device->connectRemoveListener(this, &PluginInterface::removeListener);
|
||||||
|
this->m_devices.push_back(device);
|
||||||
|
|
||||||
|
// Define device properties.
|
||||||
|
device->properties().setProperty(kCMIOObjectPropertyName,
|
||||||
|
description.c_str());
|
||||||
|
device->properties().setProperty(kCMIOObjectPropertyManufacturer,
|
||||||
|
CMIO_PLUGIN_VENDOR);
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyModelUID,
|
||||||
|
CMIO_PLUGIN_PRODUCT);
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyLinkedCoreAudioDeviceUID,
|
||||||
|
"");
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyLinkedAndSyncedCoreAudioDeviceUID,
|
||||||
|
"");
|
||||||
|
device->properties().setProperty(kCMIODevicePropertySuspendedByUser,
|
||||||
|
UInt32(0));
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyHogMode,
|
||||||
|
pid_t(-1),
|
||||||
|
false);
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyDeviceMaster,
|
||||||
|
pid_t(-1));
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyExcludeNonDALAccess,
|
||||||
|
UInt32(0));
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyDeviceIsAlive,
|
||||||
|
UInt32(1));
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyDeviceUID,
|
||||||
|
deviceId.c_str());
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyTransportType,
|
||||||
|
UInt32(kIOAudioDeviceTransportTypePCI));
|
||||||
|
device->properties().setProperty(kCMIODevicePropertyDeviceIsRunningSomewhere,
|
||||||
|
UInt32(0));
|
||||||
|
|
||||||
|
if (device->createObject() != kCMIOHardwareNoError)
|
||||||
|
goto createDevice_failed;
|
||||||
|
|
||||||
|
stream = device->addStream();
|
||||||
|
|
||||||
|
// Register one stream for this device.
|
||||||
|
if (!stream)
|
||||||
|
goto createDevice_failed;
|
||||||
|
|
||||||
|
stream->setFormats(formats);
|
||||||
|
stream->properties().setProperty(kCMIOStreamPropertyDirection, UInt32(0));
|
||||||
|
|
||||||
|
if (device->registerStreams() != kCMIOHardwareNoError) {
|
||||||
|
device->registerStreams(false);
|
||||||
|
|
||||||
|
goto createDevice_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the device.
|
||||||
|
if (device->registerObject() != kCMIOHardwareNoError) {
|
||||||
|
device->registerObject(false);
|
||||||
|
device->registerStreams(false);
|
||||||
|
|
||||||
|
goto createDevice_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->setBroadcasting(this->d->m_ipcBridge.broadcaster(deviceId));
|
||||||
|
device->setMirror(this->d->m_ipcBridge.isHorizontalMirrored(deviceId),
|
||||||
|
this->d->m_ipcBridge.isVerticalMirrored(deviceId));
|
||||||
|
device->setScaling(this->d->m_ipcBridge.scalingMode(deviceId));
|
||||||
|
device->setAspectRatio(this->d->m_ipcBridge.aspectRatioMode(deviceId));
|
||||||
|
device->setSwapRgb(this->d->m_ipcBridge.swapRgb(deviceId));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
createDevice_failed:
|
||||||
|
this->m_devices.erase(std::prev(this->m_devices.end()));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::destroyDevice(const std::string &deviceId)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::PluginInterface::destroyDevice");
|
||||||
|
|
||||||
|
for (auto it = this->m_devices.begin(); it != this->m_devices.end(); it++) {
|
||||||
|
auto device = *it;
|
||||||
|
|
||||||
|
std::string curDeviceId;
|
||||||
|
device->properties().getProperty(kCMIODevicePropertyDeviceUID,
|
||||||
|
&curDeviceId);
|
||||||
|
|
||||||
|
if (curDeviceId == deviceId) {
|
||||||
|
device->stopStreams();
|
||||||
|
device->registerObject(false);
|
||||||
|
device->registerStreams(false);
|
||||||
|
this->m_devices.erase(it);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterfacePrivate::updateDevices()
|
||||||
|
{
|
||||||
|
for (auto &device: this->self->m_devices) {
|
||||||
|
device->setBroadcasting(this->m_ipcBridge.broadcaster(device->deviceId()));
|
||||||
|
device->setMirror(this->m_ipcBridge.isHorizontalMirrored(device->deviceId()),
|
||||||
|
this->m_ipcBridge.isVerticalMirrored(device->deviceId()));
|
||||||
|
device->setScaling(this->m_ipcBridge.scalingMode(device->deviceId()));
|
||||||
|
device->setAspectRatio(this->m_ipcBridge.aspectRatioMode(device->deviceId()));
|
||||||
|
device->setSwapRgb(this->m_ipcBridge.swapRgb(device->deviceId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::PluginInterfacePrivate::QueryInterface(void *self,
|
||||||
|
REFIID uuid,
|
||||||
|
LPVOID *interface)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLog();
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
return _self->self->QueryInterface(uuid, interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AkVCam::PluginInterfacePrivate::AddRef(void *self)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLog();
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
_self->m_ref++;
|
||||||
|
|
||||||
|
return _self->m_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AkVCam::PluginInterfacePrivate::Release(void *self)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLog();
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
if (_self->m_ref > 0) {
|
||||||
|
_self->m_ref--;
|
||||||
|
|
||||||
|
if (_self->m_ref < 1) {
|
||||||
|
delete _self->self;
|
||||||
|
|
||||||
|
return 0UL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _self->m_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::Initialize(CMIOHardwarePlugInRef self)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLog();
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
return _self->self->Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::InitializeWithObjectID(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLog();
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
return _self->self->InitializeWithObjectID(objectID);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::Teardown(CMIOHardwarePlugInRef self)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLog();
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
return _self->self->Teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterfacePrivate::ObjectShow(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(objectID);
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
if (_self->self->objectID() == objectID)
|
||||||
|
_self->self->show();
|
||||||
|
else if (auto object = _self->self->findObject(objectID))
|
||||||
|
object->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean AkVCam::PluginInterfacePrivate::ObjectHasProperty(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(objectID);
|
||||||
|
Boolean result = false;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
if (_self->self->objectID() == objectID)
|
||||||
|
result = _self->self->hasProperty(address);
|
||||||
|
else if (auto object = _self->self->findObject(objectID))
|
||||||
|
result = object->hasProperty(address);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::ObjectIsPropertySettable(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address,
|
||||||
|
Boolean *isSettable)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(objectID);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
if (_self->self->objectID() == objectID)
|
||||||
|
status = _self->self->isPropertySettable(address,
|
||||||
|
isSettable);
|
||||||
|
else if (auto object = _self->self->findObject(objectID))
|
||||||
|
status = object->isPropertySettable(address,
|
||||||
|
isSettable);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::ObjectGetPropertyDataSize(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 *dataSize)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(objectID);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
if (_self->self->objectID() == objectID)
|
||||||
|
status = _self->self->getPropertyDataSize(address,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
dataSize);
|
||||||
|
else if (auto object = _self->self->findObject(objectID))
|
||||||
|
status = object->getPropertyDataSize(address,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
dataSize);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::ObjectGetPropertyData(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
UInt32 *dataUsed,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(objectID);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
if (_self->self->objectID() == objectID)
|
||||||
|
status = _self->self->getPropertyData(address,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
dataSize,
|
||||||
|
dataUsed,
|
||||||
|
data);
|
||||||
|
else if (auto object = _self->self->findObject(objectID))
|
||||||
|
status = object->getPropertyData(address,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
dataSize,
|
||||||
|
dataUsed,
|
||||||
|
data);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::ObjectSetPropertyData(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOObjectID objectID,
|
||||||
|
const CMIOObjectPropertyAddress *address,
|
||||||
|
UInt32 qualifierDataSize,
|
||||||
|
const void *qualifierData,
|
||||||
|
UInt32 dataSize,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(objectID);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
|
||||||
|
if (_self->self->objectID() == objectID)
|
||||||
|
status = _self->self->setPropertyData(address,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
dataSize,
|
||||||
|
data);
|
||||||
|
else if (auto object = _self->self->findObject(objectID))
|
||||||
|
status = object->setPropertyData(address,
|
||||||
|
qualifierDataSize,
|
||||||
|
qualifierData,
|
||||||
|
dataSize,
|
||||||
|
data);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::DeviceSuspend(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(device);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Device *>(_self->self->findObject(device));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->suspend();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::DeviceResume(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(device);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Device *>(_self->self->findObject(device));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->resume();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::DeviceStartStream(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device,
|
||||||
|
CMIOStreamID stream)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(device);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Device *>(_self->self->findObject(device));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->startStream(stream);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::DeviceStopStream(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device,
|
||||||
|
CMIOStreamID stream)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(device);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Device *>(_self->self->findObject(device));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->stopStream(stream);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::DeviceProcessAVCCommand(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device,
|
||||||
|
CMIODeviceAVCCommand *ioAVCCommand)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(device);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Device *>(_self->self->findObject(device));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->processAVCCommand(ioAVCCommand);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::DeviceProcessRS422Command(CMIOHardwarePlugInRef self,
|
||||||
|
CMIODeviceID device,
|
||||||
|
CMIODeviceRS422Command *ioRS422Command)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(device);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Device *>(_self->self->findObject(device));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->processRS422Command(ioRS422Command);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::StreamCopyBufferQueue(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream,
|
||||||
|
CMIODeviceStreamQueueAlteredProc queueAlteredProc,
|
||||||
|
void *queueAlteredRefCon,
|
||||||
|
CMSimpleQueueRef *queue)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(stream);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Stream *>(_self->self->findObject(stream));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->copyBufferQueue(queueAlteredProc,
|
||||||
|
queueAlteredRefCon,
|
||||||
|
queue);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::StreamDeckPlay(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(stream);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Stream *>(_self->self->findObject(stream));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->deckPlay();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::StreamDeckStop(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(stream);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Stream *>(_self->self->findObject(stream));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->deckStop();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::StreamDeckJog(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream,
|
||||||
|
SInt32 speed)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(stream);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Stream *>(_self->self->findObject(stream));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->deckJog(speed);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::PluginInterfacePrivate::StreamDeckCueTo(CMIOHardwarePlugInRef self,
|
||||||
|
CMIOStreamID stream,
|
||||||
|
Float64 frameNumber,
|
||||||
|
Boolean playOnCue)
|
||||||
|
{
|
||||||
|
AkPluginPrivateIntefaceLogID(stream);
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
auto _self = reinterpret_cast<PluginInterfacePrivate *>(self);
|
||||||
|
auto object = reinterpret_cast<Stream *>(_self->self->findObject(stream));
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
status = object->deckCueTo(frameNumber, playOnCue);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
89
cmio/VirtualCamera/src/plugininterface.h
Normal file
89
cmio/VirtualCamera/src/plugininterface.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLUGININTERFACE_H
|
||||||
|
#define PLUGININTERFACE_H
|
||||||
|
|
||||||
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
struct PluginInterfacePrivate;
|
||||||
|
|
||||||
|
class PluginInterface: public ObjectInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PluginInterface();
|
||||||
|
PluginInterface(const PluginInterface &other) = delete;
|
||||||
|
~PluginInterface();
|
||||||
|
|
||||||
|
CMIOObjectID objectID() const;
|
||||||
|
static CMIOHardwarePlugInRef create();
|
||||||
|
Object *findObject(CMIOObjectID objectID);
|
||||||
|
|
||||||
|
HRESULT QueryInterface(REFIID uuid, LPVOID *interface);
|
||||||
|
OSStatus Initialize();
|
||||||
|
OSStatus InitializeWithObjectID(CMIOObjectID objectID);
|
||||||
|
OSStatus Teardown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PluginInterfacePrivate *d;
|
||||||
|
CMIOObjectID m_objectID;
|
||||||
|
std::vector<DevicePtr> m_devices;
|
||||||
|
|
||||||
|
static void serverStateChanged(void *userData,
|
||||||
|
IpcBridge::ServerState state);
|
||||||
|
static void deviceAdded(void *userData,
|
||||||
|
const std::string &deviceId);
|
||||||
|
static void deviceRemoved(void *userData,
|
||||||
|
const std::string &deviceId);
|
||||||
|
static void frameReady(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const VideoFrame &frame);
|
||||||
|
static void setBroadcasting(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const std::string &broadcaster);
|
||||||
|
static void setMirror(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool horizontalMirror,
|
||||||
|
bool verticalMirror);
|
||||||
|
static void setScaling(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
Scaling scaling);
|
||||||
|
static void setAspectRatio(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
AspectRatio aspectRatio);
|
||||||
|
static void setSwapRgb(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool swap);
|
||||||
|
static void addListener(void *userData,
|
||||||
|
const std::string &deviceId);
|
||||||
|
static void removeListener(void *userData,
|
||||||
|
const std::string &deviceId);
|
||||||
|
bool createDevice(const std::string &deviceId,
|
||||||
|
const std::wstring &description,
|
||||||
|
const std::vector<VideoFormat> &formats);
|
||||||
|
void destroyDevice(const std::string &deviceId);
|
||||||
|
|
||||||
|
friend struct PluginInterfacePrivate;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // PLUGININTERFACE_H
|
101
cmio/VirtualCamera/src/queue.h
Normal file
101
cmio/VirtualCamera/src/queue.h
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QUEUE_H
|
||||||
|
#define QUEUE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <CoreMedia/CMSimpleQueue.h>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class Queue;
|
||||||
|
template <typename T>
|
||||||
|
using QueuePtr = std::shared_ptr<Queue<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Queue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Queue(int32_t capacity):
|
||||||
|
m_queue(nullptr)
|
||||||
|
{
|
||||||
|
CMSimpleQueueCreate(kCFAllocatorDefault,
|
||||||
|
capacity,
|
||||||
|
&this->m_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Queue()
|
||||||
|
{
|
||||||
|
CFRelease(this->m_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enqueue(const T &t)
|
||||||
|
{
|
||||||
|
CMSimpleQueueEnqueue(this->m_queue,
|
||||||
|
t);
|
||||||
|
}
|
||||||
|
|
||||||
|
T dequeue()
|
||||||
|
{
|
||||||
|
return CMSimpleQueueDequeue(this->m_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
CMSimpleQueueReset(this->m_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t capacity()
|
||||||
|
{
|
||||||
|
return CMSimpleQueueGetCapacity(this->m_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t count()
|
||||||
|
{
|
||||||
|
return CMSimpleQueueGetCount(this->m_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t size()
|
||||||
|
{
|
||||||
|
return this->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
Float32 fullness()
|
||||||
|
{
|
||||||
|
return CMSimpleQueueGetFullness(this->m_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFTypeID typeID()
|
||||||
|
{
|
||||||
|
return CMSimpleQueueGetTypeID();
|
||||||
|
}
|
||||||
|
|
||||||
|
CMSimpleQueueRef ref()
|
||||||
|
{
|
||||||
|
return m_queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CMSimpleQueueRef m_queue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // QUEUE_H
|
618
cmio/VirtualCamera/src/stream.cpp
Normal file
618
cmio/VirtualCamera/src/stream.cpp
Normal file
|
@ -0,0 +1,618 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <random>
|
||||||
|
#include <CoreMediaIO/CMIOSampleBuffer.h>
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include "clock.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
#include "VCamUtils/src/image/videoframe.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class StreamPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Stream *self;
|
||||||
|
ClockPtr m_clock;
|
||||||
|
UInt64 m_sequence;
|
||||||
|
CMTime m_pts;
|
||||||
|
SampleBufferQueuePtr m_queue;
|
||||||
|
CMIODeviceStreamQueueAlteredProc m_queueAltered {nullptr};
|
||||||
|
VideoFrame m_currentFrame;
|
||||||
|
VideoFrame m_testFrame;
|
||||||
|
VideoFrame m_testFrameAdapted;
|
||||||
|
void *m_queueAlteredRefCon {nullptr};
|
||||||
|
CFRunLoopTimerRef m_timer {nullptr};
|
||||||
|
std::string m_broadcaster;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
Scaling m_scaling {ScalingFast};
|
||||||
|
AspectRatio m_aspectRatio {AspectRatioIgnore};
|
||||||
|
bool m_running {false};
|
||||||
|
bool m_horizontalMirror {false};
|
||||||
|
bool m_verticalMirror {false};
|
||||||
|
bool m_swapRgb {false};
|
||||||
|
|
||||||
|
explicit StreamPrivate(Stream *self);
|
||||||
|
bool startTimer();
|
||||||
|
void stopTimer();
|
||||||
|
static void streamLoop(CFRunLoopTimerRef timer, void *info);
|
||||||
|
void sendFrame(const VideoFrame &frame);
|
||||||
|
void updateTestFrame();
|
||||||
|
VideoFrame applyAdjusts(const VideoFrame &frame);
|
||||||
|
VideoFrame randomFrame();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Stream::Stream(bool registerObject,
|
||||||
|
Object *parent):
|
||||||
|
Object(parent)
|
||||||
|
{
|
||||||
|
this->d = new StreamPrivate(this);
|
||||||
|
this->m_className = "Stream";
|
||||||
|
this->m_classID = kCMIOStreamClassID;
|
||||||
|
this->d->m_testFrame.load(CMIO_PLUGINS_DAL_PATH
|
||||||
|
"/"
|
||||||
|
CMIO_PLUGIN_NAME
|
||||||
|
".plugin/Contents/Resources/TestFrame.bmp");
|
||||||
|
|
||||||
|
this->d->m_clock =
|
||||||
|
std::make_shared<Clock>("CMIO::VirtualCamera::Stream",
|
||||||
|
CMTimeMake(1, 10),
|
||||||
|
100,
|
||||||
|
10);
|
||||||
|
this->d->m_queue = std::make_shared<SampleBufferQueue>(30);
|
||||||
|
|
||||||
|
if (registerObject) {
|
||||||
|
this->createObject();
|
||||||
|
this->registerObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_properties.setProperty(kCMIOStreamPropertyClock, this->d->m_clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Stream::~Stream()
|
||||||
|
{
|
||||||
|
this->registerObject(false);
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Stream::createObject()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (!this->m_pluginInterface
|
||||||
|
|| !*this->m_pluginInterface
|
||||||
|
|| !this->m_parent)
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
CMIOObjectID streamID = 0;
|
||||||
|
|
||||||
|
auto status =
|
||||||
|
CMIOObjectCreate(this->m_pluginInterface,
|
||||||
|
this->m_parent->objectID(),
|
||||||
|
this->m_classID,
|
||||||
|
&streamID);
|
||||||
|
|
||||||
|
if (status == kCMIOHardwareNoError) {
|
||||||
|
this->m_isCreated = true;
|
||||||
|
this->m_objectID = streamID;
|
||||||
|
AkLoggerLog("Created stream: ", this->m_objectID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Stream::registerObject(bool regist)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
OSStatus status = kCMIOHardwareUnspecifiedError;
|
||||||
|
|
||||||
|
if (!this->m_isCreated
|
||||||
|
|| !this->m_pluginInterface
|
||||||
|
|| !*this->m_pluginInterface
|
||||||
|
|| !this->m_parent)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (regist) {
|
||||||
|
status = CMIOObjectsPublishedAndDied(this->m_pluginInterface,
|
||||||
|
this->m_parent->objectID(),
|
||||||
|
1,
|
||||||
|
&this->m_objectID,
|
||||||
|
0,
|
||||||
|
nullptr);
|
||||||
|
} else {
|
||||||
|
status = CMIOObjectsPublishedAndDied(this->m_pluginInterface,
|
||||||
|
this->m_parent->objectID(),
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
1,
|
||||||
|
&this->m_objectID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setFormats(const std::vector<VideoFormat> &formats)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (formats.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::vector<VideoFormat> formatsAdjusted;
|
||||||
|
|
||||||
|
for (auto format: formats) {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
AkVCam::VideoFormat::roundNearest(format.width(),
|
||||||
|
format.height(),
|
||||||
|
&width,
|
||||||
|
&height);
|
||||||
|
format.width() = width;
|
||||||
|
format.height() = height;
|
||||||
|
formatsAdjusted.push_back(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
for (auto &format: formatsAdjusted)
|
||||||
|
AkLoggerLog("Format: ",
|
||||||
|
enumToString(format.fourcc()),
|
||||||
|
" ",
|
||||||
|
format.width(),
|
||||||
|
"x",
|
||||||
|
format.height());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this->m_properties.setProperty(kCMIOStreamPropertyFormatDescriptions,
|
||||||
|
formatsAdjusted);
|
||||||
|
this->setFormat(formatsAdjusted[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setFormat(const VideoFormat &format)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
this->m_properties.setProperty(kCMIOStreamPropertyFormatDescription,
|
||||||
|
format);
|
||||||
|
this->m_properties.setProperty(kCMIOStreamPropertyFrameRates,
|
||||||
|
format.frameRates());
|
||||||
|
this->m_properties.setProperty(kCMIOStreamPropertyFrameRateRanges,
|
||||||
|
format.frameRateRanges());
|
||||||
|
this->m_properties.setProperty(kCMIOStreamPropertyMinimumFrameRate,
|
||||||
|
format.minimumFrameRate().value());
|
||||||
|
|
||||||
|
if (!format.frameRates().empty())
|
||||||
|
this->setFrameRate(format.frameRates().front());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setFrameRate(const Fraction &frameRate)
|
||||||
|
{
|
||||||
|
this->m_properties.setProperty(kCMIOStreamPropertyFrameRate,
|
||||||
|
frameRate.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::Stream::start()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_running)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
||||||
|
this->d->m_sequence = 0;
|
||||||
|
memset(&this->d->m_pts, 0, sizeof(CMTime));
|
||||||
|
this->d->m_running = this->d->startTimer();
|
||||||
|
AkLoggerLog("Running: ", this->d->m_running);
|
||||||
|
|
||||||
|
return this->d->m_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::stop()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (!this->d->m_running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_running = false;
|
||||||
|
this->d->stopTimer();
|
||||||
|
this->d->m_currentFrame.clear();
|
||||||
|
this->d->m_testFrameAdapted.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::Stream::running()
|
||||||
|
{
|
||||||
|
return this->d->m_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::serverStateChanged(IpcBridge::ServerState state)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (state == IpcBridge::ServerStateGone) {
|
||||||
|
this->d->m_broadcaster.clear();
|
||||||
|
this->d->m_horizontalMirror = false;
|
||||||
|
this->d->m_verticalMirror = false;
|
||||||
|
this->d->m_scaling = ScalingFast;
|
||||||
|
this->d->m_aspectRatio = AspectRatioIgnore;
|
||||||
|
this->d->m_swapRgb = false;
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
|
||||||
|
this->d->m_mutex.lock();
|
||||||
|
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
||||||
|
this->d->m_mutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::frameReady(const AkVCam::VideoFrame &frame)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
AkLoggerLog("Running: ", this->d->m_running);
|
||||||
|
AkLoggerLog("Broadcaster: ", this->d->m_broadcaster);
|
||||||
|
|
||||||
|
if (!this->d->m_running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_mutex.lock();
|
||||||
|
|
||||||
|
if (!this->d->m_broadcaster.empty())
|
||||||
|
this->d->m_currentFrame = this->d->applyAdjusts(frame);
|
||||||
|
|
||||||
|
this->d->m_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setBroadcasting(const std::string &broadcaster)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_broadcaster == broadcaster)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_mutex.lock();
|
||||||
|
this->d->m_broadcaster = broadcaster;
|
||||||
|
|
||||||
|
if (broadcaster.empty())
|
||||||
|
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
||||||
|
|
||||||
|
this->d->m_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setMirror(bool horizontalMirror, bool verticalMirror)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_horizontalMirror == horizontalMirror
|
||||||
|
&& this->d->m_verticalMirror == verticalMirror)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_horizontalMirror = horizontalMirror;
|
||||||
|
this->d->m_verticalMirror = verticalMirror;
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setScaling(Scaling scaling)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_scaling == scaling)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_scaling = scaling;
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setAspectRatio(AspectRatio aspectRatio)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_aspectRatio == aspectRatio)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_aspectRatio = aspectRatio;
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setSwapRgb(bool swap)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_swapRgb == swap)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_swapRgb = swap;
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Stream::copyBufferQueue(CMIODeviceStreamQueueAlteredProc queueAlteredProc,
|
||||||
|
void *queueAlteredRefCon,
|
||||||
|
CMSimpleQueueRef *queue)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
this->d->m_queueAltered = queueAlteredProc;
|
||||||
|
this->d->m_queueAlteredRefCon = queueAlteredRefCon;
|
||||||
|
*queue = queueAlteredProc? this->d->m_queue->ref(): nullptr;
|
||||||
|
|
||||||
|
if (*queue)
|
||||||
|
CFRetain(*queue);
|
||||||
|
|
||||||
|
return kCMIOHardwareNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Stream::deckPlay()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Stream::deckStop()
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Stream::deckJog(SInt32 speed)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
UNUSED(speed)
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus AkVCam::Stream::deckCueTo(Float64 frameNumber, Boolean playOnCue)
|
||||||
|
{
|
||||||
|
AkObjectLogMethod();
|
||||||
|
UNUSED(frameNumber)
|
||||||
|
UNUSED(playOnCue)
|
||||||
|
|
||||||
|
AkLoggerLog("STUB");
|
||||||
|
|
||||||
|
return kCMIOHardwareUnspecifiedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::StreamPrivate::StreamPrivate(AkVCam::Stream *self):
|
||||||
|
self(self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::StreamPrivate::startTimer()
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::StreamPrivate::startTimer()");
|
||||||
|
|
||||||
|
if (this->m_timer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Float64 fps = 0;
|
||||||
|
this->self->m_properties.getProperty(kCMIOStreamPropertyFrameRate, &fps);
|
||||||
|
|
||||||
|
CFTimeInterval interval = 1.0 / fps;
|
||||||
|
CFRunLoopTimerContext context {0, this, nullptr, nullptr, nullptr};
|
||||||
|
this->m_timer =
|
||||||
|
CFRunLoopTimerCreate(kCFAllocatorDefault,
|
||||||
|
0.0,
|
||||||
|
interval,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
StreamPrivate::streamLoop,
|
||||||
|
&context);
|
||||||
|
|
||||||
|
if (!this->m_timer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CFRunLoopAddTimer(CFRunLoopGetMain(),
|
||||||
|
this->m_timer,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::StreamPrivate::stopTimer()
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::StreamPrivate::stopTimer()");
|
||||||
|
|
||||||
|
if (!this->m_timer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CFRunLoopTimerInvalidate(this->m_timer);
|
||||||
|
CFRunLoopRemoveTimer(CFRunLoopGetMain(),
|
||||||
|
this->m_timer,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
|
CFRelease(this->m_timer);
|
||||||
|
this->m_timer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::StreamPrivate::streamLoop(CFRunLoopTimerRef timer, void *info)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::StreamPrivate::streamLoop()");
|
||||||
|
UNUSED(timer)
|
||||||
|
|
||||||
|
auto self = reinterpret_cast<StreamPrivate *>(info);
|
||||||
|
AkLoggerLog("Running: ", self->m_running);
|
||||||
|
|
||||||
|
if (!self->m_running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
self->m_mutex.lock();
|
||||||
|
|
||||||
|
if (self->m_currentFrame.format().size() < 1)
|
||||||
|
self->sendFrame(self->randomFrame());
|
||||||
|
else
|
||||||
|
self->sendFrame(self->m_currentFrame);
|
||||||
|
|
||||||
|
self->m_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::StreamPrivate::sendFrame(const VideoFrame &frame)
|
||||||
|
{
|
||||||
|
AkLoggerLog("AkVCam::StreamPrivate::sendFrame()");
|
||||||
|
|
||||||
|
if (this->m_queue->fullness() >= 1.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FourCC fourcc = frame.format().fourcc();
|
||||||
|
int width = frame.format().width();
|
||||||
|
int height = frame.format().height();
|
||||||
|
|
||||||
|
AkLoggerLog("Sending Frame: ",
|
||||||
|
enumToString(fourcc),
|
||||||
|
" ",
|
||||||
|
width,
|
||||||
|
"x",
|
||||||
|
height);
|
||||||
|
|
||||||
|
bool resync = false;
|
||||||
|
auto hostTime = CFAbsoluteTimeGetCurrent();
|
||||||
|
auto pts = CMTimeMake(int64_t(hostTime), 1e9);
|
||||||
|
auto ptsDiff = CMTimeGetSeconds(CMTimeSubtract(this->m_pts, pts));
|
||||||
|
|
||||||
|
if (CMTimeCompare(pts, this->m_pts) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Float64 fps = 0;
|
||||||
|
this->self->m_properties.getProperty(kCMIOStreamPropertyFrameRate, &fps);
|
||||||
|
|
||||||
|
if (CMTIME_IS_INVALID(this->m_pts)
|
||||||
|
|| ptsDiff < 0
|
||||||
|
|| ptsDiff > 2. / fps) {
|
||||||
|
this->m_pts = pts;
|
||||||
|
resync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMIOStreamClockPostTimingEvent(this->m_pts,
|
||||||
|
UInt64(hostTime),
|
||||||
|
resync,
|
||||||
|
this->m_clock->ref());
|
||||||
|
|
||||||
|
CVImageBufferRef imageBuffer = nullptr;
|
||||||
|
CVPixelBufferCreate(kCFAllocatorDefault,
|
||||||
|
size_t(width),
|
||||||
|
size_t(height),
|
||||||
|
formatToCM(PixelFormat(fourcc)),
|
||||||
|
nullptr,
|
||||||
|
&imageBuffer);
|
||||||
|
|
||||||
|
if (!imageBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CVPixelBufferLockBaseAddress(imageBuffer, 0);
|
||||||
|
auto data = CVPixelBufferGetBaseAddress(imageBuffer);
|
||||||
|
memcpy(data, frame.data().data(), frame.data().size());
|
||||||
|
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
|
||||||
|
|
||||||
|
CMVideoFormatDescriptionRef format = nullptr;
|
||||||
|
CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault,
|
||||||
|
imageBuffer,
|
||||||
|
&format);
|
||||||
|
|
||||||
|
auto duration = CMTimeMake(1e3, int32_t(1e3 * fps));
|
||||||
|
CMSampleTimingInfo timingInfo {
|
||||||
|
duration,
|
||||||
|
this->m_pts,
|
||||||
|
this->m_pts
|
||||||
|
};
|
||||||
|
|
||||||
|
CMSampleBufferRef buffer = nullptr;
|
||||||
|
CMIOSampleBufferCreateForImageBuffer(kCFAllocatorDefault,
|
||||||
|
imageBuffer,
|
||||||
|
format,
|
||||||
|
&timingInfo,
|
||||||
|
this->m_sequence,
|
||||||
|
resync?
|
||||||
|
kCMIOSampleBufferDiscontinuityFlag_UnknownDiscontinuity:
|
||||||
|
kCMIOSampleBufferNoDiscontinuities,
|
||||||
|
&buffer);
|
||||||
|
CFRelease(format);
|
||||||
|
CFRelease(imageBuffer);
|
||||||
|
|
||||||
|
this->m_queue->enqueue(buffer);
|
||||||
|
this->m_pts = CMTimeAdd(this->m_pts, duration);
|
||||||
|
this->m_sequence++;
|
||||||
|
|
||||||
|
if (this->m_queueAltered)
|
||||||
|
this->m_queueAltered(this->self->m_objectID,
|
||||||
|
buffer,
|
||||||
|
this->m_queueAlteredRefCon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::StreamPrivate::updateTestFrame()
|
||||||
|
{
|
||||||
|
this->m_testFrameAdapted = this->applyAdjusts(this->m_testFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFrame AkVCam::StreamPrivate::applyAdjusts(const VideoFrame &frame)
|
||||||
|
{
|
||||||
|
VideoFormat format;
|
||||||
|
this->self->m_properties.getProperty(kCMIOStreamPropertyFormatDescription,
|
||||||
|
&format);
|
||||||
|
|
||||||
|
FourCC fourcc = format.fourcc();
|
||||||
|
int width = format.width();
|
||||||
|
int height = format.height();
|
||||||
|
|
||||||
|
if (width * height > frame.format().width() * frame.format().height()) {
|
||||||
|
return frame.mirror(this->m_horizontalMirror,
|
||||||
|
this->m_verticalMirror)
|
||||||
|
.swapRgb(this->m_swapRgb)
|
||||||
|
.scaled(width, height,
|
||||||
|
this->m_scaling,
|
||||||
|
this->m_aspectRatio)
|
||||||
|
.convert(fourcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame.scaled(width, height,
|
||||||
|
this->m_scaling,
|
||||||
|
this->m_aspectRatio)
|
||||||
|
.mirror(this->m_horizontalMirror,
|
||||||
|
this->m_verticalMirror)
|
||||||
|
.swapRgb(this->m_swapRgb)
|
||||||
|
.convert(fourcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFrame AkVCam::StreamPrivate::randomFrame()
|
||||||
|
{
|
||||||
|
VideoFormat format;
|
||||||
|
this->self->m_properties.getProperty(kCMIOStreamPropertyFormatDescription,
|
||||||
|
&format);
|
||||||
|
VideoData data(format.size());
|
||||||
|
static std::uniform_int_distribution<uint8_t> distribution(std::numeric_limits<uint8_t>::min(),
|
||||||
|
std::numeric_limits<uint8_t>::max());
|
||||||
|
static std::default_random_engine engine;
|
||||||
|
std::generate(data.begin(), data.end(), [] () {
|
||||||
|
return distribution(engine);
|
||||||
|
});
|
||||||
|
|
||||||
|
VideoFrame frame;
|
||||||
|
frame.format() = format;
|
||||||
|
frame.data() = data;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
78
cmio/VirtualCamera/src/stream.h
Normal file
78
cmio/VirtualCamera/src/stream.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STREAM_H
|
||||||
|
#define STREAM_H
|
||||||
|
|
||||||
|
#include "VCamUtils/src/fraction.h"
|
||||||
|
#include "VCamUtils/src/image/videoframetypes.h"
|
||||||
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class StreamPrivate;
|
||||||
|
class Stream;
|
||||||
|
class VideoFrame;
|
||||||
|
typedef std::shared_ptr<Stream> StreamPtr;
|
||||||
|
typedef Queue<CMSampleBufferRef> SampleBufferQueue;
|
||||||
|
typedef QueuePtr<CMSampleBufferRef> SampleBufferQueuePtr;
|
||||||
|
|
||||||
|
class Stream: public Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Stream(bool registerObject=false, Object *m_parent=nullptr);
|
||||||
|
Stream(const Stream &other) = delete;
|
||||||
|
~Stream();
|
||||||
|
|
||||||
|
OSStatus createObject();
|
||||||
|
OSStatus registerObject(bool regist=true);
|
||||||
|
void setFormats(const std::vector<VideoFormat> &formats);
|
||||||
|
void setFormat(const VideoFormat &format);
|
||||||
|
void setFrameRate(const Fraction &frameRate);
|
||||||
|
bool start();
|
||||||
|
void stop();
|
||||||
|
bool running();
|
||||||
|
|
||||||
|
void serverStateChanged(IpcBridge::ServerState state);
|
||||||
|
void frameReady(const VideoFrame &frame);
|
||||||
|
void setBroadcasting(const std::string &broadcaster);
|
||||||
|
void setMirror(bool horizontalMirror, bool verticalMirror);
|
||||||
|
void setScaling(Scaling scaling);
|
||||||
|
void setAspectRatio(AspectRatio aspectRatio);
|
||||||
|
void setSwapRgb(bool swap);
|
||||||
|
|
||||||
|
// Stream Interface
|
||||||
|
OSStatus copyBufferQueue(CMIODeviceStreamQueueAlteredProc queueAlteredProc,
|
||||||
|
void *queueAlteredRefCon,
|
||||||
|
CMSimpleQueueRef *queue);
|
||||||
|
OSStatus deckPlay();
|
||||||
|
OSStatus deckStop();
|
||||||
|
OSStatus deckJog(SInt32 speed);
|
||||||
|
OSStatus deckCueTo(Float64 frameNumber, Boolean playOnCue);
|
||||||
|
|
||||||
|
private:
|
||||||
|
StreamPrivate *d;
|
||||||
|
|
||||||
|
friend class StreamPrivate;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // STREAM_H
|
85
cmio/VirtualCamera/src/utils.cpp
Normal file
85
cmio/VirtualCamera/src/utils.cpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
inline const std::map<AkVCam::PixelFormat, FourCharCode> *formatsTable()
|
||||||
|
{
|
||||||
|
static const std::map<AkVCam::PixelFormat, FourCharCode> formatsTable {
|
||||||
|
{AkVCam::PixelFormatRGB32, kCMPixelFormat_32ARGB },
|
||||||
|
{AkVCam::PixelFormatRGB24, kCMPixelFormat_24RGB },
|
||||||
|
{AkVCam::PixelFormatRGB16, kCMPixelFormat_16LE565 },
|
||||||
|
{AkVCam::PixelFormatRGB15, kCMPixelFormat_16LE555 },
|
||||||
|
{AkVCam::PixelFormatUYVY , kCMPixelFormat_422YpCbCr8 },
|
||||||
|
{AkVCam::PixelFormatYUY2 , kCMPixelFormat_422YpCbCr8_yuvs}
|
||||||
|
};
|
||||||
|
|
||||||
|
return &formatsTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::uuidEqual(const REFIID &uuid1, const CFUUIDRef uuid2)
|
||||||
|
{
|
||||||
|
auto iid2 = CFUUIDGetUUIDBytes(uuid2);
|
||||||
|
auto puuid1 = reinterpret_cast<const UInt8 *>(&uuid1);
|
||||||
|
auto puuid2 = reinterpret_cast<const UInt8 *>(&iid2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
if (puuid1[i] != puuid2[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::enumToString(UInt32 value)
|
||||||
|
{
|
||||||
|
auto valueChr = reinterpret_cast<char *>(&value);
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
for (int i = 3; i >= 0; i--)
|
||||||
|
if (valueChr[i] < 0)
|
||||||
|
ss << std::hex << valueChr[i];
|
||||||
|
else if (valueChr[i] < 32)
|
||||||
|
ss << int(valueChr[i]);
|
||||||
|
else
|
||||||
|
ss << valueChr[i];
|
||||||
|
|
||||||
|
return "'" + ss.str() + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
FourCharCode AkVCam::formatToCM(PixelFormat format)
|
||||||
|
{
|
||||||
|
for (auto &fmt: *formatsTable())
|
||||||
|
if (fmt.first == format)
|
||||||
|
return fmt.second;
|
||||||
|
|
||||||
|
return FourCharCode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::PixelFormat AkVCam::formatFromCM(FourCharCode format)
|
||||||
|
{
|
||||||
|
for (auto &fmt: *formatsTable())
|
||||||
|
if (fmt.second == format)
|
||||||
|
return fmt.first;
|
||||||
|
|
||||||
|
return PixelFormat(0);
|
||||||
|
}
|
37
cmio/VirtualCamera/src/utils.h
Normal file
37
cmio/VirtualCamera/src/utils.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <CoreMediaIO/CMIOHardwarePlugIn.h>
|
||||||
|
#include <CoreMedia/CMFormatDescription.h>
|
||||||
|
|
||||||
|
#include "VCamUtils/src/image/videoformattypes.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
bool uuidEqual(const REFIID &uuid1, const CFUUIDRef uuid2);
|
||||||
|
std::string enumToString(UInt32 value);
|
||||||
|
FourCharCode formatToCM(PixelFormat format);
|
||||||
|
PixelFormat formatFromCM(FourCharCode format);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // UTILS_H
|
44
cmio/cmio.pri
Normal file
44
cmio/cmio.pri
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
isEmpty(CMIO_PLUGINS_DAL_PATH):
|
||||||
|
CMIO_PLUGINS_DAL_PATH = /Library/CoreMediaIO/Plug-Ins/DAL
|
||||||
|
isEmpty(CMIO_DAEMONS_PATH):
|
||||||
|
CMIO_DAEMONS_PATH = ~/Library/LaunchAgents
|
||||||
|
isEmpty(CMIO_PLUGIN_NAME):
|
||||||
|
CMIO_PLUGIN_NAME = AkVirtualCamera
|
||||||
|
isEmpty(CMIO_PLUGIN_ASSISTANT_NAME):
|
||||||
|
CMIO_PLUGIN_ASSISTANT_NAME = AkVCamAssistant
|
||||||
|
isEmpty(CMIO_PLUGIN_DEVICE_PREFIX):
|
||||||
|
CMIO_PLUGIN_DEVICE_PREFIX = /akvcam/video
|
||||||
|
isEmpty(CMIO_PLUGIN_VENDOR):
|
||||||
|
CMIO_PLUGIN_VENDOR = "Webcamoid Project"
|
||||||
|
isEmpty(CMIO_PLUGIN_PRODUCT):
|
||||||
|
CMIO_PLUGIN_PRODUCT = $$CMIO_PLUGIN_NAME
|
||||||
|
|
||||||
|
DEFINES += \
|
||||||
|
CMIO_PLUGINS_DAL_PATH=\"\\\"$$CMIO_PLUGINS_DAL_PATH\\\"\" \
|
||||||
|
CMIO_PLUGINS_DAL_PATH_L=\"L\\\"$$CMIO_PLUGINS_DAL_PATH\\\"\" \
|
||||||
|
CMIO_DAEMONS_PATH=\"\\\"$$CMIO_DAEMONS_PATH\\\"\" \
|
||||||
|
CMIO_PLUGIN_NAME=\"\\\"$$CMIO_PLUGIN_NAME\\\"\" \
|
||||||
|
CMIO_PLUGIN_NAME_L=\"L\\\"$$CMIO_PLUGIN_NAME\\\"\" \
|
||||||
|
CMIO_PLUGIN_ASSISTANT_NAME=\"\\\"$$CMIO_PLUGIN_ASSISTANT_NAME\\\"\" \
|
||||||
|
CMIO_PLUGIN_ASSISTANT_NAME_L=\"L\\\"$$CMIO_PLUGIN_ASSISTANT_NAME\\\"\" \
|
||||||
|
CMIO_PLUGIN_DEVICE_PREFIX=\"\\\"$$CMIO_PLUGIN_DEVICE_PREFIX\\\"\" \
|
||||||
|
CMIO_PLUGIN_VENDOR=\"\\\"$$CMIO_PLUGIN_VENDOR\\\"\" \
|
||||||
|
CMIO_PLUGIN_PRODUCT=\"\\\"$$CMIO_PLUGIN_PRODUCT\\\"\"
|
25
cmio/cmio.pro
Normal file
25
cmio/cmio.pro
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
TEMPLATE = subdirs
|
||||||
|
CONFIG += ordered
|
||||||
|
|
||||||
|
SUBDIRS = \
|
||||||
|
VCamIPC \
|
||||||
|
Assistant \
|
||||||
|
VirtualCamera
|
4
cmio/pspec.json
Normal file
4
cmio/pspec.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"pluginType": "Ak.SubModule",
|
||||||
|
"type": "output"
|
||||||
|
}
|
189
commons.pri
Normal file
189
commons.pri
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
COMMONS_APPNAME = "AkVirtualCamera"
|
||||||
|
COMMONS_TARGET = $$lower($${COMMONS_APPNAME})
|
||||||
|
COMMONS_TARGET = $$replace(COMMONS_TARGET, lib, "")
|
||||||
|
|
||||||
|
VER_MAJ = 9
|
||||||
|
VER_MIN = 0
|
||||||
|
VER_PAT = 0
|
||||||
|
VERSION = $${VER_MAJ}.$${VER_MIN}.$${VER_PAT}
|
||||||
|
|
||||||
|
isEmpty(BUNDLENAME): BUNDLENAME = $${COMMONS_APPNAME}
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
host_name = $$lower($$QMAKE_HOST.os)
|
||||||
|
|
||||||
|
!isEmpty(ProgramW6432) {
|
||||||
|
DEFAULT_PREFIX = $(ProgramW6432)/$${BUNDLENAME}
|
||||||
|
} else: !isEmpty(ProgramFiles) {
|
||||||
|
DEFAULT_PREFIX = $(ProgramFiles)/$${BUNDLENAME}
|
||||||
|
} else: contains(host_name, linux) {
|
||||||
|
DEFAULT_PREFIX = /$${BUNDLENAME}
|
||||||
|
} else {
|
||||||
|
DEFAULT_PREFIX = C:/$${BUNDLENAME}
|
||||||
|
}
|
||||||
|
} else: macx: isEmpty(NOAPPBUNDLE) {
|
||||||
|
DEFAULT_PREFIX = /Applications
|
||||||
|
} else {
|
||||||
|
DEFAULT_PREFIX = $$[QT_INSTALL_PREFIX]
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty(PREFIX): PREFIX = $${DEFAULT_PREFIX}
|
||||||
|
isEmpty(EXECPREFIX) {
|
||||||
|
macx: isEmpty(NOAPPBUNDLE) {
|
||||||
|
EXECPREFIX = $${PREFIX}/$${BUNDLENAME}.app/Contents
|
||||||
|
} else {
|
||||||
|
EXECPREFIX = $${PREFIX}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isEmpty(BINDIR) {
|
||||||
|
macx: isEmpty(NOAPPBUNDLE) {
|
||||||
|
BINDIR = $${EXECPREFIX}/MacOS
|
||||||
|
} else {
|
||||||
|
BINDIR = $${EXECPREFIX}/bin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isEmpty(SBINDIR): SBINDIR = $${EXECPREFIX}/sbin
|
||||||
|
isEmpty(LIBEXECDIR): LIBEXECDIR = $${EXECPREFIX}/libexec
|
||||||
|
isEmpty(DATAROOTDIR) {
|
||||||
|
macx: isEmpty(NOAPPBUNDLE) {
|
||||||
|
DATAROOTDIR = $${EXECPREFIX}/Resources
|
||||||
|
} else {
|
||||||
|
DATAROOTDIR = $${PREFIX}/share
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isEmpty(DATDIR): DATDIR = $${DATAROOTDIR}/$${COMMONS_TARGET}
|
||||||
|
isEmpty(SYSCONFDIR): SYSCONFDIR = $${PREFIX}/etc
|
||||||
|
isEmpty(SHAREDSTATEDIR): SHAREDSTATEDIR = $${PREFIX}/com
|
||||||
|
isEmpty(LOCALSTATEDIR): LOCALSTATEDIR = $${PREFIX}/var
|
||||||
|
isEmpty(INCLUDEDIR): INCLUDEDIR = $${PREFIX}/include
|
||||||
|
isEmpty(DOCDIR): DOCDIR = $${DATAROOTDIR}/doc/$${COMMONS_TARGET}
|
||||||
|
isEmpty(INFODIR): INFODIR = $${DATAROOTDIR}/info
|
||||||
|
isEmpty(HTMLDIR): HTMLDIR = $${DOCDIR}/html
|
||||||
|
isEmpty(DVIDIR): DVIDIR = $${DOCDIR}/dvi
|
||||||
|
isEmpty(PDFDIR): PDFDIR = $${DOCDIR}/pdf
|
||||||
|
isEmpty(PSDIR): PSDIR = $${DOCDIR}/ps
|
||||||
|
isEmpty(LIBDIR) {
|
||||||
|
macx: isEmpty(NOAPPBUNDLE) {
|
||||||
|
LIBDIR = $${EXECPREFIX}/Frameworks
|
||||||
|
} else {
|
||||||
|
INSTALL_LIBS = $$[QT_INSTALL_LIBS]
|
||||||
|
LIBDIR = $$replace(INSTALL_LIBS, $$[QT_INSTALL_PREFIX], $${EXECPREFIX})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isEmpty(LOCALEDIR): LOCALEDIR = $${DATAROOTDIR}/locale
|
||||||
|
isEmpty(MANDIR): MANDIR = $${DATAROOTDIR}/man
|
||||||
|
isEmpty(LICENSEDIR): LICENSEDIR = $${DATAROOTDIR}/licenses/$${COMMONS_TARGET}
|
||||||
|
isEmpty(LOCALDIR): LOCALDIR = $${PREFIX}/local
|
||||||
|
isEmpty(LOCALLIBDIR): LOCALLIBDIR = $${LOCALDIR}/lib
|
||||||
|
isEmpty(INSTALLQMLDIR) {
|
||||||
|
macx: isEmpty(NOAPPBUNDLE) {
|
||||||
|
INSTALLQMLDIR = $${DATAROOTDIR}/qml
|
||||||
|
} else {
|
||||||
|
INSTALL_QML = $$[QT_INSTALL_QML]
|
||||||
|
INSTALLQMLDIR = $$replace(INSTALL_QML, $$[QT_INSTALL_LIBS], $${LIBDIR})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isEmpty(INSTALLPLUGINSDIR) {
|
||||||
|
macx: isEmpty(NOAPPBUNDLE) {
|
||||||
|
INSTALLPLUGINSDIR = $${EXECPREFIX}/Plugins/$${COMMONS_TARGET}
|
||||||
|
} else {
|
||||||
|
INSTALLPLUGINSDIR = $${LIBDIR}/$${COMMONS_TARGET}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isEmpty(JARDIR): JARDIR = $${EXECPREFIX}/libs
|
||||||
|
|
||||||
|
macx: !isEmpty(NOAPPBUNDLE): DEFINES += NOAPPBUNDLE
|
||||||
|
|
||||||
|
DEFINES += \
|
||||||
|
COMMONS_APPNAME=\"\\\"$$COMMONS_APPNAME\\\"\" \
|
||||||
|
COMMONS_TARGET=\"\\\"$$COMMONS_TARGET\\\"\" \
|
||||||
|
COMMONS_VER_MAJ=\"\\\"$$VER_MAJ\\\"\" \
|
||||||
|
COMMONS_VERSION=\"\\\"$$VERSION\\\"\" \
|
||||||
|
PREFIX=\"\\\"$$PREFIX\\\"\" \
|
||||||
|
EXECPREFIX=\"\\\"$$EXECPREFIX\\\"\" \
|
||||||
|
BINDIR=\"\\\"$$BINDIR\\\"\" \
|
||||||
|
SBINDIR=\"\\\"$$SBINDIR\\\"\" \
|
||||||
|
LIBEXECDIR=\"\\\"$$LIBEXECDIR\\\"\" \
|
||||||
|
DATAROOTDIR=\"\\\"$$DATAROOTDIR\\\"\" \
|
||||||
|
DATDIR=\"\\\"$$DATDIR\\\"\" \
|
||||||
|
SYSCONFDIR=\"\\\"$$SYSCONFDIR\\\"\" \
|
||||||
|
SHAREDSTATEDIR=\"\\\"$$SHAREDSTATEDIR\\\"\" \
|
||||||
|
LOCALSTATEDIR=\"\\\"$$LOCALSTATEDIR\\\"\" \
|
||||||
|
INCLUDEDIR=\"\\\"$$INCLUDEDIR\\\"\" \
|
||||||
|
DOCDIR=\"\\\"$$DOCDIR\\\"\" \
|
||||||
|
INFODIR=\"\\\"$$INFODIR\\\"\" \
|
||||||
|
HTMLDIR=\"\\\"$$HTMLDIR\\\"\" \
|
||||||
|
DVIDIR=\"\\\"$$DVIDIR\\\"\" \
|
||||||
|
PDFDIR=\"\\\"$$PDFDIR\\\"\" \
|
||||||
|
PSDIR=\"\\\"$$PSDIR\\\"\" \
|
||||||
|
LIBDIR=\"\\\"$$LIBDIR\\\"\" \
|
||||||
|
LOCALEDIR=\"\\\"$$LOCALEDIR\\\"\" \
|
||||||
|
MANDIR=\"\\\"$$MANDIR\\\"\" \
|
||||||
|
LICENSEDIR=\"\\\"$$LICENSEDIR\\\"\" \
|
||||||
|
LOCALDIR=\"\\\"$$LOCALDIR\\\"\" \
|
||||||
|
LOCALLIBDIR=\"\\\"$$LOCALLIBDIR\\\"\" \
|
||||||
|
INSTALLQMLDIR=\"\\\"$$INSTALLQMLDIR\\\"\" \
|
||||||
|
INSTALLPLUGINSDIR=\"\\\"$$INSTALLPLUGINSDIR\\\"\"
|
||||||
|
|
||||||
|
msvc {
|
||||||
|
TARGET_ARCH = $${QMAKE_TARGET.arch}
|
||||||
|
TARGET_ARCH = $$basename(TARGET_ARCH)
|
||||||
|
TARGET_ARCH = $$replace(TARGET_ARCH, x64, x86_64)
|
||||||
|
} else {
|
||||||
|
TARGET_ARCH = $$system($${QMAKE_CXX} -dumpmachine)
|
||||||
|
TARGET_ARCH = $$split(TARGET_ARCH, -)
|
||||||
|
TARGET_ARCH = $$first(TARGET_ARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPILER = $$basename(QMAKE_CXX)
|
||||||
|
COMPILER = $$replace(COMPILER, \+\+, pp)
|
||||||
|
COMPILER = $$join(COMPILER, _)
|
||||||
|
|
||||||
|
CONFIG(debug, debug|release) {
|
||||||
|
COMMONS_BUILD_PATH = debug/$${COMPILER}/$${TARGET_ARCH}
|
||||||
|
DEFINES += QT_DEBUG
|
||||||
|
} else {
|
||||||
|
COMMONS_BUILD_PATH = release/$$COMPILER/$${TARGET_ARCH}
|
||||||
|
}
|
||||||
|
|
||||||
|
android: COMMONS_BUILD_PATH = $${COMMONS_BUILD_PATH}/$${ANDROID_PLATFORM}
|
||||||
|
|
||||||
|
BIN_DIR = $${COMMONS_BUILD_PATH}/bin
|
||||||
|
MOC_DIR = $${COMMONS_BUILD_PATH}/moc
|
||||||
|
OBJECTS_DIR = $${COMMONS_BUILD_PATH}/obj
|
||||||
|
RCC_DIR = $${COMMONS_BUILD_PATH}/rcc
|
||||||
|
UI_DIR = $${COMMONS_BUILD_PATH}/ui
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
CONFIG += skip_target_version_ext
|
||||||
|
!isEmpty(STATIC_BUILD):!isEqual(STATIC_BUILD, 0) {
|
||||||
|
win32-g++: QMAKE_LFLAGS = -static-libgcc -static-libstdc++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enable c++11 support in all platforms
|
||||||
|
!CONFIG(c++11): CONFIG += c++11
|
||||||
|
|
||||||
|
!win32: !macx {
|
||||||
|
error("This driver only works in Mac an Windows. For Linux check 'akvcam' instead.")
|
||||||
|
}
|
||||||
|
|
||||||
|
CMD_SEP = $$escape_expand(\n\t)
|
70
dshow/Assistant/Assistant.pro
Normal file
70
dshow/Assistant/Assistant.pro
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../../commons.pri) {
|
||||||
|
include(../../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include(../dshow.pri)
|
||||||
|
include(../../VCamUtils/VCamUtils.pri)
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console link_prl
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
TARGET = $${DSHOW_PLUGIN_ASSISTANT_NAME}
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
src/main.cpp \
|
||||||
|
src/service.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
src/service.h
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
.. \
|
||||||
|
../..
|
||||||
|
|
||||||
|
LIBS += \
|
||||||
|
-L$${OUT_PWD}/../PlatformUtils/$${BIN_DIR} -lPlatformUtils \
|
||||||
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
|
-ladvapi32 \
|
||||||
|
-lgdi32 \
|
||||||
|
-lole32 \
|
||||||
|
-lshell32 \
|
||||||
|
-lstrmiids \
|
||||||
|
-luuid
|
||||||
|
|
||||||
|
win32-g++: LIBS += -lssp
|
||||||
|
|
||||||
|
isEmpty(STATIC_BUILD) | isEqual(STATIC_BUILD, 0) {
|
||||||
|
win32-g++: QMAKE_LFLAGS = -static -static-libgcc -static-libstdc++
|
||||||
|
}
|
||||||
|
|
||||||
|
QMAKE_POST_LINK = \
|
||||||
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/../VirtualCamera/$${DSHOW_PLUGIN_NAME}.plugin/$$normalizedArch(TARGET_ARCH))) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/$${DSHOW_PLUGIN_ASSISTANT_NAME}.exe) $$shell_path($${OUT_PWD}/../VirtualCamera/$${DSHOW_PLUGIN_NAME}.plugin/$$normalizedArch(TARGET_ARCH))
|
67
dshow/Assistant/src/main.cpp
Normal file
67
dshow/Assistant/src/main.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "service.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
auto temp = AkVCam::tempPath();
|
||||||
|
AkLoggerStart(std::string(temp.begin(), temp.end())
|
||||||
|
+ "\\" DSHOW_PLUGIN_ASSISTANT_NAME, "log");
|
||||||
|
AkVCam::Service service;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
if (!strcmp(argv[1], "-i") || !strcmp(argv[1], "--install")) {
|
||||||
|
return service.install()? EXIT_SUCCESS: EXIT_FAILURE;
|
||||||
|
} else if (!strcmp(argv[1], "-u") || !strcmp(argv[1], "--uninstall")) {
|
||||||
|
service.uninstall();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
} else if (!strcmp(argv[1], "-d") || !strcmp(argv[1], "--debug")) {
|
||||||
|
service.debug();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
} else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
|
||||||
|
service.showHelp(argc, argv);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AkLoggerLog("Setting service dispatcher");
|
||||||
|
|
||||||
|
WCHAR serviceName[] = TEXT(DSHOW_PLUGIN_ASSISTANT_NAME);
|
||||||
|
SERVICE_TABLE_ENTRY serviceTable[] = {
|
||||||
|
{serviceName, serviceMain},
|
||||||
|
{nullptr , nullptr }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!StartServiceCtrlDispatcher(serviceTable)) {
|
||||||
|
AkLoggerLog("Service dispatcher failed");
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
925
dshow/Assistant/src/service.cpp
Normal file
925
dshow/Assistant/src/service.cpp
Normal file
|
@ -0,0 +1,925 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <sddl.h>
|
||||||
|
|
||||||
|
#include "service.h"
|
||||||
|
#include "PlatformUtils/src/messageserver.h"
|
||||||
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
#include "VCamUtils/src/image/videoframe.h"
|
||||||
|
#include "VCamUtils/src/timer.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
#define AkServiceLogMethod() \
|
||||||
|
AkLoggerLog("Service::", __FUNCTION__, "()")
|
||||||
|
|
||||||
|
#define AkServicePrivateLogMethod() \
|
||||||
|
AkLoggerLog("ServicePrivate::", __FUNCTION__, "()")
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
struct AssistantDevice
|
||||||
|
{
|
||||||
|
std::string broadcaster;
|
||||||
|
std::vector<std::string> listeners;
|
||||||
|
bool horizontalMirror;
|
||||||
|
bool verticalMirror;
|
||||||
|
Scaling scaling;
|
||||||
|
AspectRatio aspectRatio;
|
||||||
|
bool swapRgb;
|
||||||
|
|
||||||
|
AssistantDevice():
|
||||||
|
horizontalMirror(false),
|
||||||
|
verticalMirror(false),
|
||||||
|
scaling(ScalingFast),
|
||||||
|
aspectRatio(AspectRatioIgnore),
|
||||||
|
swapRgb(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::string> AssistantPeers;
|
||||||
|
typedef std::map<std::string, AssistantDevice> DeviceConfigs;
|
||||||
|
|
||||||
|
class ServicePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SERVICE_STATUS m_status;
|
||||||
|
SERVICE_STATUS_HANDLE m_statusHandler;
|
||||||
|
MessageServer m_messageServer;
|
||||||
|
AssistantPeers m_servers;
|
||||||
|
AssistantPeers m_clients;
|
||||||
|
DeviceConfigs m_deviceConfigs;
|
||||||
|
Timer m_timer;
|
||||||
|
std::mutex m_peerMutex;
|
||||||
|
|
||||||
|
ServicePrivate();
|
||||||
|
static void stateChanged(void *userData,
|
||||||
|
MessageServer::State state);
|
||||||
|
static void checkPeers(void *userData);
|
||||||
|
void sendStatus(DWORD currentState, DWORD exitCode, DWORD wait);
|
||||||
|
inline static uint64_t id();
|
||||||
|
void removePortByName(const std::string &portName);
|
||||||
|
void releaseDevicesFromPeer(const std::string &portName);
|
||||||
|
void requestPort(Message *message);
|
||||||
|
void addPort(Message *message);
|
||||||
|
void removePort(Message *message);
|
||||||
|
void setBroadCasting(Message *message);
|
||||||
|
void setMirroring(Message *message);
|
||||||
|
void setScaling(Message *message);
|
||||||
|
void setAspectRatio(Message *message);
|
||||||
|
void setSwapRgb(Message *message);
|
||||||
|
void frameReady(Message *message);
|
||||||
|
void listeners(Message *message);
|
||||||
|
void listener(Message *message);
|
||||||
|
void broadcasting(Message *message);
|
||||||
|
void mirroring(Message *message);
|
||||||
|
void scaling(Message *message);
|
||||||
|
void aspectRatio(Message *message);
|
||||||
|
void swapRgb(Message *message);
|
||||||
|
void listenerAdd(Message *message);
|
||||||
|
void listenerRemove(Message *message);
|
||||||
|
};
|
||||||
|
|
||||||
|
GLOBAL_STATIC(ServicePrivate, servicePrivate)
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI controlHandler(DWORD control,
|
||||||
|
DWORD eventType,
|
||||||
|
LPVOID eventData,
|
||||||
|
LPVOID context);
|
||||||
|
BOOL WINAPI controlDebugHandler(DWORD control);
|
||||||
|
|
||||||
|
AkVCam::Service::Service()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Service::~Service()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AkVCam::Service::install()
|
||||||
|
{
|
||||||
|
AkServiceLogMethod();
|
||||||
|
WCHAR fileName[MAX_PATH];
|
||||||
|
|
||||||
|
if (!GetModuleFileName(nullptr, fileName, MAX_PATH)) {
|
||||||
|
AkLoggerLog("Can't read module file name");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto scManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
|
||||||
|
|
||||||
|
if (!scManager) {
|
||||||
|
AkLoggerLog("Can't open SCManager");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto service =
|
||||||
|
CreateService(scManager,
|
||||||
|
TEXT(DSHOW_PLUGIN_ASSISTANT_NAME),
|
||||||
|
TEXT(DSHOW_PLUGIN_ASSISTANT_DESCRIPTION),
|
||||||
|
SERVICE_ALL_ACCESS,
|
||||||
|
SERVICE_WIN32_OWN_PROCESS,
|
||||||
|
SERVICE_AUTO_START,
|
||||||
|
SERVICE_ERROR_NORMAL,
|
||||||
|
fileName,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
AkLoggerLog("Can't create service");
|
||||||
|
CloseServiceHandle(scManager);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add detailed description to the service.
|
||||||
|
SERVICE_DESCRIPTION serviceDescription;
|
||||||
|
WCHAR description[] = TEXT(DSHOW_PLUGIN_DESCRIPTION_EXT);
|
||||||
|
serviceDescription.lpDescription = description;
|
||||||
|
auto result =
|
||||||
|
ChangeServiceConfig2(service,
|
||||||
|
SERVICE_CONFIG_DESCRIPTION,
|
||||||
|
&serviceDescription);
|
||||||
|
|
||||||
|
// Configure the service so it will restart if fail.
|
||||||
|
WCHAR rebootMsg[] = L"Service failed restarting...";
|
||||||
|
|
||||||
|
std::vector<SC_ACTION> actions {
|
||||||
|
{SC_ACTION_RESTART, 5000}
|
||||||
|
};
|
||||||
|
|
||||||
|
SERVICE_FAILURE_ACTIONS failureActions {
|
||||||
|
INFINITE,
|
||||||
|
rebootMsg,
|
||||||
|
nullptr,
|
||||||
|
DWORD(actions.size()),
|
||||||
|
actions.data()
|
||||||
|
};
|
||||||
|
|
||||||
|
result =
|
||||||
|
ChangeServiceConfig2(service,
|
||||||
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
||||||
|
&failureActions);
|
||||||
|
|
||||||
|
// Run the service
|
||||||
|
StartService(service, 0, nullptr);
|
||||||
|
CloseServiceHandle(service);
|
||||||
|
CloseServiceHandle(scManager);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Service::uninstall()
|
||||||
|
{
|
||||||
|
AkServiceLogMethod();
|
||||||
|
auto scManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
|
||||||
|
|
||||||
|
if (!scManager) {
|
||||||
|
AkLoggerLog("Can't open SCManager");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sevice = OpenService(scManager,
|
||||||
|
TEXT(DSHOW_PLUGIN_ASSISTANT_NAME),
|
||||||
|
SERVICE_ALL_ACCESS);
|
||||||
|
|
||||||
|
if (sevice) {
|
||||||
|
if (ControlService(sevice,
|
||||||
|
SERVICE_CONTROL_STOP,
|
||||||
|
&servicePrivate()->m_status)) {
|
||||||
|
AkLoggerLog("Stopping service");
|
||||||
|
|
||||||
|
do {
|
||||||
|
Sleep(1000);
|
||||||
|
QueryServiceStatus(sevice, &servicePrivate()->m_status);
|
||||||
|
} while(servicePrivate()->m_status.dwCurrentState != SERVICE_STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DeleteService(sevice)) {
|
||||||
|
AkLoggerLog("Delete service failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(sevice);
|
||||||
|
} else {
|
||||||
|
AkLoggerLog("Can't open service");
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(scManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Service::debug()
|
||||||
|
{
|
||||||
|
AkServiceLogMethod();
|
||||||
|
SetConsoleCtrlHandler(controlDebugHandler, TRUE);
|
||||||
|
servicePrivate()->m_messageServer.start(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Service::showHelp(int argc, char **argv)
|
||||||
|
{
|
||||||
|
AkServiceLogMethod();
|
||||||
|
UNUSED(argc)
|
||||||
|
|
||||||
|
auto programName = strrchr(argv[0], '\\');
|
||||||
|
|
||||||
|
if (!programName)
|
||||||
|
programName = strrchr(argv[0], '/');
|
||||||
|
|
||||||
|
if (!programName)
|
||||||
|
programName = argv[0];
|
||||||
|
else
|
||||||
|
programName++;
|
||||||
|
|
||||||
|
std::cout << "Usage: " << programName << " [options]" << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "Webcamoid virtual camera server." << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "Options:" << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "\t-i, --install\tInstall the service." << std::endl;
|
||||||
|
std::cout << "\t-u, --uninstall\tUnistall the service." << std::endl;
|
||||||
|
std::cout << "\t-d, --debug\tDebug the service." << std::endl;
|
||||||
|
std::cout << "\t-h, --help\tShow this help." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ServicePrivate::ServicePrivate()
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
|
||||||
|
this->m_status = {
|
||||||
|
SERVICE_WIN32_OWN_PROCESS,
|
||||||
|
SERVICE_STOPPED,
|
||||||
|
0,
|
||||||
|
NO_ERROR,
|
||||||
|
NO_ERROR,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
this->m_statusHandler = nullptr;
|
||||||
|
this->m_messageServer.setPipeName(L"\\\\.\\pipe\\" DSHOW_PLUGIN_ASSISTANT_NAME_L);
|
||||||
|
this->m_messageServer.setHandlers({
|
||||||
|
{AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(ServicePrivate::frameReady) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_REQUEST_PORT , AKVCAM_BIND_FUNC(ServicePrivate::requestPort) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_ADD_PORT , AKVCAM_BIND_FUNC(ServicePrivate::addPort) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_REMOVE_PORT , AKVCAM_BIND_FUNC(ServicePrivate::removePort) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(ServicePrivate::listenerAdd) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE, AKVCAM_BIND_FUNC(ServicePrivate::listenerRemove) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS , AKVCAM_BIND_FUNC(ServicePrivate::listeners) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER , AKVCAM_BIND_FUNC(ServicePrivate::listener) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::broadcasting) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING, AKVCAM_BIND_FUNC(ServicePrivate::setBroadCasting)},
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING , AKVCAM_BIND_FUNC(ServicePrivate::mirroring) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING , AKVCAM_BIND_FUNC(ServicePrivate::setMirroring) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SCALING , AKVCAM_BIND_FUNC(ServicePrivate::scaling) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING , AKVCAM_BIND_FUNC(ServicePrivate::setScaling) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO , AKVCAM_BIND_FUNC(ServicePrivate::aspectRatio) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO , AKVCAM_BIND_FUNC(ServicePrivate::setAspectRatio) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB , AKVCAM_BIND_FUNC(ServicePrivate::swapRgb) },
|
||||||
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB , AKVCAM_BIND_FUNC(ServicePrivate::setSwapRgb) },
|
||||||
|
});
|
||||||
|
this->m_timer.setInterval(60000);
|
||||||
|
this->m_timer.connectTimeout(this, &ServicePrivate::checkPeers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::stateChanged(void *userData,
|
||||||
|
MessageServer::State state)
|
||||||
|
{
|
||||||
|
UNUSED(userData)
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case MessageServer::StateAboutToStart:
|
||||||
|
AkVCam::servicePrivate()->sendStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessageServer::StateStarted:
|
||||||
|
AkVCam::servicePrivate()->sendStatus(SERVICE_RUNNING, NO_ERROR, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessageServer::StateAboutToStop:
|
||||||
|
AkVCam::servicePrivate()->sendStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessageServer::StateStopped:
|
||||||
|
AkVCam::servicePrivate()->sendStatus(SERVICE_STOPPED, NO_ERROR, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::checkPeers(void *userData)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<ServicePrivate *>(userData);
|
||||||
|
std::vector<std::string> removePorts;
|
||||||
|
|
||||||
|
self->m_peerMutex.lock();
|
||||||
|
std::vector<AssistantPeers *> allPeers {
|
||||||
|
&self->m_clients,
|
||||||
|
&self->m_servers
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto peers: allPeers)
|
||||||
|
for (auto &peer: *peers) {
|
||||||
|
Message message;
|
||||||
|
message.messageId = AKVCAM_ASSISTANT_MSG_ISALIVE;
|
||||||
|
message.dataSize = sizeof(MsgIsAlive);
|
||||||
|
MessageServer::sendMessage(peer.second, &message);
|
||||||
|
auto requestData = messageData<MsgIsAlive>(&message);
|
||||||
|
|
||||||
|
if (!requestData->alive)
|
||||||
|
removePorts.push_back(peer.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->m_peerMutex.unlock();
|
||||||
|
|
||||||
|
for (auto &port: removePorts) {
|
||||||
|
AkLoggerLog(port, " died, removing...");
|
||||||
|
self->removePortByName(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::sendStatus(DWORD currentState,
|
||||||
|
DWORD exitCode,
|
||||||
|
DWORD wait)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
|
||||||
|
this->m_status.dwControlsAccepted =
|
||||||
|
currentState == SERVICE_START_PENDING? 0: SERVICE_ACCEPT_STOP;
|
||||||
|
this->m_status.dwCurrentState = currentState;
|
||||||
|
this->m_status.dwWin32ExitCode = exitCode;
|
||||||
|
this->m_status.dwWaitHint = wait;
|
||||||
|
|
||||||
|
if (currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED)
|
||||||
|
this->m_status.dwCheckPoint = 0;
|
||||||
|
else
|
||||||
|
this->m_status.dwCheckPoint++;
|
||||||
|
|
||||||
|
SetServiceStatus(this->m_statusHandler, &this->m_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t AkVCam::ServicePrivate::id()
|
||||||
|
{
|
||||||
|
static uint64_t id = 0;
|
||||||
|
|
||||||
|
return id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::removePortByName(const std::string &portName)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
AkLoggerLog("Port: ", portName);
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
std::vector<AssistantPeers *> allPeers {
|
||||||
|
&this->m_clients,
|
||||||
|
&this->m_servers
|
||||||
|
};
|
||||||
|
|
||||||
|
bool breakLoop = false;
|
||||||
|
|
||||||
|
for (auto peers: allPeers) {
|
||||||
|
for (auto &peer: *peers)
|
||||||
|
if (peer.first == portName) {
|
||||||
|
peers->erase(portName);
|
||||||
|
breakLoop = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakLoop)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peersEmpty = this->m_servers.empty() && this->m_clients.empty();
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
|
||||||
|
if (peersEmpty)
|
||||||
|
this->m_timer.stop();
|
||||||
|
|
||||||
|
this->releaseDevicesFromPeer(portName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::releaseDevicesFromPeer(const std::string &portName)
|
||||||
|
{
|
||||||
|
for (auto &config: this->m_deviceConfigs)
|
||||||
|
if (config.second.broadcaster == portName) {
|
||||||
|
config.second.broadcaster.clear();
|
||||||
|
|
||||||
|
Message message;
|
||||||
|
message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING;
|
||||||
|
message.dataSize = sizeof(MsgBroadcasting);
|
||||||
|
auto data = messageData<MsgBroadcasting>(&message);
|
||||||
|
memcpy(data->device,
|
||||||
|
config.first.c_str(),
|
||||||
|
(std::min<size_t>)(config.first.size(), MAX_STRING));
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients)
|
||||||
|
MessageServer::sendMessage(client.second, &message);
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
} else {
|
||||||
|
auto it = std::find(config.second.listeners.begin(),
|
||||||
|
config.second.listeners.end(),
|
||||||
|
portName);
|
||||||
|
|
||||||
|
if (it != config.second.listeners.end())
|
||||||
|
config.second.listeners.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::requestPort(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
|
||||||
|
auto data = messageData<MsgRequestPort>(message);
|
||||||
|
std::string portName = data->client?
|
||||||
|
AKVCAM_ASSISTANT_CLIENT_NAME:
|
||||||
|
AKVCAM_ASSISTANT_SERVER_NAME;
|
||||||
|
portName += std::to_string(this->id());
|
||||||
|
|
||||||
|
AkLoggerLog("Returning Port: ", portName);
|
||||||
|
memcpy(data->port,
|
||||||
|
portName.c_str(),
|
||||||
|
(std::min<size_t>)(portName.size(), MAX_STRING));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::addPort(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
|
||||||
|
auto data = messageData<MsgAddPort>(message);
|
||||||
|
std::string portName(data->port);
|
||||||
|
std::string pipeName(data->pipeName);
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
AssistantPeers *peers;
|
||||||
|
|
||||||
|
if (portName.find(AKVCAM_ASSISTANT_CLIENT_NAME) != std::string::npos)
|
||||||
|
peers = &this->m_clients;
|
||||||
|
else
|
||||||
|
peers = &this->m_servers;
|
||||||
|
|
||||||
|
for (auto &peer: *peers)
|
||||||
|
if (peer.first == portName) {
|
||||||
|
ok = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
AkLoggerLog("Adding Peer: ", portName);
|
||||||
|
(*peers)[portName] = pipeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nPeers = this->m_servers.size() + this->m_clients.size();
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
|
||||||
|
if (ok && nPeers == 1)
|
||||||
|
this->m_timer.start();
|
||||||
|
|
||||||
|
data->status = ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::removePort(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
|
||||||
|
auto data = messageData<MsgRemovePort>(message);
|
||||||
|
this->removePortByName(data->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::setBroadCasting(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgBroadcasting>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
std::string broadcaster(data->broadcaster);
|
||||||
|
data->status = false;
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs[deviceId].broadcaster == broadcaster)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AkLoggerLog("Device: ", deviceId);
|
||||||
|
AkLoggerLog("Broadcaster: ", broadcaster);
|
||||||
|
this->m_deviceConfigs[deviceId].broadcaster = broadcaster;
|
||||||
|
data->status = true;
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients) {
|
||||||
|
Message msg(message);
|
||||||
|
MessageServer::sendMessage(client.second, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::setMirroring(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgMirroring>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
data->status = false;
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs[deviceId].horizontalMirror == data->hmirror
|
||||||
|
&& this->m_deviceConfigs[deviceId].verticalMirror == data->vmirror)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->m_deviceConfigs[deviceId].horizontalMirror = data->hmirror;
|
||||||
|
this->m_deviceConfigs[deviceId].verticalMirror = data->vmirror;
|
||||||
|
data->status = true;
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients) {
|
||||||
|
Message msg(message);
|
||||||
|
MessageServer::sendMessage(client.second, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::setScaling(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgScaling>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
data->status = false;
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs[deviceId].scaling == data->scaling)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->m_deviceConfigs[deviceId].scaling = data->scaling;
|
||||||
|
data->status = true;
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients) {
|
||||||
|
Message msg(message);
|
||||||
|
MessageServer::sendMessage(client.second, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::setAspectRatio(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgAspectRatio>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
data->status = false;
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs[deviceId].aspectRatio == data->aspect)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->m_deviceConfigs[deviceId].aspectRatio = data->aspect;
|
||||||
|
data->status = true;
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients) {
|
||||||
|
Message msg(message);
|
||||||
|
MessageServer::sendMessage(client.second, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::setSwapRgb(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgSwapRgb>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
data->status = false;
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs[deviceId].swapRgb == data->swap)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->m_deviceConfigs[deviceId].swapRgb = data->swap;
|
||||||
|
data->status = true;
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients) {
|
||||||
|
Message msg(message);
|
||||||
|
MessageServer::sendMessage(client.second, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::frameReady(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients)
|
||||||
|
MessageServer::sendMessage(client.second, message);
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::listeners(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgListeners>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
data->nlistener = this->m_deviceConfigs[deviceId].listeners.size();
|
||||||
|
|
||||||
|
if (data->nlistener > 0) {
|
||||||
|
memcpy(data->listener,
|
||||||
|
this->m_deviceConfigs[deviceId].listeners[0].c_str(),
|
||||||
|
std::min<size_t>(this->m_deviceConfigs[deviceId].listeners[0].size(),
|
||||||
|
MAX_STRING));
|
||||||
|
}
|
||||||
|
|
||||||
|
data->status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::listener(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgListeners>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
auto nlistener = this->m_deviceConfigs[deviceId].listeners.size();
|
||||||
|
|
||||||
|
if (data->nlistener >= nlistener) {
|
||||||
|
data->status = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data->listener,
|
||||||
|
this->m_deviceConfigs[deviceId].listeners[data->nlistener].c_str(),
|
||||||
|
std::min<size_t>(this->m_deviceConfigs[deviceId].listeners[data->nlistener].size(),
|
||||||
|
MAX_STRING));
|
||||||
|
|
||||||
|
data->status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::broadcasting(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgBroadcasting>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
memcpy(data->broadcaster,
|
||||||
|
this->m_deviceConfigs[deviceId].broadcaster.c_str(),
|
||||||
|
std::min<size_t>(this->m_deviceConfigs[deviceId].broadcaster.size(),
|
||||||
|
MAX_STRING));
|
||||||
|
data->status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::mirroring(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgMirroring>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
data->hmirror = this->m_deviceConfigs[deviceId].horizontalMirror;
|
||||||
|
data->vmirror = this->m_deviceConfigs[deviceId].verticalMirror;
|
||||||
|
data->status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::scaling(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgScaling>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
data->scaling = this->m_deviceConfigs[deviceId].scaling;
|
||||||
|
data->status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::aspectRatio(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgAspectRatio>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
data->aspect = this->m_deviceConfigs[deviceId].aspectRatio;
|
||||||
|
data->status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::swapRgb(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgSwapRgb>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
data->swap = this->m_deviceConfigs[deviceId].swapRgb;
|
||||||
|
data->status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::listenerAdd(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgListeners>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
auto &listeners = this->m_deviceConfigs[deviceId].listeners;
|
||||||
|
std::string listener(data->listener);
|
||||||
|
auto it = std::find(listeners.begin(), listeners.end(), listener);
|
||||||
|
|
||||||
|
if (it == listeners.end()) {
|
||||||
|
listeners.push_back(listener);
|
||||||
|
data->nlistener = listeners.size();
|
||||||
|
data->status = true;
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients) {
|
||||||
|
Message msg(message);
|
||||||
|
MessageServer::sendMessage(client.second, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
} else {
|
||||||
|
data->nlistener = listeners.size();
|
||||||
|
data->status = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::ServicePrivate::listenerRemove(AkVCam::Message *message)
|
||||||
|
{
|
||||||
|
AkServicePrivateLogMethod();
|
||||||
|
auto data = messageData<MsgListeners>(message);
|
||||||
|
std::string deviceId(data->device);
|
||||||
|
|
||||||
|
if (this->m_deviceConfigs.count(deviceId) < 1)
|
||||||
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
|
|
||||||
|
auto &listeners = this->m_deviceConfigs[deviceId].listeners;
|
||||||
|
std::string listener(data->listener);
|
||||||
|
auto it = std::find(listeners.begin(), listeners.end(), listener);
|
||||||
|
|
||||||
|
if (it != listeners.end()) {
|
||||||
|
listeners.erase(it);
|
||||||
|
data->nlistener = listeners.size();
|
||||||
|
data->status = true;
|
||||||
|
|
||||||
|
this->m_peerMutex.lock();
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients) {
|
||||||
|
Message msg(message);
|
||||||
|
MessageServer::sendMessage(client.second, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_peerMutex.unlock();
|
||||||
|
} else {
|
||||||
|
data->nlistener = listeners.size();
|
||||||
|
data->status = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI controlHandler(DWORD control,
|
||||||
|
DWORD eventType,
|
||||||
|
LPVOID eventData,
|
||||||
|
LPVOID context)
|
||||||
|
{
|
||||||
|
UNUSED(eventType)
|
||||||
|
UNUSED(eventData)
|
||||||
|
UNUSED(context)
|
||||||
|
AkLoggerLog("controlHandler()");
|
||||||
|
|
||||||
|
DWORD result = ERROR_CALL_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
switch (control) {
|
||||||
|
case SERVICE_CONTROL_SHUTDOWN:
|
||||||
|
case SERVICE_CONTROL_STOP:
|
||||||
|
AkVCam::servicePrivate()->sendStatus(SERVICE_STOP_PENDING,
|
||||||
|
NO_ERROR,
|
||||||
|
0);
|
||||||
|
AkVCam::servicePrivate()->m_messageServer.stop();
|
||||||
|
result = NO_ERROR;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
result = NO_ERROR;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto state = AkVCam::servicePrivate()->m_status.dwCurrentState;
|
||||||
|
AkVCam::servicePrivate()->sendStatus(state, NO_ERROR, 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI controlDebugHandler(DWORD control)
|
||||||
|
{
|
||||||
|
AkLoggerLog("controlDebugHandler()");
|
||||||
|
|
||||||
|
if (control == CTRL_BREAK_EVENT || control == CTRL_C_EVENT) {
|
||||||
|
AkVCam::servicePrivate()->m_messageServer.stop();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WINAPI serviceMain(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||||
|
{
|
||||||
|
UNUSED(dwArgc)
|
||||||
|
UNUSED(lpszArgv)
|
||||||
|
AkLoggerLog("serviceMain()");
|
||||||
|
AkLoggerLog("Setting service control handler");
|
||||||
|
|
||||||
|
AkVCam::servicePrivate()->m_statusHandler =
|
||||||
|
RegisterServiceCtrlHandlerEx(TEXT(DSHOW_PLUGIN_ASSISTANT_NAME),
|
||||||
|
controlHandler,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (!AkVCam::servicePrivate()->m_statusHandler)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AkVCam::servicePrivate()->sendStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
|
||||||
|
|
||||||
|
AkLoggerLog("Setting up service");
|
||||||
|
AkVCam::servicePrivate()->m_messageServer
|
||||||
|
.connectStateChanged(AkVCam::servicePrivate(),
|
||||||
|
&AkVCam::ServicePrivate::stateChanged);
|
||||||
|
AkVCam::servicePrivate()->m_messageServer.start(true);
|
||||||
|
}
|
42
dshow/Assistant/src/service.h
Normal file
42
dshow/Assistant/src/service.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SERVICE_H
|
||||||
|
#define SERVICE_H
|
||||||
|
|
||||||
|
#include <minwindef.h>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class Service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Service();
|
||||||
|
~Service();
|
||||||
|
|
||||||
|
BOOL install();
|
||||||
|
void uninstall();
|
||||||
|
void debug();
|
||||||
|
void showHelp(int argc, char **argv);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void WINAPI serviceMain(DWORD dwArgc, LPTSTR *lpszArgv);
|
||||||
|
|
||||||
|
#endif // SERVICE_H
|
63
dshow/PlatformUtils/PlatformUtils.pro
Normal file
63
dshow/PlatformUtils/PlatformUtils.pro
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../../commons.pri) {
|
||||||
|
include(../../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include(../dshow.pri)
|
||||||
|
|
||||||
|
CONFIG += \
|
||||||
|
staticlib \
|
||||||
|
create_prl \
|
||||||
|
no_install_prl
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
TARGET = PlatformUtils
|
||||||
|
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
LIBS = \
|
||||||
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
|
-ladvapi32 \
|
||||||
|
-lkernel32 \
|
||||||
|
-lgdi32 \
|
||||||
|
-lshell32
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
src/messageserver.cpp \
|
||||||
|
src/mutex.cpp \
|
||||||
|
src/utils.cpp \
|
||||||
|
src/sharedmemory.cpp
|
||||||
|
|
||||||
|
HEADERS = \
|
||||||
|
src/messagecommons.h \
|
||||||
|
src/messageserver.h \
|
||||||
|
src/mutex.h \
|
||||||
|
src/utils.h \
|
||||||
|
src/sharedmemory.h
|
||||||
|
|
||||||
|
INCLUDEPATH += ../..
|
211
dshow/PlatformUtils/src/messagecommons.h
Normal file
211
dshow/PlatformUtils/src/messagecommons.h
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MESSAGECOMMONS_H
|
||||||
|
#define MESSAGECOMMONS_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "VCamUtils/src/image/videoframetypes.h"
|
||||||
|
|
||||||
|
#define AKVCAM_ASSISTANT_CLIENT_NAME "AkVCam_Client"
|
||||||
|
#define AKVCAM_ASSISTANT_SERVER_NAME "AkVCam_Server"
|
||||||
|
|
||||||
|
// General messages
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_ISALIVE 0x000
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_FRAME_READY 0x001
|
||||||
|
|
||||||
|
// Assistant messages
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_REQUEST_PORT 0x100
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_ADD_PORT 0x101
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_REMOVE_PORT 0x102
|
||||||
|
|
||||||
|
// Device control and information
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICES 0x200
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_CREATE 0x201
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY 0x202
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION 0x203
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS 0x204
|
||||||
|
|
||||||
|
// Device listeners controls
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS 0x300
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER 0x301
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD 0x302
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE 0x303
|
||||||
|
|
||||||
|
// Device dynamic properties
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING 0x400
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING 0x402
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING 0x403
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SCALING 0x404
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING 0x405
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO 0x406
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO 0x407
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB 0x408
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB 0x409
|
||||||
|
|
||||||
|
#define MSG_BUFFER_SIZE 4096
|
||||||
|
#define MAX_STRING 1024
|
||||||
|
|
||||||
|
#define AKVCAM_BIND_FUNC(member) \
|
||||||
|
std::bind(&member, this, std::placeholders::_1)
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
struct Frame
|
||||||
|
{
|
||||||
|
uint32_t format;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
uint32_t size;
|
||||||
|
uint8_t data[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Message
|
||||||
|
{
|
||||||
|
uint32_t messageId;
|
||||||
|
uint32_t dataSize;
|
||||||
|
uint8_t data[MSG_BUFFER_SIZE];
|
||||||
|
|
||||||
|
Message():
|
||||||
|
messageId(0),
|
||||||
|
dataSize(0)
|
||||||
|
{
|
||||||
|
memset(this->data, 0, MSG_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Message(const Message &other):
|
||||||
|
messageId(other.messageId),
|
||||||
|
dataSize(other.dataSize)
|
||||||
|
{
|
||||||
|
memcpy(this->data, other.data, MSG_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Message(const Message *other):
|
||||||
|
messageId(other->messageId),
|
||||||
|
dataSize(other->dataSize)
|
||||||
|
{
|
||||||
|
memcpy(this->data, other->data, MSG_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Message &operator =(const Message &other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
this->messageId = other.messageId;
|
||||||
|
this->dataSize = other.dataSize;
|
||||||
|
memcpy(this->data, other.data, MSG_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void clear()
|
||||||
|
{
|
||||||
|
this->messageId = 0;
|
||||||
|
this->dataSize = 0;
|
||||||
|
memset(this->data, 0, MSG_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T *messageData(Message *message)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T *>(message->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
using MessageHandler = std::function<void (Message *message)>;
|
||||||
|
|
||||||
|
struct MsgRequestPort
|
||||||
|
{
|
||||||
|
bool client;
|
||||||
|
char port[MAX_STRING];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgAddPort
|
||||||
|
{
|
||||||
|
char port[MAX_STRING];
|
||||||
|
char pipeName[MAX_STRING];
|
||||||
|
bool status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgRemovePort
|
||||||
|
{
|
||||||
|
char port[MAX_STRING];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgBroadcasting
|
||||||
|
{
|
||||||
|
char device[MAX_STRING];
|
||||||
|
char broadcaster[MAX_STRING];
|
||||||
|
bool status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgMirroring
|
||||||
|
{
|
||||||
|
char device[MAX_STRING];
|
||||||
|
bool hmirror;
|
||||||
|
bool vmirror;
|
||||||
|
bool status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgScaling
|
||||||
|
{
|
||||||
|
char device[MAX_STRING];
|
||||||
|
Scaling scaling;
|
||||||
|
bool status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgAspectRatio
|
||||||
|
{
|
||||||
|
char device[MAX_STRING];
|
||||||
|
AspectRatio aspect;
|
||||||
|
bool status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgSwapRgb
|
||||||
|
{
|
||||||
|
char device[MAX_STRING];
|
||||||
|
bool swap;
|
||||||
|
bool status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgListeners
|
||||||
|
{
|
||||||
|
char device[MAX_STRING];
|
||||||
|
char listener[MAX_STRING];
|
||||||
|
size_t nlistener;
|
||||||
|
bool status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgIsAlive
|
||||||
|
{
|
||||||
|
bool alive;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsgFrameReady
|
||||||
|
{
|
||||||
|
char device[MAX_STRING];
|
||||||
|
char port[MAX_STRING];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MESSAGECOMMONS_H
|
455
dshow/PlatformUtils/src/messageserver.cpp
Normal file
455
dshow/PlatformUtils/src/messageserver.cpp
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <sddl.h>
|
||||||
|
|
||||||
|
#include "messageserver.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "MessageServer"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MessageServerPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MessageServer *self;
|
||||||
|
std::wstring m_pipeName;
|
||||||
|
std::map<uint32_t, MessageHandler> m_handlers;
|
||||||
|
MessageServer::ServerMode m_mode {MessageServer::ServerModeReceive};
|
||||||
|
MessageServer::PipeState m_pipeState {MessageServer::PipeStateGone};
|
||||||
|
HANDLE m_pipe {INVALID_HANDLE_VALUE};
|
||||||
|
OVERLAPPED m_overlapped;
|
||||||
|
std::thread m_thread;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
std::condition_variable_any m_exitCheckLoop;
|
||||||
|
int m_checkInterval {5000};
|
||||||
|
bool m_running {false};
|
||||||
|
|
||||||
|
explicit MessageServerPrivate(MessageServer *self);
|
||||||
|
bool startReceive(bool wait=false);
|
||||||
|
void stopReceive(bool wait=false);
|
||||||
|
bool startSend();
|
||||||
|
void stopSend();
|
||||||
|
void messagesLoop();
|
||||||
|
void checkLoop();
|
||||||
|
HRESULT waitResult(DWORD *bytesTransferred);
|
||||||
|
bool readMessage(Message *message);
|
||||||
|
bool writeMessage(const Message &message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MessageServer::MessageServer()
|
||||||
|
{
|
||||||
|
this->d = new MessageServerPrivate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MessageServer::~MessageServer()
|
||||||
|
{
|
||||||
|
this->stop(true);
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring AkVCam::MessageServer::pipeName() const
|
||||||
|
{
|
||||||
|
return this->d->m_pipeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring &AkVCam::MessageServer::pipeName()
|
||||||
|
{
|
||||||
|
return this->d->m_pipeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServer::setPipeName(const std::wstring &pipeName)
|
||||||
|
{
|
||||||
|
this->d->m_pipeName = pipeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MessageServer::ServerMode AkVCam::MessageServer::mode() const
|
||||||
|
{
|
||||||
|
return this->d->m_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MessageServer::ServerMode &AkVCam::MessageServer::mode()
|
||||||
|
{
|
||||||
|
return this->d->m_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServer::setMode(ServerMode mode)
|
||||||
|
{
|
||||||
|
this->d->m_mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::MessageServer::checkInterval() const
|
||||||
|
{
|
||||||
|
return this->d->m_checkInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int &AkVCam::MessageServer::checkInterval()
|
||||||
|
{
|
||||||
|
return this->d->m_checkInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServer::setCheckInterval(int checkInterval)
|
||||||
|
{
|
||||||
|
this->d->m_checkInterval = checkInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServer::setHandlers(const std::map<uint32_t, MessageHandler> &handlers)
|
||||||
|
{
|
||||||
|
this->d->m_handlers = handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::MessageServer::start(bool wait)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
switch (this->d->m_mode) {
|
||||||
|
case ServerModeReceive:
|
||||||
|
AkLoggerLog("Starting mode receive");
|
||||||
|
|
||||||
|
return this->d->startReceive(wait);
|
||||||
|
|
||||||
|
case ServerModeSend:
|
||||||
|
AkLoggerLog("Starting mode send");
|
||||||
|
|
||||||
|
return this->d->startSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServer::stop(bool wait)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_mode == ServerModeReceive)
|
||||||
|
this->d->stopReceive(wait);
|
||||||
|
else
|
||||||
|
this->d->stopSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AkVCam::MessageServer::sendMessage(Message *message,
|
||||||
|
uint32_t timeout)
|
||||||
|
{
|
||||||
|
return this->sendMessage(this->d->m_pipeName, message, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AkVCam::MessageServer::sendMessage(const Message &messageIn,
|
||||||
|
Message *messageOut,
|
||||||
|
uint32_t timeout)
|
||||||
|
{
|
||||||
|
return this->sendMessage(this->d->m_pipeName,
|
||||||
|
messageIn,
|
||||||
|
messageOut,
|
||||||
|
timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AkVCam::MessageServer::sendMessage(const std::string &pipeName,
|
||||||
|
Message *message,
|
||||||
|
uint32_t timeout)
|
||||||
|
{
|
||||||
|
return sendMessage(std::wstring(pipeName.begin(), pipeName.end()),
|
||||||
|
message,
|
||||||
|
timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AkVCam::MessageServer::sendMessage(const std::wstring &pipeName,
|
||||||
|
Message *message,
|
||||||
|
uint32_t timeout)
|
||||||
|
{
|
||||||
|
return sendMessage(pipeName,
|
||||||
|
*message,
|
||||||
|
message,
|
||||||
|
timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AkVCam::MessageServer::sendMessage(const std::wstring &pipeName,
|
||||||
|
const Message &messageIn,
|
||||||
|
Message *messageOut,
|
||||||
|
uint32_t timeout)
|
||||||
|
{
|
||||||
|
DWORD bytesTransferred = 0;
|
||||||
|
|
||||||
|
return CallNamedPipe(pipeName.c_str(),
|
||||||
|
const_cast<Message *>(&messageIn),
|
||||||
|
DWORD(sizeof(Message)),
|
||||||
|
messageOut,
|
||||||
|
DWORD(sizeof(Message)),
|
||||||
|
&bytesTransferred,
|
||||||
|
timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MessageServerPrivate::MessageServerPrivate(MessageServer *self):
|
||||||
|
self(self)
|
||||||
|
{
|
||||||
|
memset(&this->m_overlapped, 0, sizeof(OVERLAPPED));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::MessageServerPrivate::startReceive(bool wait)
|
||||||
|
{
|
||||||
|
AKVCAM_EMIT(this->self, StateChanged, MessageServer::StateAboutToStart)
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
// Define who can read and write from pipe.
|
||||||
|
|
||||||
|
/* Define the SDDL for the DACL.
|
||||||
|
*
|
||||||
|
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa379570(v=vs.85).aspx
|
||||||
|
*/
|
||||||
|
WCHAR descriptor[] =
|
||||||
|
L"D:" // Discretionary ACL
|
||||||
|
L"(D;OICI;GA;;;BG)" // Deny access to Built-in Guests
|
||||||
|
L"(D;OICI;GA;;;AN)" // Deny access to Anonymous Logon
|
||||||
|
L"(A;OICI;GRGWGX;;;AU)" // Allow read/write/execute to Authenticated Users
|
||||||
|
L"(A;OICI;GA;;;BA)"; // Allow full control to Administrators
|
||||||
|
|
||||||
|
SECURITY_ATTRIBUTES securityAttributes;
|
||||||
|
PSECURITY_DESCRIPTOR securityDescriptor =
|
||||||
|
LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
||||||
|
|
||||||
|
if (!securityDescriptor)
|
||||||
|
goto startReceive_failed;
|
||||||
|
|
||||||
|
if (!InitializeSecurityDescriptor(securityDescriptor,
|
||||||
|
SECURITY_DESCRIPTOR_REVISION))
|
||||||
|
goto startReceive_failed;
|
||||||
|
|
||||||
|
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(descriptor,
|
||||||
|
SDDL_REVISION_1,
|
||||||
|
&securityDescriptor,
|
||||||
|
nullptr))
|
||||||
|
goto startReceive_failed;
|
||||||
|
|
||||||
|
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
|
securityAttributes.lpSecurityDescriptor = securityDescriptor;
|
||||||
|
securityAttributes.bInheritHandle = TRUE;
|
||||||
|
|
||||||
|
// Create a read/write message type pipe.
|
||||||
|
this->m_pipe = CreateNamedPipe(this->m_pipeName.c_str(),
|
||||||
|
PIPE_ACCESS_DUPLEX
|
||||||
|
| FILE_FLAG_OVERLAPPED,
|
||||||
|
PIPE_TYPE_MESSAGE
|
||||||
|
| PIPE_READMODE_BYTE
|
||||||
|
| PIPE_WAIT,
|
||||||
|
PIPE_UNLIMITED_INSTANCES,
|
||||||
|
sizeof(Message),
|
||||||
|
sizeof(Message),
|
||||||
|
NMPWAIT_USE_DEFAULT_WAIT,
|
||||||
|
&securityAttributes);
|
||||||
|
|
||||||
|
if (this->m_pipe == INVALID_HANDLE_VALUE)
|
||||||
|
goto startReceive_failed;
|
||||||
|
|
||||||
|
memset(&this->m_overlapped, 0, sizeof(OVERLAPPED));
|
||||||
|
this->m_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
|
AKVCAM_EMIT(this->self, StateChanged, MessageServer::StateStarted)
|
||||||
|
this->m_running = true;
|
||||||
|
|
||||||
|
if (wait)
|
||||||
|
this->messagesLoop();
|
||||||
|
else
|
||||||
|
this->m_thread =
|
||||||
|
std::thread(&MessageServerPrivate::messagesLoop, this);
|
||||||
|
|
||||||
|
ok = true;
|
||||||
|
|
||||||
|
startReceive_failed:
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
AkLoggerLog("Error starting server: ",
|
||||||
|
errorToString(GetLastError()),
|
||||||
|
" (", GetLastError(), ")");
|
||||||
|
AKVCAM_EMIT(this->self, StateChanged, MessageServer::StateStopped)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (securityDescriptor)
|
||||||
|
LocalFree(securityDescriptor);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServerPrivate::stopReceive(bool wait)
|
||||||
|
{
|
||||||
|
if (!this->m_running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->m_running = false;
|
||||||
|
SetEvent(this->m_overlapped.hEvent);
|
||||||
|
|
||||||
|
if (wait)
|
||||||
|
this->m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::MessageServerPrivate::startSend()
|
||||||
|
{
|
||||||
|
this->m_running = true;
|
||||||
|
this->m_thread = std::thread(&MessageServerPrivate::checkLoop, this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServerPrivate::stopSend()
|
||||||
|
{
|
||||||
|
if (!this->m_running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->m_running = false;
|
||||||
|
this->m_mutex.lock();
|
||||||
|
this->m_exitCheckLoop.notify_all();
|
||||||
|
this->m_mutex.unlock();
|
||||||
|
this->m_thread.join();
|
||||||
|
this->m_pipeState = MessageServer::PipeStateGone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServerPrivate::messagesLoop()
|
||||||
|
{
|
||||||
|
DWORD bytesTransferred = 0;
|
||||||
|
|
||||||
|
while (this->m_running) {
|
||||||
|
HRESULT result = S_OK;
|
||||||
|
|
||||||
|
// Wait for a connection.
|
||||||
|
if (!ConnectNamedPipe(this->m_pipe, &this->m_overlapped))
|
||||||
|
result = this->waitResult(&bytesTransferred);
|
||||||
|
|
||||||
|
if (result == S_OK) {
|
||||||
|
Message message;
|
||||||
|
|
||||||
|
if (this->readMessage(&message)) {
|
||||||
|
if (this->m_handlers.count(message.messageId))
|
||||||
|
this->m_handlers[message.messageId](&message);
|
||||||
|
|
||||||
|
this->writeMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisconnectNamedPipe(this->m_pipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
AKVCAM_EMIT(this->self, StateChanged, MessageServer::StateStopped)
|
||||||
|
|
||||||
|
if (this->m_overlapped.hEvent != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(this->m_overlapped.hEvent);
|
||||||
|
memset(&this->m_overlapped, 0, sizeof(OVERLAPPED));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_pipe != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(this->m_pipe);
|
||||||
|
this->m_pipe = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
AKVCAM_EMIT(this->self, StateChanged, MessageServer::StateStopped)
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MessageServerPrivate::checkLoop()
|
||||||
|
{
|
||||||
|
while (this->m_running) {
|
||||||
|
auto result = WaitNamedPipe(this->m_pipeName.c_str(), NMPWAIT_NOWAIT);
|
||||||
|
|
||||||
|
if (result
|
||||||
|
&& this->m_pipeState != AkVCam::MessageServer::PipeStateAvailable) {
|
||||||
|
AkLoggerLog("Pipe Available: ",
|
||||||
|
std::string(this->m_pipeName.begin(),
|
||||||
|
this->m_pipeName.end()));
|
||||||
|
this->m_pipeState = AkVCam::MessageServer::PipeStateAvailable;
|
||||||
|
AKVCAM_EMIT(this->self, PipeStateChanged, this->m_pipeState);
|
||||||
|
} else if (!result
|
||||||
|
&& this->m_pipeState != AkVCam::MessageServer::PipeStateGone
|
||||||
|
&& GetLastError() != ERROR_SEM_TIMEOUT) {
|
||||||
|
AkLoggerLog("Pipe Gone: ",
|
||||||
|
std::string(this->m_pipeName.begin(),
|
||||||
|
this->m_pipeName.end()));
|
||||||
|
this->m_pipeState = AkVCam::MessageServer::PipeStateGone;
|
||||||
|
AKVCAM_EMIT(this->self, PipeStateChanged, this->m_pipeState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->m_running)
|
||||||
|
break;
|
||||||
|
|
||||||
|
this->m_mutex.lock();
|
||||||
|
this->m_exitCheckLoop.wait_for(this->m_mutex,
|
||||||
|
std::chrono::milliseconds(this->m_checkInterval));
|
||||||
|
this->m_mutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MessageServerPrivate::waitResult(DWORD *bytesTransferred)
|
||||||
|
{
|
||||||
|
auto lastError = GetLastError();
|
||||||
|
|
||||||
|
if (lastError == ERROR_IO_PENDING) {
|
||||||
|
if (WaitForSingleObject(this->m_overlapped.hEvent,
|
||||||
|
INFINITE) == WAIT_OBJECT_0) {
|
||||||
|
if (!GetOverlappedResult(this->m_pipe,
|
||||||
|
&this->m_overlapped,
|
||||||
|
bytesTransferred,
|
||||||
|
FALSE))
|
||||||
|
return S_FALSE;
|
||||||
|
} else {
|
||||||
|
CancelIo(this->m_pipe);
|
||||||
|
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AkLoggerLog("Wait result failed: ",
|
||||||
|
errorToString(lastError),
|
||||||
|
" (", lastError, ")");
|
||||||
|
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::MessageServerPrivate::readMessage(Message *message)
|
||||||
|
{
|
||||||
|
DWORD bytesTransferred = 0;
|
||||||
|
HRESULT result = S_OK;
|
||||||
|
|
||||||
|
if (!ReadFile(this->m_pipe,
|
||||||
|
message,
|
||||||
|
DWORD(sizeof(Message)),
|
||||||
|
&bytesTransferred,
|
||||||
|
&this->m_overlapped))
|
||||||
|
result = this->waitResult(&bytesTransferred);
|
||||||
|
|
||||||
|
return result == S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::MessageServerPrivate::writeMessage(const Message &message)
|
||||||
|
{
|
||||||
|
DWORD bytesTransferred = 0;
|
||||||
|
HRESULT result = S_OK;
|
||||||
|
|
||||||
|
if (!WriteFile(this->m_pipe,
|
||||||
|
&message,
|
||||||
|
DWORD(sizeof(Message)),
|
||||||
|
&bytesTransferred,
|
||||||
|
&this->m_overlapped))
|
||||||
|
result = this->waitResult(&bytesTransferred);
|
||||||
|
|
||||||
|
return result == S_OK;
|
||||||
|
}
|
104
dshow/PlatformUtils/src/messageserver.h
Normal file
104
dshow/PlatformUtils/src/messageserver.h
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MESSAGESERVER_H
|
||||||
|
#define MESSAGESERVER_H
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <map>
|
||||||
|
#include <minwindef.h>
|
||||||
|
|
||||||
|
#include "messagecommons.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define MSERVER_TIMEOUT_DEFAULT 0
|
||||||
|
#define MSERVER_TIMEOUT_MIN 1
|
||||||
|
#define MSERVER_TIMEOUT_MAX (std::numeric_limits<uint32_t>::max)()
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MessageServerPrivate;
|
||||||
|
|
||||||
|
class MessageServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ServerMode
|
||||||
|
{
|
||||||
|
ServerModeReceive,
|
||||||
|
ServerModeSend
|
||||||
|
};
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
StateAboutToStart,
|
||||||
|
StateStarted,
|
||||||
|
StateAboutToStop,
|
||||||
|
StateStopped
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PipeState
|
||||||
|
{
|
||||||
|
PipeStateAvailable,
|
||||||
|
PipeStateGone
|
||||||
|
};
|
||||||
|
|
||||||
|
AKVCAM_SIGNAL(StateChanged, State state)
|
||||||
|
AKVCAM_SIGNAL(PipeStateChanged, PipeState state)
|
||||||
|
|
||||||
|
public:
|
||||||
|
MessageServer();
|
||||||
|
MessageServer(const MessageServer &other) = delete;
|
||||||
|
~MessageServer();
|
||||||
|
|
||||||
|
std::wstring pipeName() const;
|
||||||
|
std::wstring &pipeName();
|
||||||
|
void setPipeName(const std::wstring &pipeName);
|
||||||
|
ServerMode mode() const;
|
||||||
|
ServerMode &mode();
|
||||||
|
void setMode(ServerMode mode);
|
||||||
|
int checkInterval() const;
|
||||||
|
int &checkInterval();
|
||||||
|
void setCheckInterval(int checkInterval);
|
||||||
|
void setHandlers(const std::map<uint32_t,
|
||||||
|
MessageHandler> &handlers);
|
||||||
|
bool start(bool wait=false);
|
||||||
|
void stop(bool wait=false);
|
||||||
|
BOOL sendMessage(Message *message,
|
||||||
|
uint32_t timeout=MSERVER_TIMEOUT_MAX);
|
||||||
|
BOOL sendMessage(const Message &messageIn,
|
||||||
|
Message *messageOut,
|
||||||
|
uint32_t timeout=MSERVER_TIMEOUT_MAX);
|
||||||
|
static BOOL sendMessage(const std::string &pipeName,
|
||||||
|
Message *message,
|
||||||
|
uint32_t timeout=MSERVER_TIMEOUT_MAX);
|
||||||
|
static BOOL sendMessage(const std::wstring &pipeName,
|
||||||
|
Message *message,
|
||||||
|
uint32_t timeout=MSERVER_TIMEOUT_MAX);
|
||||||
|
static BOOL sendMessage(const std::wstring &pipeName,
|
||||||
|
const Message &messageIn,
|
||||||
|
Message *messageOut,
|
||||||
|
uint32_t timeout=MSERVER_TIMEOUT_MAX);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MessageServerPrivate *d;
|
||||||
|
friend class MessageServerPrivate;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MESSAGESERVER_H
|
110
dshow/PlatformUtils/src/mutex.cpp
Normal file
110
dshow/PlatformUtils/src/mutex.cpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "mutex.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MutexPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HANDLE m_mutex;
|
||||||
|
std::wstring m_name;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Mutex::Mutex(const std::wstring &name)
|
||||||
|
{
|
||||||
|
this->d = new MutexPrivate();
|
||||||
|
this->d->m_mutex = CreateMutex(nullptr,
|
||||||
|
FALSE,
|
||||||
|
name.empty()?
|
||||||
|
nullptr: name.c_str());
|
||||||
|
this->d->m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Mutex::Mutex(const Mutex &other)
|
||||||
|
{
|
||||||
|
this->d = new MutexPrivate();
|
||||||
|
this->d->m_mutex = CreateMutex(nullptr,
|
||||||
|
FALSE,
|
||||||
|
other.d->m_name.empty()?
|
||||||
|
nullptr: other.d->m_name.c_str());
|
||||||
|
this->d->m_name = other.d->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Mutex::~Mutex()
|
||||||
|
{
|
||||||
|
if (this->d->m_mutex)
|
||||||
|
CloseHandle(this->d->m_mutex);
|
||||||
|
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Mutex &AkVCam::Mutex::operator =(const Mutex &other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
this->unlock();
|
||||||
|
|
||||||
|
if (this->d->m_mutex)
|
||||||
|
CloseHandle(this->d->m_mutex);
|
||||||
|
|
||||||
|
this->d->m_mutex = CreateMutex(nullptr,
|
||||||
|
FALSE,
|
||||||
|
other.d->m_name.empty()?
|
||||||
|
nullptr: other.d->m_name.c_str());
|
||||||
|
this->d->m_name = other.d->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring AkVCam::Mutex::name() const
|
||||||
|
{
|
||||||
|
return this->d->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Mutex::lock()
|
||||||
|
{
|
||||||
|
if (!this->d->m_mutex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
WaitForSingleObject(this->d->m_mutex, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::Mutex::tryLock(int timeout)
|
||||||
|
{
|
||||||
|
if (!this->d->m_mutex)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DWORD waitResult = WaitForSingleObject(this->d->m_mutex,
|
||||||
|
!timeout? INFINITE: DWORD(timeout));
|
||||||
|
|
||||||
|
return waitResult != WAIT_FAILED && waitResult != WAIT_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Mutex::unlock()
|
||||||
|
{
|
||||||
|
if (!this->d->m_mutex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ReleaseMutex(this->d->m_mutex);
|
||||||
|
}
|
47
dshow/PlatformUtils/src/mutex.h
Normal file
47
dshow/PlatformUtils/src/mutex.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MUTEX_H
|
||||||
|
#define MUTEX_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MutexPrivate;
|
||||||
|
|
||||||
|
class Mutex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Mutex(const std::wstring &name={});
|
||||||
|
Mutex(const Mutex &other);
|
||||||
|
~Mutex();
|
||||||
|
Mutex &operator =(const Mutex &other);
|
||||||
|
|
||||||
|
std::wstring name() const;
|
||||||
|
void lock();
|
||||||
|
bool tryLock(int timeout=0);
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MutexPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MUTEX_H
|
204
dshow/PlatformUtils/src/sharedmemory.cpp
Normal file
204
dshow/PlatformUtils/src/sharedmemory.cpp
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "sharedmemory.h"
|
||||||
|
#include "mutex.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class SharedMemoryPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HANDLE m_sharedHandle;
|
||||||
|
std::wstring m_name;
|
||||||
|
void *m_buffer;
|
||||||
|
size_t m_pageSize;
|
||||||
|
SharedMemory::OpenMode m_mode;
|
||||||
|
bool m_isOpen;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::SharedMemory::SharedMemory()
|
||||||
|
{
|
||||||
|
this->d = new SharedMemoryPrivate;
|
||||||
|
this->d->m_sharedHandle = nullptr;
|
||||||
|
this->d->m_buffer = nullptr;
|
||||||
|
this->d->m_pageSize = 0;
|
||||||
|
this->d->m_mode = OpenModeRead;
|
||||||
|
this->d->m_isOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::SharedMemory::SharedMemory(const SharedMemory &other)
|
||||||
|
{
|
||||||
|
this->d = new SharedMemoryPrivate;
|
||||||
|
this->d->m_sharedHandle = nullptr;
|
||||||
|
this->d->m_name = other.d->m_name;
|
||||||
|
this->d->m_buffer = nullptr;
|
||||||
|
this->d->m_pageSize = 0;
|
||||||
|
this->d->m_mode = OpenModeRead;
|
||||||
|
this->d->m_isOpen = false;
|
||||||
|
|
||||||
|
if (other.d->m_isOpen)
|
||||||
|
this->open(other.d->m_pageSize, other.d->m_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::SharedMemory::~SharedMemory()
|
||||||
|
{
|
||||||
|
this->close();
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::SharedMemory &AkVCam::SharedMemory::operator =(const SharedMemory &other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
this->close();
|
||||||
|
this->d->m_name = other.d->m_name;
|
||||||
|
this->d->m_buffer = nullptr;
|
||||||
|
this->d->m_pageSize = 0;
|
||||||
|
this->d->m_mode = OpenModeRead;
|
||||||
|
this->d->m_isOpen = false;
|
||||||
|
|
||||||
|
if (other.d->m_isOpen)
|
||||||
|
this->open(other.d->m_pageSize, other.d->m_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring AkVCam::SharedMemory::name() const
|
||||||
|
{
|
||||||
|
return this->d->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring &AkVCam::SharedMemory::name()
|
||||||
|
{
|
||||||
|
return this->d->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::SharedMemory::setName(const std::wstring &name)
|
||||||
|
{
|
||||||
|
this->d->m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::SharedMemory::open(size_t pageSize, OpenMode mode)
|
||||||
|
{
|
||||||
|
if (this->d->m_isOpen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this->d->m_name.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mode == OpenModeRead) {
|
||||||
|
this->d->m_sharedHandle =
|
||||||
|
OpenFileMapping(FILE_MAP_ALL_ACCESS,
|
||||||
|
FALSE,
|
||||||
|
this->d->m_name.c_str());
|
||||||
|
} else {
|
||||||
|
if (pageSize < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->d->m_sharedHandle =
|
||||||
|
CreateFileMapping(INVALID_HANDLE_VALUE,
|
||||||
|
nullptr,
|
||||||
|
PAGE_READWRITE,
|
||||||
|
0,
|
||||||
|
DWORD(pageSize),
|
||||||
|
this->d->m_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->d->m_sharedHandle) {
|
||||||
|
AkLoggerLog("Error opening shared memory (",
|
||||||
|
std::string(this->d->m_name.begin(),
|
||||||
|
this->d->m_name.end()),
|
||||||
|
"): ",
|
||||||
|
errorToString(GetLastError()),
|
||||||
|
" (", GetLastError(), ")");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->d->m_buffer = MapViewOfFile(this->d->m_sharedHandle,
|
||||||
|
FILE_MAP_ALL_ACCESS,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
pageSize);
|
||||||
|
|
||||||
|
if (!this->d->m_buffer) {
|
||||||
|
CloseHandle(this->d->m_sharedHandle);
|
||||||
|
this->d->m_sharedHandle = nullptr;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->d->m_pageSize = pageSize;
|
||||||
|
this->d->m_mode = mode;
|
||||||
|
this->d->m_isOpen = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::SharedMemory::isOpen() const
|
||||||
|
{
|
||||||
|
return this->d->m_isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::SharedMemory::pageSize() const
|
||||||
|
{
|
||||||
|
return this->d->m_pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::SharedMemory::OpenMode AkVCam::SharedMemory::mode() const
|
||||||
|
{
|
||||||
|
return this->d->m_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *AkVCam::SharedMemory::lock(AkVCam::Mutex *mutex, int timeout)
|
||||||
|
{
|
||||||
|
if (mutex && !mutex->tryLock(timeout))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return this->d->m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::SharedMemory::unlock(AkVCam::Mutex *mutex)
|
||||||
|
{
|
||||||
|
if (mutex)
|
||||||
|
mutex->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::SharedMemory::close()
|
||||||
|
{
|
||||||
|
if (this->d->m_buffer) {
|
||||||
|
UnmapViewOfFile(this->d->m_buffer);
|
||||||
|
this->d->m_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->d->m_sharedHandle) {
|
||||||
|
CloseHandle(this->d->m_sharedHandle);
|
||||||
|
this->d->m_sharedHandle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->d->m_pageSize = 0;
|
||||||
|
this->d->m_mode = OpenModeRead;
|
||||||
|
this->d->m_isOpen = false;
|
||||||
|
}
|
60
dshow/PlatformUtils/src/sharedmemory.h
Normal file
60
dshow/PlatformUtils/src/sharedmemory.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHAREDMEMORY_H
|
||||||
|
#define SHAREDMEMORY_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class SharedMemoryPrivate;
|
||||||
|
class Mutex;
|
||||||
|
|
||||||
|
class SharedMemory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum OpenMode
|
||||||
|
{
|
||||||
|
OpenModeRead,
|
||||||
|
OpenModeWrite
|
||||||
|
};
|
||||||
|
|
||||||
|
SharedMemory();
|
||||||
|
SharedMemory(const SharedMemory &other);
|
||||||
|
~SharedMemory();
|
||||||
|
SharedMemory &operator =(const SharedMemory &other);
|
||||||
|
|
||||||
|
std::wstring name() const;
|
||||||
|
std::wstring &name();
|
||||||
|
void setName(const std::wstring &name);
|
||||||
|
bool open(size_t pageSize=0, OpenMode mode=OpenModeRead);
|
||||||
|
bool isOpen() const;
|
||||||
|
size_t pageSize() const;
|
||||||
|
OpenMode mode() const;
|
||||||
|
void *lock(Mutex *mutex=nullptr, int timeout=0);
|
||||||
|
void unlock(Mutex *mutex=nullptr);
|
||||||
|
void close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedMemoryPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SHAREDMEMORY_H
|
1140
dshow/PlatformUtils/src/utils.cpp
Normal file
1140
dshow/PlatformUtils/src/utils.cpp
Normal file
File diff suppressed because it is too large
Load diff
97
dshow/PlatformUtils/src/utils.h
Normal file
97
dshow/PlatformUtils/src/utils.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLATFORM_UTILS_H
|
||||||
|
#define PLATFORM_UTILS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <strmif.h>
|
||||||
|
|
||||||
|
#include "VCamUtils/src/image/videoformattypes.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
#define AkLogInterface(interface, instance) \
|
||||||
|
AkLoggerLog("Returning ", #interface, "(", instance, ")")
|
||||||
|
|
||||||
|
#define AkLogMethod() \
|
||||||
|
AkLoggerLog(AK_CUR_INTERFACE, "(", this, ")::", __FUNCTION__, "()")
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class VideoFormat;
|
||||||
|
|
||||||
|
BOOL isWow64();
|
||||||
|
std::wstring tempPath();
|
||||||
|
std::wstring programFilesPath();
|
||||||
|
std::wstring moduleFileNameW(HINSTANCE hinstDLL);
|
||||||
|
std::string moduleFileName(HINSTANCE hinstDLL);
|
||||||
|
std::wstring errorToStringW(DWORD errorCode);
|
||||||
|
std::string errorToString(DWORD errorCode);
|
||||||
|
CLSID createClsidFromStr(const std::string &str);
|
||||||
|
CLSID createClsidFromStr(const std::wstring &str);
|
||||||
|
std::wstring createClsidWStrFromStr(const std::string &str);
|
||||||
|
std::wstring createClsidWStrFromStr(const std::wstring &str);
|
||||||
|
std::string stringFromIid(const IID &iid);
|
||||||
|
std::wstring wstringFromIid(const IID &iid);
|
||||||
|
std::string stringFromResult(HRESULT result);
|
||||||
|
std::string stringFromClsid(const CLSID &clsid);
|
||||||
|
wchar_t *wcharStrFromWStr(const std::wstring &wstr);
|
||||||
|
FourCC formatFromGuid(const GUID &guid);
|
||||||
|
const GUID &guidFromFormat(FourCC format);
|
||||||
|
DWORD compressionFromFormat(FourCC format);
|
||||||
|
bool isSubTypeSupported(const GUID &subType);
|
||||||
|
AM_MEDIA_TYPE *mediaTypeFromFormat(const VideoFormat &format);
|
||||||
|
VideoFormat formatFromMediaType(const AM_MEDIA_TYPE *mediaType);
|
||||||
|
bool isEqualMediaType(const AM_MEDIA_TYPE *mediaType1,
|
||||||
|
const AM_MEDIA_TYPE *mediaType2,
|
||||||
|
bool exact=false);
|
||||||
|
bool copyMediaType(AM_MEDIA_TYPE *dstMediaType,
|
||||||
|
const AM_MEDIA_TYPE *srcMediaType);
|
||||||
|
AM_MEDIA_TYPE *createMediaType(const AM_MEDIA_TYPE *mediaType);
|
||||||
|
void deleteMediaType(AM_MEDIA_TYPE **mediaType);
|
||||||
|
bool containsMediaType(const AM_MEDIA_TYPE *mediaType,
|
||||||
|
IEnumMediaTypes *mediaTypes);
|
||||||
|
std::string stringFromMajorType(const GUID &majorType);
|
||||||
|
std::string stringFromSubType(const GUID &subType);
|
||||||
|
std::string stringFromFormatType(const GUID &formatType);
|
||||||
|
std::string stringFromMediaType(const AM_MEDIA_TYPE *mediaType);
|
||||||
|
std::string stringFromMediaSample(IMediaSample *mediaSample);
|
||||||
|
LONG regGetValue(HKEY hkey,
|
||||||
|
LPCWSTR lpSubKey,
|
||||||
|
LPCWSTR lpValue,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPDWORD pdwType,
|
||||||
|
PVOID pvData,
|
||||||
|
LPDWORD pcbData);
|
||||||
|
std::vector<CLSID> listRegisteredCameras(HINSTANCE hinstDLL);
|
||||||
|
DWORD camerasCount();
|
||||||
|
std::wstring createDevicePath();
|
||||||
|
int cameraFromId(const std::wstring &path);
|
||||||
|
int cameraFromId(const CLSID &clsid);
|
||||||
|
bool cameraExists(const std::string &path);
|
||||||
|
bool cameraExists(const std::wstring &path);
|
||||||
|
std::wstring cameraDescription(DWORD cameraIndex);
|
||||||
|
std::wstring cameraPath(DWORD cameraIndex);
|
||||||
|
std::wstring cameraPath(const CLSID &clsid);
|
||||||
|
DWORD formatsCount(DWORD cameraIndex);
|
||||||
|
VideoFormat cameraFormat(DWORD cameraIndex, DWORD formatIndex);
|
||||||
|
std::vector<VideoFormat> cameraFormats(DWORD cameraIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // PLATFORM_UTILS_H
|
65
dshow/VCamIPC/VCamIPC.pro
Normal file
65
dshow/VCamIPC/VCamIPC.pro
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../../commons.pri) {
|
||||||
|
include(../../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include(../dshow.pri)
|
||||||
|
|
||||||
|
CONFIG += \
|
||||||
|
staticlib \
|
||||||
|
create_prl \
|
||||||
|
no_install_prl
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
TARGET = VCamIPC
|
||||||
|
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
LIBS = \
|
||||||
|
-L$${OUT_PWD}/../PlatformUtils/$${BIN_DIR} -lPlatformUtils \
|
||||||
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
|
-ladvapi32 \
|
||||||
|
-lkernel32 \
|
||||||
|
-lpsapi \
|
||||||
|
-lrstrmgr
|
||||||
|
|
||||||
|
win32-g++: LIBS += -lssp
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
src/ipcbridge.cpp
|
||||||
|
|
||||||
|
HEADERS = \
|
||||||
|
../../ipcbridge.h
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
.. \
|
||||||
|
../..
|
||||||
|
|
||||||
|
DEFINES += \
|
||||||
|
DSHOW_PLUGIN_ARCH=\"\\\"$$normalizedArch(TARGET_ARCH)\\\"\" \
|
||||||
|
DSHOW_PLUGIN_ARCH_L=\"L\\\"$$normalizedArch(TARGET_ARCH)\\\"\"
|
2120
dshow/VCamIPC/src/ipcbridge.cpp
Normal file
2120
dshow/VCamIPC/src/ipcbridge.cpp
Normal file
File diff suppressed because it is too large
Load diff
26
dshow/VirtualCamera/VirtualCamera.def
Normal file
26
dshow/VirtualCamera/VirtualCamera.def
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
; akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
; Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
;
|
||||||
|
; akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
;
|
||||||
|
; Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
LIBRARY VirtualCameraSource.dll
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
DllMain PRIVATE
|
||||||
|
DllGetClassObject PRIVATE
|
||||||
|
DllCanUnloadNow PRIVATE
|
||||||
|
DllRegisterServer PRIVATE
|
||||||
|
DllUnregisterServer PRIVATE
|
130
dshow/VirtualCamera/VirtualCamera.pro
Normal file
130
dshow/VirtualCamera/VirtualCamera.pro
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
# akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
# Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
#
|
||||||
|
# akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Web-Site: http://webcamoid.github.io/
|
||||||
|
|
||||||
|
exists(commons.pri) {
|
||||||
|
include(commons.pri)
|
||||||
|
} else {
|
||||||
|
exists(../../commons.pri) {
|
||||||
|
include(../../commons.pri)
|
||||||
|
} else {
|
||||||
|
error("commons.pri file not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include(../dshow.pri)
|
||||||
|
include(../../VCamUtils/VCamUtils.pri)
|
||||||
|
|
||||||
|
CONFIG -= qt
|
||||||
|
CONFIG += link_prl
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
.. \
|
||||||
|
../..
|
||||||
|
|
||||||
|
LIBS += \
|
||||||
|
-L$${OUT_PWD}/../VCamIPC/$${BIN_DIR} -lVCamIPC \
|
||||||
|
-L$${OUT_PWD}/../PlatformUtils/$${BIN_DIR} -lPlatformUtils \
|
||||||
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
|
-ladvapi32 \
|
||||||
|
-lgdi32 \
|
||||||
|
-lkernel32 \
|
||||||
|
-lole32 \
|
||||||
|
-loleaut32 \
|
||||||
|
-lpsapi \
|
||||||
|
-lshell32 \
|
||||||
|
-lstrmiids \
|
||||||
|
-luser32 \
|
||||||
|
-luuid \
|
||||||
|
-lwinmm
|
||||||
|
|
||||||
|
TARGET = $${DSHOW_PLUGIN_NAME}
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
src/basefilter.h \
|
||||||
|
src/classfactory.h \
|
||||||
|
src/cunknown.h \
|
||||||
|
src/enummediatypes.h \
|
||||||
|
src/enumpins.h \
|
||||||
|
src/filtermiscflags.h \
|
||||||
|
src/latency.h \
|
||||||
|
src/mediafilter.h \
|
||||||
|
src/mediasample.h \
|
||||||
|
src/mediasample2.h \
|
||||||
|
src/memallocator.h \
|
||||||
|
src/persist.h \
|
||||||
|
src/persistpropertybag.h \
|
||||||
|
src/pin.h \
|
||||||
|
src/plugin.h \
|
||||||
|
src/plugininterface.h \
|
||||||
|
src/propertyset.h \
|
||||||
|
src/pushsource.h \
|
||||||
|
src/qualitycontrol.h \
|
||||||
|
src/referenceclock.h \
|
||||||
|
src/specifypropertypages.h \
|
||||||
|
src/streamconfig.h \
|
||||||
|
src/videocontrol.h \
|
||||||
|
src/videoprocamp.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
src/basefilter.cpp \
|
||||||
|
src/classfactory.cpp \
|
||||||
|
src/cunknown.cpp \
|
||||||
|
src/enummediatypes.cpp \
|
||||||
|
src/enumpins.cpp \
|
||||||
|
src/filtermiscflags.cpp \
|
||||||
|
src/latency.cpp \
|
||||||
|
src/mediafilter.cpp \
|
||||||
|
src/mediasample.cpp \
|
||||||
|
src/mediasample2.cpp \
|
||||||
|
src/memallocator.cpp \
|
||||||
|
src/persist.cpp \
|
||||||
|
src/persistpropertybag.cpp \
|
||||||
|
src/pin.cpp \
|
||||||
|
src/plugin.cpp \
|
||||||
|
src/plugininterface.cpp \
|
||||||
|
src/propertyset.cpp \
|
||||||
|
src/pushsource.cpp \
|
||||||
|
src/qualitycontrol.cpp \
|
||||||
|
src/referenceclock.cpp \
|
||||||
|
src/specifypropertypages.cpp \
|
||||||
|
src/streamconfig.cpp \
|
||||||
|
src/videocontrol.cpp \
|
||||||
|
src/videoprocamp.cpp
|
||||||
|
|
||||||
|
DESTDIR = $${OUT_PWD}/$${BIN_DIR}
|
||||||
|
|
||||||
|
OTHER_FILES = \
|
||||||
|
VirtualCamera.def
|
||||||
|
|
||||||
|
DEF_FILE = VirtualCamera.def
|
||||||
|
|
||||||
|
isEmpty(STATIC_BUILD) | isEqual(STATIC_BUILD, 0) {
|
||||||
|
win32-g++: QMAKE_LFLAGS = -static -static-libgcc -static-libstdc++
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTALLS += vcam
|
||||||
|
vcam.files = $${OUT_PWD}/$${TARGET}.plugin
|
||||||
|
vcam.path = $${DATAROOTDIR}
|
||||||
|
vcam.CONFIG += no_check_exist
|
||||||
|
|
||||||
|
QMAKE_POST_LINK = \
|
||||||
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/$${TARGET}.plugin/$$normalizedArch(TARGET_ARCH))) $${CMD_SEP} \
|
||||||
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/$${TARGET}.plugin/share)) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/$${TARGET}.dll) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/$$normalizedArch(TARGET_ARCH)) $${CMD_SEP} \
|
||||||
|
$(COPY) $$shell_path($${PWD}/../../share/TestFrame/TestFrame.bmp) $$shell_path($${OUT_PWD}/$${TARGET}.plugin/share)
|
524
dshow/VirtualCamera/src/basefilter.cpp
Normal file
524
dshow/VirtualCamera/src/basefilter.cpp
Normal file
|
@ -0,0 +1,524 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <dshow.h>
|
||||||
|
|
||||||
|
#include "basefilter.h"
|
||||||
|
#include "enumpins.h"
|
||||||
|
#include "filtermiscflags.h"
|
||||||
|
#include "pin.h"
|
||||||
|
#include "referenceclock.h"
|
||||||
|
#include "specifypropertypages.h"
|
||||||
|
#include "videocontrol.h"
|
||||||
|
#include "videoprocamp.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "BaseFilter"
|
||||||
|
|
||||||
|
#define AkBaseFilterPrivateLog() \
|
||||||
|
AkLoggerLog("BaseFilterPrivate::", __FUNCTION__, "()")
|
||||||
|
|
||||||
|
#define AkVCamPinCall(pins, func, ...) \
|
||||||
|
pins->Reset(); \
|
||||||
|
Pin *pin = nullptr; \
|
||||||
|
\
|
||||||
|
while (pins->Next(1, reinterpret_cast<IPin **>(&pin), nullptr) == S_OK) { \
|
||||||
|
pin->func(__VA_ARGS__); \
|
||||||
|
pin->Release(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AkVCamDevicePinCall(deviceId, where, func, ...) \
|
||||||
|
if (auto pins = where->pinsForDevice(deviceId)) { \
|
||||||
|
AkVCamPinCall(pins, func, __VA_ARGS__) \
|
||||||
|
pins->Release(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class BaseFilterPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaseFilter *self;
|
||||||
|
EnumPins *m_pins;
|
||||||
|
VideoProcAmp *m_videoProcAmp;
|
||||||
|
ReferenceClock *m_referenceClock;
|
||||||
|
std::wstring m_vendor;
|
||||||
|
std::wstring m_filterName;
|
||||||
|
IFilterGraph *m_filterGraph;
|
||||||
|
IpcBridge m_ipcBridge;
|
||||||
|
|
||||||
|
BaseFilterPrivate(BaseFilter *self,
|
||||||
|
const std::wstring &filterName,
|
||||||
|
const std::wstring &vendor);
|
||||||
|
BaseFilterPrivate(const BaseFilterPrivate &other) = delete;
|
||||||
|
~BaseFilterPrivate();
|
||||||
|
IEnumPins *pinsForDevice(const std::string &deviceId);
|
||||||
|
void updatePins();
|
||||||
|
static void serverStateChanged(void *userData,
|
||||||
|
IpcBridge::ServerState state);
|
||||||
|
static void frameReady(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const VideoFrame &frame);
|
||||||
|
static void setBroadcasting(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const std::string &broadcasting);
|
||||||
|
static void setMirror(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool horizontalMirror,
|
||||||
|
bool verticalMirror);
|
||||||
|
static void setScaling(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
Scaling scaling);
|
||||||
|
static void setAspectRatio(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
AspectRatio aspectRatio);
|
||||||
|
static void setSwapRgb(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool swap);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::BaseFilter::BaseFilter(const GUID &clsid,
|
||||||
|
const std::wstring &filterName,
|
||||||
|
const std::wstring &vendor):
|
||||||
|
MediaFilter(clsid, this)
|
||||||
|
{
|
||||||
|
this->setParent(this, &IID_IBaseFilter);
|
||||||
|
this->d = new BaseFilterPrivate(this, filterName, vendor);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::BaseFilter::~BaseFilter()
|
||||||
|
{
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilter::addPin(const std::vector<AkVCam::VideoFormat> &formats,
|
||||||
|
const std::wstring &pinName,
|
||||||
|
bool changed)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_pins->addPin(new Pin(this, formats, pinName), changed);
|
||||||
|
|
||||||
|
if (this->d->m_pins->count() == 1)
|
||||||
|
this->d->m_ipcBridge.connectService(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilter::removePin(IPin *pin, bool changed)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_ipcBridge.disconnectService();
|
||||||
|
this->d->m_pins->removePin(pin, changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::BaseFilter *AkVCam::BaseFilter::create(const GUID &clsid)
|
||||||
|
{
|
||||||
|
AkLoggerLog("BaseFilter::create()");
|
||||||
|
auto camera = cameraFromId(clsid);
|
||||||
|
AkLoggerLog("CLSID: ", stringFromClsid(clsid));
|
||||||
|
AkLoggerLog("ID: ", camera);
|
||||||
|
|
||||||
|
if (camera < 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto description = cameraDescription(DWORD(camera));
|
||||||
|
AkLoggerLog("Description: ", std::string(description.begin(),
|
||||||
|
description.end()));
|
||||||
|
auto baseFilter = new BaseFilter(clsid,
|
||||||
|
description,
|
||||||
|
DSHOW_PLUGIN_VENDOR_L);
|
||||||
|
auto formats = cameraFormats(DWORD(camera));
|
||||||
|
baseFilter->addPin(formats, L"Video", false);
|
||||||
|
|
||||||
|
return baseFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFilterGraph *AkVCam::BaseFilter::filterGraph() const
|
||||||
|
{
|
||||||
|
return this->d->m_filterGraph;
|
||||||
|
}
|
||||||
|
|
||||||
|
IReferenceClock *AkVCam::BaseFilter::referenceClock() const
|
||||||
|
{
|
||||||
|
return this->d->m_referenceClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::BaseFilter::QueryInterface(const IID &riid, void **ppvObject)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
AkLoggerLog("IID: ", AkVCam::stringFromClsid(riid));
|
||||||
|
|
||||||
|
if (!ppvObject)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*ppvObject = nullptr;
|
||||||
|
|
||||||
|
if (IsEqualIID(riid, IID_IUnknown)
|
||||||
|
|| IsEqualIID(riid, IID_IBaseFilter)
|
||||||
|
|| IsEqualIID(riid, IID_IMediaFilter)) {
|
||||||
|
AkLogInterface(IBaseFilter, this);
|
||||||
|
this->AddRef();
|
||||||
|
*ppvObject = this;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else if (IsEqualIID(riid, IID_IAMFilterMiscFlags)) {
|
||||||
|
auto filterMiscFlags = new FilterMiscFlags;
|
||||||
|
AkLogInterface(IAMFilterMiscFlags, filterMiscFlags);
|
||||||
|
filterMiscFlags->AddRef();
|
||||||
|
*ppvObject = filterMiscFlags;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else if (IsEqualIID(riid, IID_IAMVideoControl)) {
|
||||||
|
IEnumPins *pins = nullptr;
|
||||||
|
this->d->m_pins->Clone(&pins);
|
||||||
|
auto videoControl = new VideoControl(pins);
|
||||||
|
pins->Release();
|
||||||
|
AkLogInterface(IAMVideoControl, videoControl);
|
||||||
|
videoControl->AddRef();
|
||||||
|
*ppvObject = videoControl;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else if (IsEqualIID(riid, IID_IAMVideoProcAmp)) {
|
||||||
|
auto videoProcAmp = this->d->m_videoProcAmp;
|
||||||
|
AkLogInterface(IAMVideoProcAmp, videoProcAmp);
|
||||||
|
videoProcAmp->AddRef();
|
||||||
|
*ppvObject = videoProcAmp;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else if (IsEqualIID(riid, IID_IReferenceClock)) {
|
||||||
|
auto referenceClock = this->d->m_referenceClock;
|
||||||
|
AkLogInterface(IReferenceClock, referenceClock);
|
||||||
|
referenceClock->AddRef();
|
||||||
|
*ppvObject = referenceClock;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else if (IsEqualIID(riid, IID_ISpecifyPropertyPages)) {
|
||||||
|
this->d->m_pins->Reset();
|
||||||
|
IPin *pin = nullptr;
|
||||||
|
this->d->m_pins->Next(1, &pin, nullptr);
|
||||||
|
auto specifyPropertyPages = new SpecifyPropertyPages(pin);
|
||||||
|
pin->Release();
|
||||||
|
AkLogInterface(ISpecifyPropertyPages, specifyPropertyPages);
|
||||||
|
specifyPropertyPages->AddRef();
|
||||||
|
*ppvObject = specifyPropertyPages;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else {
|
||||||
|
this->d->m_pins->Reset();
|
||||||
|
IPin *pin = nullptr;
|
||||||
|
this->d->m_pins->Next(1, &pin, nullptr);
|
||||||
|
auto result = pin->QueryInterface(riid, ppvObject);
|
||||||
|
pin->Release();
|
||||||
|
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MediaFilter::QueryInterface(riid, ppvObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::BaseFilter::EnumPins(IEnumPins **ppEnum)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!this->d->m_pins)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
auto result = this->d->m_pins->Clone(ppEnum);
|
||||||
|
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
(*ppEnum)->Reset();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::BaseFilter::FindPin(LPCWSTR Id, IPin **ppPin)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!ppPin)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*ppPin = nullptr;
|
||||||
|
|
||||||
|
if (!Id)
|
||||||
|
return VFW_E_NOT_FOUND;
|
||||||
|
|
||||||
|
IPin *pin = nullptr;
|
||||||
|
HRESULT result = VFW_E_NOT_FOUND;
|
||||||
|
this->d->m_pins->Reset();
|
||||||
|
|
||||||
|
while (this->d->m_pins->Next(1, &pin, nullptr) == S_OK) {
|
||||||
|
WCHAR *pinId = nullptr;
|
||||||
|
auto ok = pin->QueryId(&pinId);
|
||||||
|
|
||||||
|
if (ok == S_OK && wcscmp(pinId, Id) == 0) {
|
||||||
|
*ppPin = pin;
|
||||||
|
(*ppPin)->AddRef();
|
||||||
|
result = S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoTaskMemFree(pinId);
|
||||||
|
pin->Release();
|
||||||
|
pin = nullptr;
|
||||||
|
|
||||||
|
if (result == S_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::BaseFilter::QueryFilterInfo(FILTER_INFO *pInfo)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!pInfo)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
memset(pInfo->achName, 0, MAX_FILTER_NAME * sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (this->d->m_filterName.size() > 0) {
|
||||||
|
memcpy(pInfo->achName,
|
||||||
|
this->d->m_filterName.c_str(),
|
||||||
|
std::max<size_t>(this->d->m_filterName.size() * sizeof(WCHAR),
|
||||||
|
MAX_FILTER_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
pInfo->pGraph = this->d->m_filterGraph;
|
||||||
|
|
||||||
|
if (pInfo->pGraph)
|
||||||
|
pInfo->pGraph->AddRef();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::BaseFilter::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
this->d->m_filterGraph = pGraph;
|
||||||
|
this->d->m_filterName = std::wstring(pName? pName: L"");
|
||||||
|
|
||||||
|
AkLoggerLog("Filter graph: ", this->d->m_filterGraph);
|
||||||
|
AkLoggerLog("Name: ", std::string(this->d->m_filterName.begin(),
|
||||||
|
this->d->m_filterName.end()));
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::BaseFilter::QueryVendorInfo(LPWSTR *pVendorInfo)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_vendor.size() < 1)
|
||||||
|
return E_NOTIMPL;
|
||||||
|
|
||||||
|
if (!pVendorInfo)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*pVendorInfo = wcharStrFromWStr(this->d->m_vendor);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilter::stateChanged(FILTER_STATE state)
|
||||||
|
{
|
||||||
|
CLSID clsid;
|
||||||
|
this->GetClassID(&clsid);
|
||||||
|
auto path = cameraPath(clsid);
|
||||||
|
std::string deviceId(path.begin(), path.end());
|
||||||
|
|
||||||
|
if (state == State_Running)
|
||||||
|
this->d->m_ipcBridge.addListener(deviceId);
|
||||||
|
else
|
||||||
|
this->d->m_ipcBridge.removeListener(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::BaseFilterPrivate::BaseFilterPrivate(AkVCam::BaseFilter *self,
|
||||||
|
const std::wstring &filterName,
|
||||||
|
const std::wstring &vendor):
|
||||||
|
self(self),
|
||||||
|
m_pins(new AkVCam::EnumPins),
|
||||||
|
m_videoProcAmp(new VideoProcAmp),
|
||||||
|
m_referenceClock(new ReferenceClock),
|
||||||
|
m_vendor(vendor),
|
||||||
|
m_filterName(filterName),
|
||||||
|
m_filterGraph(nullptr)
|
||||||
|
{
|
||||||
|
this->m_pins->AddRef();
|
||||||
|
this->m_videoProcAmp->AddRef();
|
||||||
|
this->m_referenceClock->AddRef();
|
||||||
|
|
||||||
|
this->m_ipcBridge.connectServerStateChanged(this,
|
||||||
|
&BaseFilterPrivate::serverStateChanged);
|
||||||
|
this->m_ipcBridge.connectFrameReady(this,
|
||||||
|
&BaseFilterPrivate::frameReady);
|
||||||
|
this->m_ipcBridge.connectBroadcastingChanged(this,
|
||||||
|
&BaseFilterPrivate::setBroadcasting);
|
||||||
|
this->m_ipcBridge.connectMirrorChanged(this,
|
||||||
|
&BaseFilterPrivate::setMirror);
|
||||||
|
this->m_ipcBridge.connectScalingChanged(this,
|
||||||
|
&BaseFilterPrivate::setScaling);
|
||||||
|
this->m_ipcBridge.connectAspectRatioChanged(this,
|
||||||
|
&BaseFilterPrivate::setAspectRatio);
|
||||||
|
this->m_ipcBridge.connectSwapRgbChanged(this,
|
||||||
|
&BaseFilterPrivate::setSwapRgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::BaseFilterPrivate::~BaseFilterPrivate()
|
||||||
|
{
|
||||||
|
this->m_ipcBridge.disconnectService();
|
||||||
|
this->m_pins->setBaseFilter(nullptr);
|
||||||
|
this->m_pins->Release();
|
||||||
|
this->m_videoProcAmp->Release();
|
||||||
|
this->m_referenceClock->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumPins *AkVCam::BaseFilterPrivate::pinsForDevice(const std::string &deviceId)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
CLSID clsid;
|
||||||
|
self->GetClassID(&clsid);
|
||||||
|
auto path = cameraPath(clsid);
|
||||||
|
|
||||||
|
if (path.empty() || std::string(path.begin(), path.end()) != deviceId)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
IEnumPins *pins = nullptr;
|
||||||
|
self->EnumPins(&pins);
|
||||||
|
|
||||||
|
return pins;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::updatePins()
|
||||||
|
{
|
||||||
|
CLSID clsid;
|
||||||
|
this->self->GetClassID(&clsid);
|
||||||
|
auto path = cameraPath(clsid);
|
||||||
|
std::string deviceId(path.begin(), path.end());
|
||||||
|
|
||||||
|
auto broadcaster = this->m_ipcBridge.broadcaster(deviceId);
|
||||||
|
AkVCamDevicePinCall(deviceId,
|
||||||
|
this,
|
||||||
|
setBroadcasting,
|
||||||
|
broadcaster);
|
||||||
|
auto hmirror = this->m_ipcBridge.isHorizontalMirrored(deviceId);
|
||||||
|
auto vmirror = this->m_ipcBridge.isVerticalMirrored(deviceId);
|
||||||
|
AkVCamDevicePinCall(deviceId,
|
||||||
|
this,
|
||||||
|
setMirror,
|
||||||
|
hmirror,
|
||||||
|
vmirror);
|
||||||
|
auto scaling = this->m_ipcBridge.scalingMode(deviceId);
|
||||||
|
AkVCamDevicePinCall(deviceId,
|
||||||
|
this,
|
||||||
|
setScaling,
|
||||||
|
scaling);
|
||||||
|
auto aspect = this->m_ipcBridge.aspectRatioMode(deviceId);
|
||||||
|
AkVCamDevicePinCall(deviceId,
|
||||||
|
this,
|
||||||
|
setAspectRatio,
|
||||||
|
aspect);
|
||||||
|
auto swap = this->m_ipcBridge.swapRgb(deviceId);
|
||||||
|
AkVCamDevicePinCall(deviceId,
|
||||||
|
this,
|
||||||
|
setSwapRgb,
|
||||||
|
swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::serverStateChanged(void *userData,
|
||||||
|
IpcBridge::ServerState state)
|
||||||
|
{
|
||||||
|
AkBaseFilterPrivateLog();
|
||||||
|
auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
|
||||||
|
IEnumPins *pins = nullptr;
|
||||||
|
self->self->EnumPins(&pins);
|
||||||
|
|
||||||
|
if (pins) {
|
||||||
|
AkVCamPinCall(pins, serverStateChanged, state)
|
||||||
|
pins->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == IpcBridge::ServerStateAvailable)
|
||||||
|
self->updatePins();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::frameReady(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const VideoFrame &frame)
|
||||||
|
{
|
||||||
|
AkBaseFilterPrivateLog();
|
||||||
|
auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
|
||||||
|
AkVCamDevicePinCall(deviceId, self, frameReady, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::setBroadcasting(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
const std::string &broadcaster)
|
||||||
|
{
|
||||||
|
AkBaseFilterPrivateLog();
|
||||||
|
auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
|
||||||
|
AkVCamDevicePinCall(deviceId, self, setBroadcasting, broadcaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::setMirror(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool horizontalMirror,
|
||||||
|
bool verticalMirror)
|
||||||
|
{
|
||||||
|
AkBaseFilterPrivateLog();
|
||||||
|
auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
|
||||||
|
AkVCamDevicePinCall(deviceId,
|
||||||
|
self,
|
||||||
|
setMirror,
|
||||||
|
horizontalMirror,
|
||||||
|
verticalMirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::setScaling(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
Scaling scaling)
|
||||||
|
{
|
||||||
|
AkBaseFilterPrivateLog();
|
||||||
|
auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
|
||||||
|
AkVCamDevicePinCall(deviceId, self, setScaling, scaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::setAspectRatio(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
AspectRatio aspectRatio)
|
||||||
|
{
|
||||||
|
AkBaseFilterPrivateLog();
|
||||||
|
auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
|
||||||
|
AkVCamDevicePinCall(deviceId, self, setAspectRatio, aspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::setSwapRgb(void *userData,
|
||||||
|
const std::string &deviceId,
|
||||||
|
bool swap)
|
||||||
|
{
|
||||||
|
AkBaseFilterPrivateLog();
|
||||||
|
auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
|
||||||
|
AkVCamDevicePinCall(deviceId, self, setSwapRgb, swap);
|
||||||
|
}
|
73
dshow/VirtualCamera/src/basefilter.h
Normal file
73
dshow/VirtualCamera/src/basefilter.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BASEFILTER_H
|
||||||
|
#define BASEFILTER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "mediafilter.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class BaseFilterPrivate;
|
||||||
|
class VideoFormat;
|
||||||
|
|
||||||
|
class BaseFilter:
|
||||||
|
public IBaseFilter,
|
||||||
|
public MediaFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaseFilter(const GUID &clsid,
|
||||||
|
const std::wstring &filterName={},
|
||||||
|
const std::wstring &vendor={});
|
||||||
|
virtual ~BaseFilter();
|
||||||
|
|
||||||
|
void addPin(const std::vector<VideoFormat> &formats={},
|
||||||
|
const std::wstring &pinName={},
|
||||||
|
bool changed=true);
|
||||||
|
void removePin(IPin *pin, bool changed=true);
|
||||||
|
static BaseFilter *create(const GUID &clsid);
|
||||||
|
IFilterGraph *filterGraph() const;
|
||||||
|
IReferenceClock *referenceClock() const;
|
||||||
|
|
||||||
|
DECLARE_IMEDIAFILTER_NQ
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
|
||||||
|
void **ppvObject);
|
||||||
|
|
||||||
|
// IBaseFilter
|
||||||
|
HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
|
||||||
|
HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
|
||||||
|
HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph,
|
||||||
|
LPCWSTR pName);
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BaseFilterPrivate *d;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void stateChanged(FILTER_STATE state);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BASEFILTER_H
|
121
dshow/VirtualCamera/src/classfactory.cpp
Normal file
121
dshow/VirtualCamera/src/classfactory.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "classfactory.h"
|
||||||
|
#include "basefilter.h"
|
||||||
|
#include "persistpropertybag.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "ClassFactory"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class ClassFactoryPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CLSID m_clsid;
|
||||||
|
static int m_locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
int ClassFactoryPrivate::m_locked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ClassFactory::ClassFactory(const CLSID &clsid):
|
||||||
|
CUnknown(this, IID_IClassFactory)
|
||||||
|
{
|
||||||
|
this->d = new ClassFactoryPrivate;
|
||||||
|
this->d->m_clsid = clsid;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::ClassFactory::~ClassFactory()
|
||||||
|
{
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::ClassFactory::locked()
|
||||||
|
{
|
||||||
|
return ClassFactoryPrivate::m_locked > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::ClassFactory::QueryInterface(const IID &riid, void **ppvObject)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
AkLoggerLog("IID: ", AkVCam::stringFromClsid(riid));
|
||||||
|
|
||||||
|
if (!ppvObject)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*ppvObject = nullptr;
|
||||||
|
|
||||||
|
if (IsEqualIID(riid, IID_IUnknown)
|
||||||
|
|| IsEqualIID(riid, IID_IClassFactory)) {
|
||||||
|
AkLogInterface(IClassFactory, this);
|
||||||
|
this->AddRef();
|
||||||
|
*ppvObject = this;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else if (IsEqualIID(riid, IID_IPersistPropertyBag)) {
|
||||||
|
auto persistPropertyBag = new PersistPropertyBag(this->d->m_clsid);
|
||||||
|
AkLogInterface(IPersistPropertyBag, persistPropertyBag);
|
||||||
|
persistPropertyBag->AddRef();
|
||||||
|
*ppvObject = persistPropertyBag;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else if (IsEqualIID(riid, IID_IBaseFilter)) {
|
||||||
|
auto baseFilter = BaseFilter::create(this->d->m_clsid);
|
||||||
|
AkLogInterface(IBaseFilter, baseFilter);
|
||||||
|
baseFilter->AddRef();
|
||||||
|
*ppvObject = baseFilter;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CUnknown::QueryInterface(riid, ppvObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::ClassFactory::CreateInstance(IUnknown *pUnkOuter,
|
||||||
|
const IID &riid,
|
||||||
|
void **ppvObject)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
AkLoggerLog("Outer: ", ULONG_PTR(pUnkOuter));
|
||||||
|
AkLoggerLog("IID: ", stringFromClsid(riid));
|
||||||
|
|
||||||
|
if (!ppvObject)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
*ppvObject = nullptr;
|
||||||
|
|
||||||
|
if (pUnkOuter && !IsEqualIID(riid, IID_IUnknown))
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
|
||||||
|
this->AddRef();
|
||||||
|
*ppvObject = this;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::ClassFactory::LockServer(BOOL fLock)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_locked += fLock? 1: -1;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
56
dshow/VirtualCamera/src/classfactory.h
Normal file
56
dshow/VirtualCamera/src/classfactory.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLASSFACTORY_H
|
||||||
|
#define CLASSFACTORY_H
|
||||||
|
|
||||||
|
#include "cunknown.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class ClassFactoryPrivate;
|
||||||
|
|
||||||
|
class ClassFactory:
|
||||||
|
public IClassFactory,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClassFactory(const CLSID &clsid);
|
||||||
|
virtual ~ClassFactory();
|
||||||
|
|
||||||
|
static bool locked();
|
||||||
|
|
||||||
|
DECLARE_IUNKNOWN_NQ
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
|
||||||
|
void **ppvObject);
|
||||||
|
|
||||||
|
// IClassFactory
|
||||||
|
HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter,
|
||||||
|
REFIID riid,
|
||||||
|
void **ppvObject);
|
||||||
|
HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClassFactoryPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CLASSFACTORY_H
|
118
dshow/VirtualCamera/src/cunknown.cpp
Normal file
118
dshow/VirtualCamera/src/cunknown.cpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "cunknown.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AkCUnknownLogMethod() \
|
||||||
|
AkLoggerLog((this->d->m_parent? \
|
||||||
|
stringFromClsid(this->d->m_parentCLSID): \
|
||||||
|
std::string("CUnknown")), \
|
||||||
|
"(", (this->d->m_parent? this->d->m_parent: this), \
|
||||||
|
")::", __FUNCTION__, "()")
|
||||||
|
|
||||||
|
#define AkCUnknownLogThis() \
|
||||||
|
AkLoggerLog("Returning ", \
|
||||||
|
(this->d->m_parent? \
|
||||||
|
stringFromClsid(this->d->m_parentCLSID): \
|
||||||
|
std::string("CUnknown")), \
|
||||||
|
"(", (this->d->m_parent? this->d->m_parent: this), ")")
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class CUnknownPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::atomic<ULONG> m_ref;
|
||||||
|
CUnknown *m_parent;
|
||||||
|
CLSID m_parentCLSID;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::CUnknown::CUnknown(CUnknown *parent, REFIID parentCLSID)
|
||||||
|
{
|
||||||
|
this->d = new CUnknownPrivate;
|
||||||
|
this->d->m_ref = 0;
|
||||||
|
this->d->m_parent = parent;
|
||||||
|
this->d->m_parentCLSID = parentCLSID;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::CUnknown::~CUnknown()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::CUnknown::setParent(AkVCam::CUnknown *parent,
|
||||||
|
const IID *parentCLSID)
|
||||||
|
{
|
||||||
|
this->d->m_parent = parent;
|
||||||
|
this->d->m_parentCLSID = parentCLSID? *parentCLSID: GUID_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AkVCam::CUnknown::ref() const
|
||||||
|
{
|
||||||
|
return this->d->m_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::CUnknown::QueryInterface(const IID &riid, void **ppvObject)
|
||||||
|
{
|
||||||
|
AkCUnknownLogMethod();
|
||||||
|
AkLoggerLog("IID: ", AkVCam::stringFromClsid(riid));
|
||||||
|
|
||||||
|
if (!ppvObject)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*ppvObject = nullptr;
|
||||||
|
|
||||||
|
if (IsEqualIID(riid, IID_IUnknown)
|
||||||
|
|| IsEqualIID(riid, this->d->m_parentCLSID)) {
|
||||||
|
AkCUnknownLogThis();
|
||||||
|
this->d->m_parent->AddRef();
|
||||||
|
*ppvObject = this->d->m_parent;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else {
|
||||||
|
AkLoggerLog("Unknown interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AkVCam::CUnknown::AddRef()
|
||||||
|
{
|
||||||
|
AkCUnknownLogMethod();
|
||||||
|
this->d->m_ref++;
|
||||||
|
AkLoggerLog("REF: ", this->d->m_ref);
|
||||||
|
|
||||||
|
return this->d->m_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AkVCam::CUnknown::Release()
|
||||||
|
{
|
||||||
|
AkCUnknownLogMethod();
|
||||||
|
AkLoggerLog("REF: ", this->d->m_ref);
|
||||||
|
|
||||||
|
if (this->d->m_ref)
|
||||||
|
this->d->m_ref--;
|
||||||
|
|
||||||
|
return this->d->m_ref;
|
||||||
|
}
|
108
dshow/VirtualCamera/src/cunknown.h
Normal file
108
dshow/VirtualCamera/src/cunknown.h
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CUNKNOWN_H
|
||||||
|
#define CUNKNOWN_H
|
||||||
|
|
||||||
|
#include <unknwnbase.h>
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class CUnknownPrivate;
|
||||||
|
|
||||||
|
class CUnknown: public IUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CUnknown(CUnknown *parent, REFIID parentCLSID);
|
||||||
|
virtual ~CUnknown();
|
||||||
|
|
||||||
|
void setParent(CUnknown *parent, const IID *parentCLSID=nullptr);
|
||||||
|
ULONG ref() const;
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
|
||||||
|
void **ppvObject);
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef();
|
||||||
|
ULONG STDMETHODCALLTYPE Release();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CUnknownPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IUNKNOWN_Q(interfaceIid) \
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, \
|
||||||
|
void **ppvObject) \
|
||||||
|
{ \
|
||||||
|
if (!ppvObject) \
|
||||||
|
return E_POINTER; \
|
||||||
|
\
|
||||||
|
*ppvObject = nullptr; \
|
||||||
|
\
|
||||||
|
if (IsEqualIID(riid, interfaceIid)) { \
|
||||||
|
this->AddRef(); \
|
||||||
|
*ppvObject = this; \
|
||||||
|
\
|
||||||
|
return S_OK; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return CUnknown::QueryInterface(riid, ppvObject); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IUNKNOWN_R \
|
||||||
|
ULONG STDMETHODCALLTYPE Release() \
|
||||||
|
{ \
|
||||||
|
auto result = CUnknown::Release(); \
|
||||||
|
\
|
||||||
|
if (!result) \
|
||||||
|
delete this; \
|
||||||
|
\
|
||||||
|
return result; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IUNKNOWN_NQR \
|
||||||
|
ULONG ref() const \
|
||||||
|
{ \
|
||||||
|
return CUnknown::ref(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void setParent(CUnknown *parent, const IID *parentCLSID=nullptr) \
|
||||||
|
{ \
|
||||||
|
return CUnknown::setParent(parent, parentCLSID); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef() \
|
||||||
|
{ \
|
||||||
|
return CUnknown::AddRef(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IUNKNOWN_NQ \
|
||||||
|
DECLARE_IUNKNOWN_NQR \
|
||||||
|
DECLARE_IUNKNOWN_R
|
||||||
|
|
||||||
|
#define DECLARE_IUNKNOWN_NR(interfaceIid) \
|
||||||
|
DECLARE_IUNKNOWN_NQR \
|
||||||
|
DECLARE_IUNKNOWN_Q(interfaceIid)
|
||||||
|
|
||||||
|
#define DECLARE_IUNKNOWN(interfaceIid) \
|
||||||
|
DECLARE_IUNKNOWN_NQR \
|
||||||
|
DECLARE_IUNKNOWN_Q(interfaceIid) \
|
||||||
|
DECLARE_IUNKNOWN_R
|
||||||
|
|
||||||
|
#endif // CUNKNOWN_H
|
181
dshow/VirtualCamera/src/enummediatypes.cpp
Normal file
181
dshow/VirtualCamera/src/enummediatypes.cpp
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dshow.h>
|
||||||
|
|
||||||
|
#include "enummediatypes.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "EnumMediaTypes"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class EnumMediaTypesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<VideoFormat> m_formats;
|
||||||
|
size_t m_position;
|
||||||
|
bool m_changed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::EnumMediaTypes::EnumMediaTypes(const std::vector<VideoFormat> &formats):
|
||||||
|
CUnknown(this, IID_IEnumMediaTypes)
|
||||||
|
{
|
||||||
|
this->d = new EnumMediaTypesPrivate;
|
||||||
|
this->d->m_formats = formats;
|
||||||
|
this->d->m_position = 0;
|
||||||
|
this->d->m_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::EnumMediaTypes::EnumMediaTypes(const AkVCam::EnumMediaTypes &other):
|
||||||
|
CUnknown(this, IID_IEnumMediaTypes)
|
||||||
|
{
|
||||||
|
this->d = new EnumMediaTypesPrivate;
|
||||||
|
this->d->m_formats = other.d->m_formats;
|
||||||
|
this->d->m_position = other.d->m_position;
|
||||||
|
this->d->m_changed = other.d->m_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::EnumMediaTypes &AkVCam::EnumMediaTypes::operator =(const EnumMediaTypes &other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
this->d->m_formats = other.d->m_formats;
|
||||||
|
this->d->m_position = other.d->m_position;
|
||||||
|
this->d->m_changed = other.d->m_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::EnumMediaTypes::~EnumMediaTypes()
|
||||||
|
{
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AkVCam::VideoFormat> &AkVCam::EnumMediaTypes::formats()
|
||||||
|
{
|
||||||
|
return this->d->m_formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AkVCam::VideoFormat> AkVCam::EnumMediaTypes::formats() const
|
||||||
|
{
|
||||||
|
return this->d->m_formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::EnumMediaTypes::setFormats(const std::vector<AkVCam::VideoFormat> &formats,
|
||||||
|
bool changed)
|
||||||
|
{
|
||||||
|
if (this->d->m_formats == formats)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->d->m_formats = formats;
|
||||||
|
this->d->m_changed = changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::EnumMediaTypes::Next(ULONG cMediaTypes,
|
||||||
|
AM_MEDIA_TYPE **ppMediaTypes,
|
||||||
|
ULONG *pcFetched)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (pcFetched)
|
||||||
|
*pcFetched = 0;
|
||||||
|
|
||||||
|
if (!cMediaTypes)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (!ppMediaTypes)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
memset(ppMediaTypes, 0, cMediaTypes * sizeof(AM_MEDIA_TYPE *));
|
||||||
|
|
||||||
|
if (this->d->m_changed) {
|
||||||
|
this->d->m_changed = false;
|
||||||
|
|
||||||
|
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG fetched = 0;
|
||||||
|
|
||||||
|
for (;
|
||||||
|
fetched < cMediaTypes
|
||||||
|
&& this->d->m_position < this->d->m_formats.size();
|
||||||
|
fetched++, this->d->m_position++) {
|
||||||
|
*ppMediaTypes = mediaTypeFromFormat(this->d->m_formats[this->d->m_position]);
|
||||||
|
|
||||||
|
if (*ppMediaTypes)
|
||||||
|
ppMediaTypes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcFetched)
|
||||||
|
*pcFetched = fetched;
|
||||||
|
|
||||||
|
return fetched == cMediaTypes? S_OK: S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::EnumMediaTypes::Skip(ULONG cMediaTypes)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
AkLoggerLog("Skip ", cMediaTypes, " media types");
|
||||||
|
|
||||||
|
if (this->d->m_changed) {
|
||||||
|
this->d->m_changed = false;
|
||||||
|
|
||||||
|
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto position = this->d->m_position + cMediaTypes;
|
||||||
|
|
||||||
|
if (position > this->d->m_formats.size())
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
this->d->m_position = position;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::EnumMediaTypes::Reset()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_position = 0;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::EnumMediaTypes::Clone(IEnumMediaTypes **ppEnum)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!ppEnum)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
if (this->d->m_changed) {
|
||||||
|
this->d->m_changed = false;
|
||||||
|
|
||||||
|
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppEnum = new EnumMediaTypes(*this);
|
||||||
|
(*ppEnum)->AddRef();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
63
dshow/VirtualCamera/src/enummediatypes.h
Normal file
63
dshow/VirtualCamera/src/enummediatypes.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ENUMMEDIATYPES_H
|
||||||
|
#define ENUMMEDIATYPES_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <strmif.h>
|
||||||
|
|
||||||
|
#include "cunknown.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class EnumMediaTypesPrivate;
|
||||||
|
class VideoFormat;
|
||||||
|
|
||||||
|
class EnumMediaTypes:
|
||||||
|
public IEnumMediaTypes,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EnumMediaTypes(const std::vector<VideoFormat> &formats={});
|
||||||
|
EnumMediaTypes(const EnumMediaTypes &other);
|
||||||
|
EnumMediaTypes &operator =(const EnumMediaTypes &other);
|
||||||
|
virtual ~EnumMediaTypes();
|
||||||
|
|
||||||
|
std::vector<VideoFormat> &formats();
|
||||||
|
std::vector<VideoFormat> formats() const;
|
||||||
|
void setFormats(const std::vector<VideoFormat> &formats,
|
||||||
|
bool changed=true);
|
||||||
|
|
||||||
|
DECLARE_IUNKNOWN(IID_IEnumMediaTypes)
|
||||||
|
|
||||||
|
// IEnumMediaTypes
|
||||||
|
HRESULT STDMETHODCALLTYPE Next(ULONG cMediaTypes,
|
||||||
|
AM_MEDIA_TYPE **ppMediaTypes,
|
||||||
|
ULONG *pcFetched);
|
||||||
|
HRESULT STDMETHODCALLTYPE Skip(ULONG cMediaTypes);
|
||||||
|
HRESULT STDMETHODCALLTYPE Reset();
|
||||||
|
HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes **ppEnum);
|
||||||
|
|
||||||
|
private:
|
||||||
|
EnumMediaTypesPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ENUMMEDIATYPES_H
|
186
dshow/VirtualCamera/src/enumpins.cpp
Normal file
186
dshow/VirtualCamera/src/enumpins.cpp
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <dshow.h>
|
||||||
|
|
||||||
|
#include "enumpins.h"
|
||||||
|
#include "pin.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "EnumPins"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class EnumPinsPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<IPin *> m_pins;
|
||||||
|
size_t m_position {0};
|
||||||
|
bool m_changed {false};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::EnumPins::EnumPins():
|
||||||
|
CUnknown(this, IID_IEnumPins)
|
||||||
|
{
|
||||||
|
this->d = new EnumPinsPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::EnumPins::EnumPins(const EnumPins &other):
|
||||||
|
CUnknown(this, IID_IEnumPins)
|
||||||
|
{
|
||||||
|
this->d = new EnumPinsPrivate;
|
||||||
|
this->d->m_position = other.d->m_position;
|
||||||
|
this->d->m_changed = other.d->m_changed;
|
||||||
|
|
||||||
|
for (auto &pin: other.d->m_pins) {
|
||||||
|
this->d->m_pins.push_back(pin);
|
||||||
|
this->d->m_pins.back()->AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::EnumPins::~EnumPins()
|
||||||
|
{
|
||||||
|
for (auto &pin: this->d->m_pins)
|
||||||
|
pin->Release();
|
||||||
|
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AkVCam::EnumPins::count() const
|
||||||
|
{
|
||||||
|
return this->d->m_pins.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::EnumPins::addPin(IPin *pin, bool changed)
|
||||||
|
{
|
||||||
|
this->d->m_pins.push_back(pin);
|
||||||
|
this->d->m_pins.back()->AddRef();
|
||||||
|
this->d->m_changed = changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::EnumPins::removePin(IPin *pin, bool changed)
|
||||||
|
{
|
||||||
|
for (auto it = this->d->m_pins.begin(); it != this->d->m_pins.end(); it++)
|
||||||
|
if (*it == pin) {
|
||||||
|
this->d->m_pins.erase(it);
|
||||||
|
pin->Release();
|
||||||
|
this->d->m_changed = changed;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::EnumPins::setBaseFilter(BaseFilter *baseFilter)
|
||||||
|
{
|
||||||
|
for (auto &pin: this->d->m_pins) {
|
||||||
|
auto akPin = static_cast<Pin *>(pin);
|
||||||
|
akPin->setBaseFilter(baseFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::EnumPins::Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (pcFetched)
|
||||||
|
*pcFetched = 0;
|
||||||
|
|
||||||
|
if (!cPins)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (!ppPins)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
memset(ppPins, 0, cPins * sizeof(IPin *));
|
||||||
|
|
||||||
|
if (this->d->m_changed) {
|
||||||
|
this->d->m_changed = false;
|
||||||
|
|
||||||
|
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG fetched = 0;
|
||||||
|
|
||||||
|
for (;
|
||||||
|
fetched < cPins
|
||||||
|
&& this->d->m_position < this->d->m_pins.size();
|
||||||
|
fetched++, this->d->m_position++) {
|
||||||
|
*ppPins = this->d->m_pins[this->d->m_position];
|
||||||
|
(*ppPins)->AddRef();
|
||||||
|
|
||||||
|
if (*ppPins)
|
||||||
|
ppPins++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcFetched)
|
||||||
|
*pcFetched = fetched;
|
||||||
|
|
||||||
|
return fetched == cPins? S_OK: S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::EnumPins::Skip(ULONG cPins)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
AkLoggerLog("Skip ", cPins, " pins");
|
||||||
|
|
||||||
|
if (this->d->m_changed) {
|
||||||
|
this->d->m_changed = false;
|
||||||
|
|
||||||
|
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto position = this->d->m_position + cPins;
|
||||||
|
|
||||||
|
if (position > this->d->m_pins.size())
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
this->d->m_position = position;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::EnumPins::Reset()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_position = 0;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::EnumPins::Clone(IEnumPins **ppEnum)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!ppEnum)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
if (this->d->m_changed) {
|
||||||
|
this->d->m_changed = false;
|
||||||
|
|
||||||
|
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppEnum = new EnumPins(*this);
|
||||||
|
(*ppEnum)->AddRef();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
61
dshow/VirtualCamera/src/enumpins.h
Normal file
61
dshow/VirtualCamera/src/enumpins.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ENUMPINS_H
|
||||||
|
#define ENUMPINS_H
|
||||||
|
|
||||||
|
#include <strmif.h>
|
||||||
|
|
||||||
|
#include "cunknown.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class EnumPinsPrivate;
|
||||||
|
class BaseFilter;
|
||||||
|
|
||||||
|
class EnumPins:
|
||||||
|
public IEnumPins,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EnumPins();
|
||||||
|
EnumPins(const EnumPins &other);
|
||||||
|
virtual ~EnumPins();
|
||||||
|
|
||||||
|
size_t count() const;
|
||||||
|
void addPin(IPin *pin, bool changed=true);
|
||||||
|
void removePin(IPin *pin, bool changed=true);
|
||||||
|
void setBaseFilter(AkVCam::BaseFilter *baseFilter);
|
||||||
|
|
||||||
|
DECLARE_IUNKNOWN(IID_IEnumPins)
|
||||||
|
|
||||||
|
// IEnumPins
|
||||||
|
HRESULT STDMETHODCALLTYPE Next(ULONG cPins,
|
||||||
|
IPin **ppPins,
|
||||||
|
ULONG *pcFetched);
|
||||||
|
HRESULT STDMETHODCALLTYPE Skip(ULONG cPins);
|
||||||
|
HRESULT STDMETHODCALLTYPE Reset();
|
||||||
|
HRESULT STDMETHODCALLTYPE Clone(IEnumPins **ppEnum);
|
||||||
|
|
||||||
|
private:
|
||||||
|
EnumPinsPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ENUMPINS_H
|
42
dshow/VirtualCamera/src/filtermiscflags.cpp
Normal file
42
dshow/VirtualCamera/src/filtermiscflags.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "filtermiscflags.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "FilterMiscFlags"
|
||||||
|
|
||||||
|
AkVCam::FilterMiscFlags::FilterMiscFlags():
|
||||||
|
CUnknown(this, IID_IAMFilterMiscFlags)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::FilterMiscFlags::~FilterMiscFlags()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AkVCam::FilterMiscFlags::GetMiscFlags()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
return AM_FILTER_MISC_FLAGS_IS_SOURCE;
|
||||||
|
}
|
44
dshow/VirtualCamera/src/filtermiscflags.h
Normal file
44
dshow/VirtualCamera/src/filtermiscflags.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FILTERMISCFLAGS_H
|
||||||
|
#define FILTERMISCFLAGS_H
|
||||||
|
|
||||||
|
#include <strmif.h>
|
||||||
|
|
||||||
|
#include "cunknown.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class FilterMiscFlags:
|
||||||
|
public IAMFilterMiscFlags,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilterMiscFlags();
|
||||||
|
virtual ~FilterMiscFlags();
|
||||||
|
|
||||||
|
DECLARE_IUNKNOWN(IID_IAMFilterMiscFlags)
|
||||||
|
|
||||||
|
// IAMFilterMiscFlags
|
||||||
|
ULONG STDMETHODCALLTYPE GetMiscFlags();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FILTERMISCFLAGS_H
|
78
dshow/VirtualCamera/src/latency.cpp
Normal file
78
dshow/VirtualCamera/src/latency.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <strmif.h>
|
||||||
|
#include <amvideo.h>
|
||||||
|
#include <dvdmedia.h>
|
||||||
|
#include <uuids.h>
|
||||||
|
|
||||||
|
#include "latency.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "Latency"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class LatencyPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IAMStreamConfig *m_streamConfig;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Latency::Latency(IAMStreamConfig *streamConfig):
|
||||||
|
CUnknown(this, IID_IAMLatency)
|
||||||
|
{
|
||||||
|
this->d = new LatencyPrivate;
|
||||||
|
this->d->m_streamConfig = streamConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Latency::~Latency()
|
||||||
|
{
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::Latency::GetLatency(REFERENCE_TIME *prtLatency)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!prtLatency)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*prtLatency = 0;
|
||||||
|
|
||||||
|
if (this->d->m_streamConfig) {
|
||||||
|
AM_MEDIA_TYPE *mediaType = nullptr;
|
||||||
|
|
||||||
|
if (SUCCEEDED(this->d->m_streamConfig->GetFormat(&mediaType))) {
|
||||||
|
if (IsEqualGUID(mediaType->formattype, FORMAT_VideoInfo)) {
|
||||||
|
auto format = reinterpret_cast<VIDEOINFOHEADER *>(mediaType->pbFormat);
|
||||||
|
*prtLatency = format->AvgTimePerFrame;
|
||||||
|
} else if (IsEqualGUID(mediaType->formattype, FORMAT_VideoInfo2)) {
|
||||||
|
auto format = reinterpret_cast<VIDEOINFOHEADER2 *>(mediaType->pbFormat);
|
||||||
|
*prtLatency = format->AvgTimePerFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteMediaType(&mediaType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
61
dshow/VirtualCamera/src/latency.h
Normal file
61
dshow/VirtualCamera/src/latency.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LATENCY_H
|
||||||
|
#define LATENCY_H
|
||||||
|
|
||||||
|
#include <strmif.h>
|
||||||
|
|
||||||
|
#include "cunknown.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class LatencyPrivate;
|
||||||
|
|
||||||
|
class Latency:
|
||||||
|
public IAMLatency,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Latency(IAMStreamConfig *streamConfig=nullptr);
|
||||||
|
virtual ~Latency();
|
||||||
|
|
||||||
|
DECLARE_IUNKNOWN(IID_IAMLatency)
|
||||||
|
|
||||||
|
// IAMLatency
|
||||||
|
HRESULT WINAPI GetLatency(REFERENCE_TIME *prtLatency);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LatencyPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IAMLATENCY_NQ \
|
||||||
|
DECLARE_IUNKNOWN_NQ \
|
||||||
|
\
|
||||||
|
HRESULT WINAPI GetLatency(REFERENCE_TIME *prtLatency) \
|
||||||
|
{ \
|
||||||
|
return Latency::GetLatency(prtLatency); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IAMLATENCY(interfaceIid) \
|
||||||
|
DECLARE_IUNKNOWN_Q(interfaceIid) \
|
||||||
|
DECLARE_IAMLATENCY_NQ
|
||||||
|
|
||||||
|
#endif // LATENCY_H
|
191
dshow/VirtualCamera/src/mediafilter.cpp
Normal file
191
dshow/VirtualCamera/src/mediafilter.cpp
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <dshow.h>
|
||||||
|
|
||||||
|
#include "mediafilter.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "MediaFilter"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
typedef std::pair<void *, StateChangedCallbackT> StateChangedCallback;
|
||||||
|
|
||||||
|
class MediaFilterPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IBaseFilter *m_baseFilter;
|
||||||
|
IReferenceClock *m_clock;
|
||||||
|
std::vector<StateChangedCallback> m_stateChanged;
|
||||||
|
FILTER_STATE m_state;
|
||||||
|
REFERENCE_TIME m_start;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MediaFilter::MediaFilter(const IID &classCLSID,
|
||||||
|
IBaseFilter *baseFilter):
|
||||||
|
PersistPropertyBag(classCLSID)
|
||||||
|
{
|
||||||
|
this->setParent(this, &IID_IMediaFilter);
|
||||||
|
this->d = new MediaFilterPrivate;
|
||||||
|
this->d->m_baseFilter = baseFilter;
|
||||||
|
this->d->m_clock = nullptr;
|
||||||
|
this->d->m_state = State_Stopped;
|
||||||
|
this->d->m_start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MediaFilter::~MediaFilter()
|
||||||
|
{
|
||||||
|
if (this->d->m_clock)
|
||||||
|
this->d->m_clock->Release();
|
||||||
|
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MediaFilter::connectStateChanged(void *userData,
|
||||||
|
StateChangedCallbackT callback)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_stateChanged.push_back({userData, callback});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MediaFilter::disconnectStateChanged(void *userData,
|
||||||
|
StateChangedCallbackT callback)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
for (auto it = this->d->m_stateChanged.begin();
|
||||||
|
it != this->d->m_stateChanged.end();
|
||||||
|
it++) {
|
||||||
|
if (it->first == userData
|
||||||
|
&& it->second == callback) {
|
||||||
|
this->d->m_stateChanged.erase(it);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaFilter::Stop()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_state = State_Stopped;
|
||||||
|
HRESULT result = S_OK;
|
||||||
|
|
||||||
|
for (auto &callback: this->d->m_stateChanged) {
|
||||||
|
auto r = callback.second(callback.first, this->d->m_state);
|
||||||
|
|
||||||
|
if (r != S_OK)
|
||||||
|
result = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->stateChanged(this->d->m_state);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaFilter::Pause()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_state = State_Paused;
|
||||||
|
HRESULT result = S_OK;
|
||||||
|
|
||||||
|
for (auto &callback: this->d->m_stateChanged) {
|
||||||
|
auto r = callback.second(callback.first, this->d->m_state);
|
||||||
|
|
||||||
|
if (r != S_OK)
|
||||||
|
result = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->stateChanged(this->d->m_state);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaFilter::Run(REFERENCE_TIME tStart)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_start = tStart;
|
||||||
|
this->d->m_state = State_Running;
|
||||||
|
HRESULT result = S_OK;
|
||||||
|
|
||||||
|
for (auto &callback: this->d->m_stateChanged) {
|
||||||
|
auto r = callback.second(callback.first, this->d->m_state);
|
||||||
|
|
||||||
|
if (r != S_OK)
|
||||||
|
result = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->stateChanged(this->d->m_state);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaFilter::GetState(DWORD dwMilliSecsTimeout,
|
||||||
|
FILTER_STATE *State)
|
||||||
|
{
|
||||||
|
UNUSED(dwMilliSecsTimeout)
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!State)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*State = this->d->m_state;
|
||||||
|
AkLoggerLog("State: ", *State);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaFilter::SetSyncSource(IReferenceClock *pClock)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_clock)
|
||||||
|
this->d->m_clock->Release();
|
||||||
|
|
||||||
|
this->d->m_clock = pClock;
|
||||||
|
|
||||||
|
if (this->d->m_clock)
|
||||||
|
this->d->m_clock->AddRef();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaFilter::GetSyncSource(IReferenceClock **pClock)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!pClock)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*pClock = this->d->m_clock;
|
||||||
|
|
||||||
|
if (*pClock)
|
||||||
|
(*pClock)->AddRef();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::MediaFilter::stateChanged(FILTER_STATE state)
|
||||||
|
{
|
||||||
|
UNUSED(state)
|
||||||
|
}
|
115
dshow/VirtualCamera/src/mediafilter.h
Normal file
115
dshow/VirtualCamera/src/mediafilter.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEDIAFILTER_H
|
||||||
|
#define MEDIAFILTER_H
|
||||||
|
|
||||||
|
#include <strmif.h>
|
||||||
|
|
||||||
|
#include "persistpropertybag.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MediaFilterPrivate;
|
||||||
|
typedef HRESULT (*StateChangedCallbackT)(void *userData,
|
||||||
|
FILTER_STATE state);
|
||||||
|
|
||||||
|
class MediaFilter:
|
||||||
|
public IMediaFilter,
|
||||||
|
public PersistPropertyBag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MediaFilter(REFIID classCLSID, IBaseFilter *baseFilter);
|
||||||
|
virtual ~MediaFilter();
|
||||||
|
|
||||||
|
void connectStateChanged(void *userData,
|
||||||
|
StateChangedCallbackT callback);
|
||||||
|
void disconnectStateChanged(void *userData,
|
||||||
|
StateChangedCallbackT callback);
|
||||||
|
|
||||||
|
DECLARE_IPERSISTPROPERTYBAG(IID_IMediaFilter)
|
||||||
|
|
||||||
|
// IMediaFilter
|
||||||
|
HRESULT STDMETHODCALLTYPE Stop();
|
||||||
|
HRESULT STDMETHODCALLTYPE Pause();
|
||||||
|
HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
|
||||||
|
HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout,
|
||||||
|
FILTER_STATE *State);
|
||||||
|
HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
|
||||||
|
HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **pClock);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MediaFilterPrivate *d;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void stateChanged(FILTER_STATE state);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IMEDIAFILTER_NQ \
|
||||||
|
DECLARE_IPERSISTPROPERTYBAG_NQ \
|
||||||
|
\
|
||||||
|
void connectStateChanged(void *userData, \
|
||||||
|
StateChangedCallbackT callback) \
|
||||||
|
{ \
|
||||||
|
MediaFilter::connectStateChanged(userData, callback); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void disconnectStateChanged(void *userData, \
|
||||||
|
StateChangedCallbackT callback) \
|
||||||
|
{ \
|
||||||
|
MediaFilter::disconnectStateChanged(userData, callback); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE Stop() \
|
||||||
|
{ \
|
||||||
|
return MediaFilter::Stop(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE Pause() \
|
||||||
|
{ \
|
||||||
|
return MediaFilter::Pause(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart) \
|
||||||
|
{ \
|
||||||
|
return MediaFilter::Run(tStart); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, \
|
||||||
|
FILTER_STATE *State) \
|
||||||
|
{ \
|
||||||
|
return MediaFilter::GetState(dwMilliSecsTimeout, State); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock) \
|
||||||
|
{ \
|
||||||
|
return MediaFilter::SetSyncSource(pClock); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **pClock) \
|
||||||
|
{ \
|
||||||
|
return MediaFilter::GetSyncSource(pClock); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IMEDIAFILTER(interfaceIid) \
|
||||||
|
DECLARE_IPERSISTPROPERTYBAG_Q(interfaceIid) \
|
||||||
|
DECLARE_IMEDIAFILTER_NQ
|
||||||
|
|
||||||
|
#endif // MEDIAFILTER_H
|
275
dshow/VirtualCamera/src/mediasample.cpp
Normal file
275
dshow/VirtualCamera/src/mediasample.cpp
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dshow.h>
|
||||||
|
|
||||||
|
#include "mediasample.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "MediaSample"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MediaSamplePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IMemAllocator *m_memAllocator;
|
||||||
|
BYTE *m_buffer;
|
||||||
|
LONG m_bufferSize;
|
||||||
|
LONG m_dataLength;
|
||||||
|
LONG m_prefix;
|
||||||
|
AM_MEDIA_TYPE *m_mediaType;
|
||||||
|
REFERENCE_TIME m_sampleTimeStart;
|
||||||
|
REFERENCE_TIME m_sampleTimeEnd;
|
||||||
|
REFERENCE_TIME m_mediaTimeStart;
|
||||||
|
REFERENCE_TIME m_mediaTimeEnd;
|
||||||
|
BOOL m_syncPoint;
|
||||||
|
BOOL m_preroll;
|
||||||
|
BOOL m_discontinuity;
|
||||||
|
BOOL m_mediaTypeChanged;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MediaSample::MediaSample(IMemAllocator *memAllocator,
|
||||||
|
LONG bufferSize,
|
||||||
|
LONG align,
|
||||||
|
LONG prefix):
|
||||||
|
CUnknown(this, IID_IMediaSample)
|
||||||
|
{
|
||||||
|
this->d = new MediaSamplePrivate;
|
||||||
|
this->d->m_memAllocator = memAllocator;
|
||||||
|
this->d->m_bufferSize = bufferSize;
|
||||||
|
this->d->m_dataLength = bufferSize;
|
||||||
|
this->d->m_prefix = prefix;
|
||||||
|
auto realSize = size_t(bufferSize + prefix + align - 1) & ~size_t(align - 1);
|
||||||
|
this->d->m_buffer = new BYTE[realSize];
|
||||||
|
this->d->m_mediaType = nullptr;
|
||||||
|
this->d->m_sampleTimeStart = -1;
|
||||||
|
this->d->m_sampleTimeEnd = -1;
|
||||||
|
this->d->m_mediaTimeStart = -1;
|
||||||
|
this->d->m_mediaTimeEnd = -1;
|
||||||
|
this->d->m_syncPoint = S_FALSE;
|
||||||
|
this->d->m_preroll = S_FALSE;
|
||||||
|
this->d->m_discontinuity = S_FALSE;
|
||||||
|
this->d->m_mediaTypeChanged = S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MediaSample::~MediaSample()
|
||||||
|
{
|
||||||
|
delete [] this->d->m_buffer;
|
||||||
|
deleteMediaType(&this->d->m_mediaType);
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG AkVCam::MediaSample::Release()
|
||||||
|
{
|
||||||
|
auto result = CUnknown::Release();
|
||||||
|
this->d->m_memAllocator->ReleaseBuffer(this);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
delete this;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::GetPointer(BYTE **ppBuffer)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!ppBuffer)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*ppBuffer = this->d->m_buffer + this->d->m_prefix;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG AkVCam::MediaSample::GetSize()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
return this->d->m_bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::GetTime(REFERENCE_TIME *pTimeStart,
|
||||||
|
REFERENCE_TIME *pTimeEnd)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!pTimeStart || !pTimeEnd)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*pTimeStart = this->d->m_sampleTimeStart;
|
||||||
|
*pTimeEnd = this->d->m_sampleTimeEnd;
|
||||||
|
|
||||||
|
if (*pTimeStart < 0)
|
||||||
|
return VFW_E_SAMPLE_TIME_NOT_SET;
|
||||||
|
|
||||||
|
if (*pTimeEnd < 0) {
|
||||||
|
*pTimeEnd = *pTimeStart + 1;
|
||||||
|
|
||||||
|
return VFW_S_NO_STOP_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::SetTime(REFERENCE_TIME *pTimeStart,
|
||||||
|
REFERENCE_TIME *pTimeEnd)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
this->d->m_sampleTimeStart = pTimeStart? *pTimeStart: -1;
|
||||||
|
this->d->m_sampleTimeEnd = pTimeEnd? *pTimeEnd: -1;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::IsSyncPoint()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
return this->d->m_syncPoint? S_OK: S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::SetSyncPoint(BOOL bIsSyncPoint)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_syncPoint = bIsSyncPoint;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::IsPreroll()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
return this->d->m_preroll? S_OK: S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::SetPreroll(BOOL bIsPreroll)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_preroll = bIsPreroll;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG AkVCam::MediaSample::GetActualDataLength()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
return this->d->m_dataLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::SetActualDataLength(LONG lLen)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (lLen < 0 || lLen > this->d->m_bufferSize)
|
||||||
|
return VFW_E_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
this->d->m_dataLength = lLen;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::GetMediaType(AM_MEDIA_TYPE **ppMediaType)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!ppMediaType)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*ppMediaType = nullptr;
|
||||||
|
|
||||||
|
if (this->d->m_mediaTypeChanged == S_FALSE)
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
*ppMediaType = createMediaType(this->d->m_mediaType);
|
||||||
|
|
||||||
|
if (!*ppMediaType)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::SetMediaType(AM_MEDIA_TYPE *pMediaType)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!pMediaType)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
if (isEqualMediaType(pMediaType, this->d->m_mediaType, true)) {
|
||||||
|
this->d->m_mediaTypeChanged = S_FALSE;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteMediaType(&this->d->m_mediaType);
|
||||||
|
this->d->m_mediaType = createMediaType(pMediaType);
|
||||||
|
this->d->m_mediaTypeChanged = S_OK;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::IsDiscontinuity()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
return this->d->m_discontinuity? S_OK: S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::SetDiscontinuity(BOOL bDiscontinuity)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
this->d->m_discontinuity = bDiscontinuity;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::GetMediaTime(LONGLONG *pTimeStart,
|
||||||
|
LONGLONG *pTimeEnd)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!pTimeStart || !pTimeEnd)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*pTimeStart = this->d->m_mediaTimeStart;
|
||||||
|
*pTimeEnd = this->d->m_mediaTimeEnd;
|
||||||
|
|
||||||
|
if (*pTimeStart < 0 || *pTimeEnd < 0)
|
||||||
|
return VFW_E_MEDIA_TIME_NOT_SET;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample::SetMediaTime(LONGLONG *pTimeStart,
|
||||||
|
LONGLONG *pTimeEnd)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
this->d->m_mediaTimeStart = pTimeStart? *pTimeStart: -1;
|
||||||
|
this->d->m_mediaTimeEnd = pTimeEnd? *pTimeEnd: -1;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
164
dshow/VirtualCamera/src/mediasample.h
Normal file
164
dshow/VirtualCamera/src/mediasample.h
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEDIASAMPLE_H
|
||||||
|
#define MEDIASAMPLE_H
|
||||||
|
|
||||||
|
#include <strmif.h>
|
||||||
|
|
||||||
|
#include "cunknown.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MediaSamplePrivate;
|
||||||
|
|
||||||
|
class MediaSample:
|
||||||
|
public IMediaSample,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MediaSample(IMemAllocator *memAllocator,
|
||||||
|
LONG bufferSize, LONG align, LONG prefix);
|
||||||
|
virtual ~MediaSample();
|
||||||
|
|
||||||
|
DECLARE_IUNKNOWN_NR(IID_IMediaSample)
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
ULONG STDMETHODCALLTYPE Release();
|
||||||
|
|
||||||
|
// IMediaSample
|
||||||
|
HRESULT STDMETHODCALLTYPE GetPointer(BYTE **ppBuffer);
|
||||||
|
LONG STDMETHODCALLTYPE GetSize();
|
||||||
|
HRESULT STDMETHODCALLTYPE GetTime(REFERENCE_TIME *pTimeStart,
|
||||||
|
REFERENCE_TIME *pTimeEnd);
|
||||||
|
HRESULT STDMETHODCALLTYPE SetTime(REFERENCE_TIME *pTimeStart,
|
||||||
|
REFERENCE_TIME *pTimeEnd);
|
||||||
|
HRESULT STDMETHODCALLTYPE IsSyncPoint();
|
||||||
|
HRESULT STDMETHODCALLTYPE SetSyncPoint(BOOL bIsSyncPoint);
|
||||||
|
HRESULT STDMETHODCALLTYPE IsPreroll();
|
||||||
|
HRESULT STDMETHODCALLTYPE SetPreroll(BOOL bIsPreroll);
|
||||||
|
LONG STDMETHODCALLTYPE GetActualDataLength();
|
||||||
|
HRESULT STDMETHODCALLTYPE SetActualDataLength(LONG lLen);
|
||||||
|
HRESULT STDMETHODCALLTYPE GetMediaType(AM_MEDIA_TYPE **ppMediaType);
|
||||||
|
HRESULT STDMETHODCALLTYPE SetMediaType(AM_MEDIA_TYPE *pMediaType);
|
||||||
|
HRESULT STDMETHODCALLTYPE IsDiscontinuity();
|
||||||
|
HRESULT STDMETHODCALLTYPE SetDiscontinuity(BOOL bDiscontinuity);
|
||||||
|
HRESULT STDMETHODCALLTYPE GetMediaTime(LONGLONG *pTimeStart,
|
||||||
|
LONGLONG *pTimeEnd);
|
||||||
|
HRESULT STDMETHODCALLTYPE SetMediaTime(LONGLONG *pTimeStart,
|
||||||
|
LONGLONG *pTimeEnd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MediaSamplePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_IMEDIASAMPLE(interfaceIid) \
|
||||||
|
DECLARE_IUNKNOWN_NR(interfaceIid) \
|
||||||
|
\
|
||||||
|
ULONG STDMETHODCALLTYPE Release() \
|
||||||
|
{ \
|
||||||
|
return MediaSample::Release(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE GetPointer(BYTE **ppBuffer) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::GetPointer(ppBuffer); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
LONG STDMETHODCALLTYPE GetSize() \
|
||||||
|
{ \
|
||||||
|
return MediaSample::GetSize(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE GetTime(REFERENCE_TIME *pTimeStart, \
|
||||||
|
REFERENCE_TIME *pTimeEnd) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::GetTime(pTimeStart, pTimeEnd); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE SetTime(REFERENCE_TIME *pTimeStart, \
|
||||||
|
REFERENCE_TIME *pTimeEnd) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::SetTime(pTimeStart, pTimeEnd); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE IsSyncPoint() \
|
||||||
|
{ \
|
||||||
|
return MediaSample::IsSyncPoint(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE SetSyncPoint(BOOL bIsSyncPoint) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::SetSyncPoint(bIsSyncPoint); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE IsPreroll() \
|
||||||
|
{ \
|
||||||
|
return MediaSample::IsPreroll(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE SetPreroll(BOOL bIsPreroll) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::SetPreroll(bIsPreroll); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
LONG STDMETHODCALLTYPE GetActualDataLength() \
|
||||||
|
{ \
|
||||||
|
return MediaSample::GetActualDataLength(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE SetActualDataLength(LONG lLen) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::SetActualDataLength(lLen); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE GetMediaType(AM_MEDIA_TYPE **ppMediaType) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::GetMediaType(ppMediaType); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE SetMediaType(AM_MEDIA_TYPE *pMediaType) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::SetMediaType(pMediaType); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE IsDiscontinuity() \
|
||||||
|
{ \
|
||||||
|
return MediaSample::IsDiscontinuity(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE SetDiscontinuity(BOOL bDiscontinuity) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::SetDiscontinuity(bDiscontinuity); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE GetMediaTime(LONGLONG *pTimeStart, \
|
||||||
|
LONGLONG *pTimeEnd) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::GetMediaTime(pTimeStart, pTimeEnd); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
HRESULT STDMETHODCALLTYPE SetMediaTime(LONGLONG *pTimeStart, \
|
||||||
|
LONGLONG *pTimeEnd) \
|
||||||
|
{ \
|
||||||
|
return MediaSample::SetMediaTime(pTimeStart, pTimeEnd); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MEDIASAMPLE_H
|
123
dshow/VirtualCamera/src/mediasample2.cpp
Normal file
123
dshow/VirtualCamera/src/mediasample2.cpp
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mediasample2.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "MediaFilter2"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MediaSample2Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DWORD m_data;
|
||||||
|
DWORD m_typeSpecificFlags;
|
||||||
|
DWORD m_sampleFlags;
|
||||||
|
DWORD m_streamId;
|
||||||
|
AM_MEDIA_TYPE *m_mediaType;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MediaSample2::MediaSample2(IMemAllocator *memAllocator,
|
||||||
|
LONG bufferSize,
|
||||||
|
LONG align,
|
||||||
|
LONG prefix):
|
||||||
|
MediaSample(memAllocator, bufferSize, align, prefix)
|
||||||
|
{
|
||||||
|
this->d = new MediaSample2Private;
|
||||||
|
this->d->m_data = 0;
|
||||||
|
this->d->m_typeSpecificFlags = 0;
|
||||||
|
this->d->m_sampleFlags = 0;
|
||||||
|
this->d->m_streamId = 0;
|
||||||
|
this->d->m_mediaType = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MediaSample2::~MediaSample2()
|
||||||
|
{
|
||||||
|
deleteMediaType(&this->d->m_mediaType);
|
||||||
|
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample2::SetProperties(DWORD cbProperties,
|
||||||
|
const BYTE *pbProperties)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (cbProperties < sizeof(AM_SAMPLE2_PROPERTIES))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (!pbProperties)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
auto properties =
|
||||||
|
reinterpret_cast<const AM_SAMPLE2_PROPERTIES *>(pbProperties);
|
||||||
|
|
||||||
|
if (properties->pbBuffer || properties->cbBuffer)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
this->d->m_data = properties->cbData;
|
||||||
|
this->d->m_typeSpecificFlags = properties->dwTypeSpecificFlags;
|
||||||
|
this->d->m_sampleFlags = properties->dwSampleFlags;
|
||||||
|
this->SetDiscontinuity(this->d->m_sampleFlags & AM_SAMPLE_DATADISCONTINUITY);
|
||||||
|
this->SetSyncPoint(this->d->m_sampleFlags & AM_SAMPLE_SPLICEPOINT);
|
||||||
|
this->SetPreroll(this->d->m_sampleFlags & AM_SAMPLE_PREROLL);
|
||||||
|
this->SetActualDataLength(properties->lActual);
|
||||||
|
auto start = properties->tStart;
|
||||||
|
auto stop = properties->tStop;
|
||||||
|
this->SetTime(&start, &stop);
|
||||||
|
this->SetMediaTime(&start, &stop);
|
||||||
|
this->d->m_streamId = properties->dwStreamId;
|
||||||
|
deleteMediaType(&this->d->m_mediaType);
|
||||||
|
this->d->m_mediaType = createMediaType(properties->pMediaType);
|
||||||
|
this->SetMediaType(properties->pMediaType);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MediaSample2::GetProperties(DWORD cbProperties,
|
||||||
|
BYTE *pbProperties)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (cbProperties < sizeof(AM_SAMPLE2_PROPERTIES))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (!pbProperties)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
auto properties =
|
||||||
|
reinterpret_cast<AM_SAMPLE2_PROPERTIES *>(pbProperties);
|
||||||
|
|
||||||
|
properties->cbData = this->d->m_data;
|
||||||
|
properties->dwTypeSpecificFlags = this->d->m_typeSpecificFlags;
|
||||||
|
properties->dwSampleFlags = this->d->m_sampleFlags;
|
||||||
|
properties->lActual = this->GetActualDataLength();
|
||||||
|
this->GetTime(&properties->tStart, &properties->tStop);
|
||||||
|
properties->dwStreamId = this->d->m_streamId;
|
||||||
|
deleteMediaType(&this->d->m_mediaType);
|
||||||
|
this->GetMediaType(&this->d->m_mediaType);
|
||||||
|
properties->pMediaType = this->d->m_mediaType;
|
||||||
|
this->GetPointer(&properties->pbBuffer);
|
||||||
|
properties->cbBuffer = this->GetSize();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
51
dshow/VirtualCamera/src/mediasample2.h
Normal file
51
dshow/VirtualCamera/src/mediasample2.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEDIASAMPLE2_H
|
||||||
|
#define MEDIASAMPLE2_H
|
||||||
|
|
||||||
|
#include "mediasample.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MediaSample2Private;
|
||||||
|
|
||||||
|
class MediaSample2:
|
||||||
|
public IMediaSample2,
|
||||||
|
public MediaSample
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MediaSample2(IMemAllocator *memAllocator,
|
||||||
|
LONG bufferSize, LONG align, LONG prefix);
|
||||||
|
virtual ~MediaSample2();
|
||||||
|
|
||||||
|
DECLARE_IMEDIASAMPLE(IID_IMediaSample2)
|
||||||
|
|
||||||
|
// IMediaSample2
|
||||||
|
HRESULT STDMETHODCALLTYPE GetProperties(DWORD cbProperties,
|
||||||
|
BYTE *pbProperties);
|
||||||
|
HRESULT STDMETHODCALLTYPE SetProperties(DWORD cbProperties,
|
||||||
|
const BYTE *pbProperties);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MediaSample2Private *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MEDIASAMPLE2_H
|
229
dshow/VirtualCamera/src/memallocator.cpp
Normal file
229
dshow/VirtualCamera/src/memallocator.cpp
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
#include <dshow.h>
|
||||||
|
|
||||||
|
#include "memallocator.h"
|
||||||
|
#include "mediasample.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "MemAllocator"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MemAllocatorPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<MediaSample *> m_samples;
|
||||||
|
ALLOCATOR_PROPERTIES m_properties;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
std::condition_variable_any m_bufferReleased;
|
||||||
|
bool m_commited;
|
||||||
|
bool m_decommiting;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MemAllocator::MemAllocator():
|
||||||
|
CUnknown(this, IID_IMemAllocator)
|
||||||
|
{
|
||||||
|
this->d = new MemAllocatorPrivate;
|
||||||
|
memset(&this->d->m_properties, 0, sizeof(ALLOCATOR_PROPERTIES));
|
||||||
|
this->d->m_commited = false;
|
||||||
|
this->d->m_decommiting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::MemAllocator::~MemAllocator()
|
||||||
|
{
|
||||||
|
for (auto &sample: this->d->m_samples)
|
||||||
|
sample->Release();
|
||||||
|
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MemAllocator::SetProperties(ALLOCATOR_PROPERTIES *pRequest,
|
||||||
|
ALLOCATOR_PROPERTIES *pActual)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!pRequest || !pActual)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
if (this->d->m_commited)
|
||||||
|
return VFW_E_ALREADY_COMMITTED;
|
||||||
|
|
||||||
|
if (pRequest->cbAlign < 1)
|
||||||
|
return VFW_E_BADALIGN;
|
||||||
|
|
||||||
|
for (auto &sample:this->d->m_samples)
|
||||||
|
if (sample->ref() > 1)
|
||||||
|
return VFW_E_BUFFERS_OUTSTANDING;
|
||||||
|
|
||||||
|
memcpy(&this->d->m_properties, pRequest, sizeof(ALLOCATOR_PROPERTIES));
|
||||||
|
memcpy(pActual, &this->d->m_properties, sizeof(ALLOCATOR_PROPERTIES));
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MemAllocator::GetProperties(ALLOCATOR_PROPERTIES *pProps)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!pProps)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(this->d->m_mutex);
|
||||||
|
memcpy(pProps, &this->d->m_properties, sizeof(ALLOCATOR_PROPERTIES));
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MemAllocator::Commit()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (this->d->m_commited)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
if (this->d->m_properties.cBuffers < 1
|
||||||
|
|| this->d->m_properties.cbBuffer < 1) {
|
||||||
|
AkLoggerLog("Wrong memory allocator size");
|
||||||
|
|
||||||
|
return VFW_E_SIZENOTSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->d->m_samples.clear();
|
||||||
|
|
||||||
|
for (LONG i = 0; i < this->d->m_properties.cBuffers; i++) {
|
||||||
|
auto sample =
|
||||||
|
new MediaSample(this,
|
||||||
|
this->d->m_properties.cbBuffer,
|
||||||
|
this->d->m_properties.cbAlign,
|
||||||
|
this->d->m_properties.cbPrefix);
|
||||||
|
sample->AddRef();
|
||||||
|
this->d->m_samples.push_back(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->d->m_commited = true;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MemAllocator::Decommit()
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!this->d->m_commited)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
this->d->m_decommiting = true;
|
||||||
|
auto totalSamples = this->d->m_samples.size();
|
||||||
|
size_t freeSamples = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < totalSamples; i++)
|
||||||
|
if (this->d->m_samples[i]) {
|
||||||
|
if (this->d->m_samples[i]->ref() < 2) {
|
||||||
|
this->d->m_samples[i]->Release();
|
||||||
|
this->d->m_samples[i] = nullptr;
|
||||||
|
freeSamples++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
freeSamples++;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkLoggerLog("Free samples: ", freeSamples, "/", totalSamples);
|
||||||
|
|
||||||
|
if (freeSamples >= totalSamples) {
|
||||||
|
AkLoggerLog("Decommiting");
|
||||||
|
this->d->m_samples.clear();
|
||||||
|
this->d->m_commited = false;
|
||||||
|
this->d->m_decommiting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MemAllocator::GetBuffer(IMediaSample **ppBuffer,
|
||||||
|
REFERENCE_TIME *pStartTime,
|
||||||
|
REFERENCE_TIME *pEndTime,
|
||||||
|
DWORD dwFlags)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!ppBuffer)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*ppBuffer = nullptr;
|
||||||
|
|
||||||
|
if (pStartTime)
|
||||||
|
*pStartTime = 0;
|
||||||
|
|
||||||
|
if (pEndTime)
|
||||||
|
*pEndTime = 0;
|
||||||
|
|
||||||
|
if (!this->d->m_commited || this->d->m_decommiting) {
|
||||||
|
AkLoggerLog("Allocator not commited.");
|
||||||
|
|
||||||
|
return VFW_E_NOT_COMMITTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = S_FALSE;
|
||||||
|
|
||||||
|
do {
|
||||||
|
for (auto &sample: this->d->m_samples) {
|
||||||
|
if (sample->ref() < 2) {
|
||||||
|
*ppBuffer = sample;
|
||||||
|
(*ppBuffer)->AddRef();
|
||||||
|
(*ppBuffer)->GetTime(pStartTime, pEndTime);
|
||||||
|
result = S_OK;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->d->m_mutex.lock();
|
||||||
|
|
||||||
|
if (result == S_FALSE) {
|
||||||
|
if (dwFlags & AM_GBF_NOWAIT)
|
||||||
|
result = VFW_E_TIMEOUT;
|
||||||
|
else
|
||||||
|
this->d->m_bufferReleased.wait(this->d->m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->d->m_mutex.unlock();
|
||||||
|
} while (result == S_FALSE);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::MemAllocator::ReleaseBuffer(IMediaSample *pBuffer)
|
||||||
|
{
|
||||||
|
UNUSED(pBuffer)
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
this->d->m_mutex.lock();
|
||||||
|
this->d->m_bufferReleased.notify_one();
|
||||||
|
this->d->m_mutex.unlock();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
58
dshow/VirtualCamera/src/memallocator.h
Normal file
58
dshow/VirtualCamera/src/memallocator.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEMALLOCATOR_H
|
||||||
|
#define MEMALLOCATOR_H
|
||||||
|
|
||||||
|
#include <strmif.h>
|
||||||
|
|
||||||
|
#include "cunknown.h"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class MemAllocatorPrivate;
|
||||||
|
|
||||||
|
class MemAllocator:
|
||||||
|
public IMemAllocator,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemAllocator();
|
||||||
|
virtual ~MemAllocator();
|
||||||
|
|
||||||
|
DECLARE_IUNKNOWN(IID_IMemAllocator)
|
||||||
|
|
||||||
|
// IMemAllocator
|
||||||
|
HRESULT STDMETHODCALLTYPE SetProperties(ALLOCATOR_PROPERTIES *pRequest,
|
||||||
|
ALLOCATOR_PROPERTIES *pActual);
|
||||||
|
HRESULT STDMETHODCALLTYPE GetProperties(ALLOCATOR_PROPERTIES *pProps);
|
||||||
|
HRESULT STDMETHODCALLTYPE Commit();
|
||||||
|
HRESULT STDMETHODCALLTYPE Decommit();
|
||||||
|
HRESULT STDMETHODCALLTYPE GetBuffer(IMediaSample **ppBuffer,
|
||||||
|
REFERENCE_TIME *pStartTime,
|
||||||
|
REFERENCE_TIME *pEndTime,
|
||||||
|
DWORD dwFlags);
|
||||||
|
HRESULT STDMETHODCALLTYPE ReleaseBuffer(IMediaSample *pBuffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemAllocatorPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MEMALLOCATOR_H
|
57
dshow/VirtualCamera/src/persist.cpp
Normal file
57
dshow/VirtualCamera/src/persist.cpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/* akvirtualcamera, virtual camera for Mac and Windows.
|
||||||
|
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
||||||
|
*
|
||||||
|
* akvirtualcamera is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* akvirtualcamera is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Web-Site: http://webcamoid.github.io/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "persist.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#define AK_CUR_INTERFACE "Persist"
|
||||||
|
|
||||||
|
namespace AkVCam
|
||||||
|
{
|
||||||
|
class PersistPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CLSID m_clsid;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Persist::Persist(const IID &classCLSID):
|
||||||
|
CUnknown(this, IID_IPersist)
|
||||||
|
{
|
||||||
|
this->d = new PersistPrivate;
|
||||||
|
this->d->m_clsid = classCLSID;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::Persist::~Persist()
|
||||||
|
{
|
||||||
|
delete this->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT AkVCam::Persist::GetClassID(CLSID *pClassID)
|
||||||
|
{
|
||||||
|
AkLogMethod();
|
||||||
|
|
||||||
|
if (!pClassID)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*pClassID = this->d->m_clsid;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue