forked from tshino/softcam
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial version of src, test and examples
- Loading branch information
Showing
66 changed files
with
21,785 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.vs/ | ||
*.vcxproj.user | ||
x64/ | ||
/packages/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Softcam | ||
|
||
This is a library to make a virtual webcam on Windows. | ||
|
||
|
||
## How it works | ||
|
||
This software is a DLL which implements a DirectShow filter of Video Input Device category. | ||
Once it is installed to the system, any camera application which is using DirectShow API will recognize the filter as a camera-like device attached to the system. | ||
And thankfully many of camera applications running on Windows use DirectShow API to access camera devices. | ||
|
||
This DLL provides Softcam Sender API too. Using this API, your application can create a virtual webcam instance and send arbitrary images as a video stream to the camera application. | ||
|
||
Your code will look like this: | ||
|
||
``` | ||
auto camera = scCreateCamera(320, 240, 60); | ||
for (;;) | ||
{ | ||
uint8_t image[320 * 240 * 3]; | ||
DrawSomething(image); | ||
scSendFrame(camera, image); | ||
} | ||
``` | ||
. | ||
|
||
## How to build and run | ||
|
||
Following software is required. | ||
|
||
- Visual Studio 2019 (installed with Desktop development with C++) | ||
|
||
The procedure is as follows. | ||
|
||
1. Open `softcam.sln`, choose configuration `Release` and build the solution. If it successfully builds, you will get `softcam.dll` in `x64/Release` directory. | ||
2. Open `examples/softcam_installer/softcam_installer.sln`, choose configuration `Release` and build the solution. Then you will get `softcam_installer.exe` in `examples/softcam_installer/x64/Release` directory. | ||
3. Then you register `softcam.dll` to your system by double clicking the `RegisterSoftcam.bat` in the `examples/softcam_installer` directory. Note since this process requires Windows administrator permissions, `softcam_installer.exe` will request the permissions to the user through UAC. You can also unregister the DLL using `UnregisterSoftcam.bat` with the same manner. | ||
4. Open `examples/sender/sender.sln`, choose configuration `Release` and build the solution. | ||
5. Run `sender.exe`. If it worked, you will see the message '`Ok. Softcam is now active.`' in the console. This means that you got a new virtual webcam running on the system. | ||
6. To see the video stream which is being sent from the `sender.exe`, you may try my web application Compare ([https://tshino.github.io/compare/compare.html](https://tshino.github.io/compare/compare.html)) on your browser. This is an image comparison tool which is written in JavaScript, and it can take a capture from a webcam. Open the above link and click the camera icon which appeares on the side bar. If it shows a different camera image, you need to change the settings of your browser to select '`DirectShow Softcam`' as main camera device. In case of Chrome or Edge, the camera icon on the address bar is a shortcut to the camera settings. | ||
|
||
|
||
## License | ||
|
||
[MIT](LICENSE). | ||
|
||
Note that the Base Classes libary (in [src/baseclasses](src/baseclasses) directory) is a part of [Microsft Windows Samples](https://github.com/microsoft/Windows-classic-samples) (Base Classes is in [Samples/Win7Samples/multimedia/directshow/baseclasses](https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/multimedia/directshow/baseclasses) directory) which is also provided under MIT license. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
#include <cstdio> | ||
#include <vector> | ||
#include <algorithm> | ||
#include <cmath> | ||
#include <softcam/softcam.h> | ||
|
||
|
||
const int WIDTH = 320; | ||
const int HEIGHT = 240; | ||
|
||
|
||
/// A Rendering Example of Bouncing Balls | ||
class BouncingBalls | ||
{ | ||
public: | ||
static constexpr int NUM_BALLS = 2; | ||
static constexpr float RADIUS = 30.0f; | ||
static constexpr float GRAVITY = 400.0f; | ||
static constexpr float STIFFNESS = 600.0f; | ||
|
||
struct Ball | ||
{ | ||
float x = RADIUS, y = RADIUS * 2.0f; | ||
float vx = 100.0f, vy = 0.0f; | ||
float ax = 0.0f, ay = 0.0f; | ||
float rx = RADIUS, ry = RADIUS; | ||
|
||
void move(float delta) | ||
{ | ||
vx += delta * ax; | ||
vy += delta * ay; | ||
x += delta * vx; | ||
y += delta * vy; | ||
float cx = std::min(std::max(x, RADIUS), (float)WIDTH - RADIUS); | ||
float cy = std::min(y, (float)HEIGHT - RADIUS); | ||
ax = (cx - x) * STIFFNESS; | ||
ay = (cy - y) * STIFFNESS + GRAVITY; | ||
rx = std::max(RADIUS - std::abs(cx - x), RADIUS * 0.1f); | ||
ry = std::max(RADIUS - std::abs(cy - y), RADIUS * 0.1f); | ||
} | ||
void collide(Ball& other) | ||
{ | ||
float dx = x - other.x; | ||
float dy = y - other.y; | ||
float d = std::sqrt(dx * dx + dy * dy); | ||
if (d <= RADIUS * 2.0f) | ||
{ | ||
float p = RADIUS * 2.0f - d; | ||
float nx = dx / std::max(RADIUS, d); | ||
float ny = dy / std::max(RADIUS, d); | ||
ax += p * STIFFNESS * nx; | ||
ay += p * STIFFNESS * ny; | ||
other.ax -= p * STIFFNESS * nx; | ||
other.ay -= p * STIFFNESS * ny; | ||
} | ||
} | ||
bool hit(int sx, int sy) const | ||
{ | ||
float dx = (float(sx) + 0.5f - x) / rx; | ||
float dy = (float(sy) + 0.5f - y) / ry; | ||
return 1.0f >= dx * dx + dy * dy; | ||
} | ||
}; | ||
|
||
Ball balls[NUM_BALLS]; | ||
|
||
BouncingBalls() | ||
{ | ||
for (int i = 0; i < NUM_BALLS; i++) | ||
{ | ||
balls[i].x = (float)(WIDTH * (i + 1) / (2 * NUM_BALLS)); | ||
balls[i].y = (float)(HEIGHT * i / (2 * NUM_BALLS)) + RADIUS * 2.0f; | ||
balls[i].vx = RADIUS * 2.0f * (float)(i + 1); | ||
} | ||
} | ||
void move(float delta) | ||
{ | ||
for (int i = 0; i < NUM_BALLS; i++) | ||
{ | ||
balls[i].move(delta); | ||
} | ||
for (int i = 0; i < NUM_BALLS; i++) | ||
{ | ||
for (int j = i + 1; j < NUM_BALLS; j++) | ||
{ | ||
balls[i].collide(balls[j]); | ||
} | ||
} | ||
} | ||
void draw(unsigned char *image) | ||
{ | ||
for (int y = 0; y < HEIGHT; y++) | ||
{ | ||
for (int x = 0; x < WIDTH; x++) | ||
{ | ||
if (std::any_of( | ||
balls, balls + NUM_BALLS, | ||
[x,y](Ball& ball) { return ball.hit(x, y); })) | ||
{ | ||
int red = x * 256 / WIDTH; | ||
int green = 255; | ||
int blue = y * 256 / HEIGHT; | ||
|
||
image[0] = (unsigned char)blue; | ||
image[1] = (unsigned char)green; | ||
image[2] = (unsigned char)red; | ||
} | ||
else | ||
{ | ||
image[0] = 0; | ||
image[1] = 0; | ||
image[2] = 0; | ||
} | ||
image += 3; | ||
} | ||
} | ||
} | ||
}; | ||
|
||
|
||
int main() | ||
{ | ||
// First, create a virtual camera instance with scCreateCamera(). | ||
// A virtual camera is a source of a video image stream. | ||
// The dimension width and height can be arbitrary positive numbers | ||
// which are multiples of four. | ||
// The third argument framerate is used to make sending frames at regular intervals. | ||
// This framerate argument can be omitted, and the default framerate is 60. | ||
// If you want to send every frame immediately without the frame rate regulator, | ||
// specify 0 to the framerate argument, then it will be a variable frame rate. | ||
scCamera cam = scCreateCamera(WIDTH, HEIGHT, 60); | ||
if (!cam) | ||
{ | ||
std::printf("failed to create camera\n"); | ||
return 1; | ||
} | ||
std::printf("Ok. Softcam is now active.\n"); | ||
|
||
// Here, we wait for an application to connect to this camera. | ||
// You can comment out this line to start sending frames immediately | ||
// no matter there is a receiver or not. | ||
scWaitForConnection(cam); | ||
|
||
// Our canvas is a simple array of RGB pixels. | ||
// Note that the color component order is BGR, not RGB. | ||
// This is due to the convention of DirectShow. | ||
std::vector<unsigned char> image(WIDTH * HEIGHT * 3); | ||
|
||
// This is an example class for drawing something to the canvas. | ||
BouncingBalls balls; | ||
|
||
for (int i = 0; i < 100000; i++) | ||
{ | ||
// Draw bouncing balls. | ||
balls.move(1.0f / 60.0f); | ||
balls.draw(image.data()); | ||
|
||
// Send the image as a newly captured frame of the camera. | ||
scSendFrame(cam, image.data()); | ||
} | ||
|
||
// Delete the camera instance. | ||
// The receiver application will no longer receive new frames from this camera. | ||
scDeleteCamera(cam); | ||
std::printf("Softcam has been shut down.\n"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 16 | ||
VisualStudioVersion = 16.0.30523.141 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sender", "sender.vcxproj", "{07DDA575-7366-4ED4-A5C0-CA1D9C2FBD94}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|x64 = Debug|x64 | ||
Release|x64 = Release|x64 | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{07DDA575-7366-4ED4-A5C0-CA1D9C2FBD94}.Debug|x64.ActiveCfg = Debug|x64 | ||
{07DDA575-7366-4ED4-A5C0-CA1D9C2FBD94}.Debug|x64.Build.0 = Debug|x64 | ||
{07DDA575-7366-4ED4-A5C0-CA1D9C2FBD94}.Release|x64.ActiveCfg = Release|x64 | ||
{07DDA575-7366-4ED4-A5C0-CA1D9C2FBD94}.Release|x64.Build.0 = Release|x64 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {5DEC6E41-1C14-49D2-BA60-6E49F81B95D2} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<ItemGroup Label="ProjectConfigurations"> | ||
<ProjectConfiguration Include="Debug|x64"> | ||
<Configuration>Debug</Configuration> | ||
<Platform>x64</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Release|x64"> | ||
<Configuration>Release</Configuration> | ||
<Platform>x64</Platform> | ||
</ProjectConfiguration> | ||
</ItemGroup> | ||
<PropertyGroup Label="Globals"> | ||
<VCProjectVersion>16.0</VCProjectVersion> | ||
<Keyword>Win32Proj</Keyword> | ||
<ProjectGuid>{07dda575-7366-4ed4-a5c0-ca1d9c2fbd94}</ProjectGuid> | ||
<RootNamespace>sender</RootNamespace> | ||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | ||
</PropertyGroup> | ||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | ||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | ||
<ConfigurationType>Application</ConfigurationType> | ||
<UseDebugLibraries>true</UseDebugLibraries> | ||
<PlatformToolset>v142</PlatformToolset> | ||
<CharacterSet>Unicode</CharacterSet> | ||
</PropertyGroup> | ||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | ||
<ConfigurationType>Application</ConfigurationType> | ||
<UseDebugLibraries>false</UseDebugLibraries> | ||
<PlatformToolset>v142</PlatformToolset> | ||
<WholeProgramOptimization>true</WholeProgramOptimization> | ||
<CharacterSet>Unicode</CharacterSet> | ||
</PropertyGroup> | ||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | ||
<ImportGroup Label="ExtensionSettings"> | ||
</ImportGroup> | ||
<ImportGroup Label="Shared"> | ||
</ImportGroup> | ||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | ||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | ||
</ImportGroup> | ||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | ||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | ||
</ImportGroup> | ||
<PropertyGroup Label="UserMacros" /> | ||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | ||
<LinkIncremental>true</LinkIncremental> | ||
</PropertyGroup> | ||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | ||
<LinkIncremental>false</LinkIncremental> | ||
</PropertyGroup> | ||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | ||
<ClCompile> | ||
<WarningLevel>Level3</WarningLevel> | ||
<SDLCheck>true</SDLCheck> | ||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||
<ConformanceMode>true</ConformanceMode> | ||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src</AdditionalIncludeDirectories> | ||
</ClCompile> | ||
<Link> | ||
<SubSystem>Console</SubSystem> | ||
<GenerateDebugInformation>true</GenerateDebugInformation> | ||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\x64\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> | ||
<AdditionalDependencies>softcam.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> | ||
</Link> | ||
<PostBuildEvent> | ||
<Command>copy $(ProjectDir)..\..\x64\$(Configuration)\softcam.dll $(OutDir)</Command> | ||
</PostBuildEvent> | ||
</ItemDefinitionGroup> | ||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | ||
<ClCompile> | ||
<WarningLevel>Level3</WarningLevel> | ||
<FunctionLevelLinking>true</FunctionLevelLinking> | ||
<IntrinsicFunctions>true</IntrinsicFunctions> | ||
<SDLCheck>true</SDLCheck> | ||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||
<ConformanceMode>true</ConformanceMode> | ||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src</AdditionalIncludeDirectories> | ||
</ClCompile> | ||
<Link> | ||
<SubSystem>Console</SubSystem> | ||
<EnableCOMDATFolding>true</EnableCOMDATFolding> | ||
<OptimizeReferences>true</OptimizeReferences> | ||
<GenerateDebugInformation>true</GenerateDebugInformation> | ||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\x64\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> | ||
<AdditionalDependencies>softcam.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> | ||
</Link> | ||
<PostBuildEvent> | ||
<Command>copy $(ProjectDir)..\..\x64\$(Configuration)\softcam.dll $(OutDir)</Command> | ||
</PostBuildEvent> | ||
</ItemDefinitionGroup> | ||
<ItemGroup> | ||
<ClCompile Include="sender.cpp" /> | ||
</ItemGroup> | ||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||
<ImportGroup Label="ExtensionTargets"> | ||
</ImportGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<ItemGroup> | ||
<Filter Include="Source Files"> | ||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | ||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | ||
</Filter> | ||
<Filter Include="Header Files"> | ||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> | ||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> | ||
</Filter> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<ClCompile Include="sender.cpp"> | ||
<Filter>Source Files</Filter> | ||
</ClCompile> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
@echo off | ||
|
||
set INSTALLER=x64\Release\softcam_installer.exe | ||
set TARGET=..\..\x64\Release\softcam.dll | ||
|
||
echo ############################################################## | ||
echo Softcam Installer (softcam_installer.exe) will install Softcam | ||
echo (softcam.dll) to your system. | ||
echo ############################################################## | ||
echo. | ||
|
||
%INSTALLER% register %TARGET% | ||
|
||
if %ERRORLEVEL% == 0 ( | ||
echo. | ||
echo Successfully done. | ||
echo. | ||
) else ( | ||
echo. | ||
echo The process has been canceled or failed. | ||
echo. | ||
) | ||
pause |
Oops, something went wrong.