├── .gitattributes
├── .github
└── workflows
│ ├── msbuild.yml
│ └── release.yml
├── .gitignore
├── LICENSE
├── Nuget
├── ScreenRecorderLib.nuspec
├── ScreenRecorderLib.targets
├── nuget.exe
└── pack.cmd
├── README.md
├── ScreenRecorderLib.sln
├── ScreenRecorderLib
├── .editorconfig
├── AssemblyInfo.cpp
├── AudioDevice.h
├── Callback.h
├── Coordinates.h
├── ManagedIStream.h
├── ManagedStreamWrapper.h
├── Options.h
├── Recorder.cpp
├── Recorder.h
├── RecordingOverlays.h
├── RecordingSources.h
├── ScreenRecorderLib.vcxproj
├── ScreenRecorderLib.vcxproj.filters
├── VideoCaptureFormat.h
├── VideoEncoders.h
├── Win32WindowEnumeration.h
├── app.ico
├── app.rc
└── resource.h
├── ScreenRecorderLibNative
├── .editorconfig
├── AudioManager.cpp
├── AudioManager.h
├── CMFSinkWriterCallback.h
├── CameraCapture.cpp
├── CameraCapture.h
├── CaptureBase.cpp
├── CaptureBase.h
├── CommonTypes.h
├── CoreAudio.util.cpp
├── CoreAudio.util.h
├── DX.util.cpp
├── DX.util.h
├── DesktopDuplicationCapture.cpp
├── DesktopDuplicationCapture.h
├── DynamicWait.cpp
├── DynamicWait.h
├── Exception.h
├── GifReader.cpp
├── GifReader.h
├── HighresTimer.cpp
├── HighresTimer.h
├── ImageReader.cpp
├── ImageReader.h
├── Log.cpp
├── LogMediaType.cpp
├── LogMediaType.h
├── MF.util.cpp
├── MF.util.h
├── MouseManager.cpp
├── MouseManager.h
├── OutputManager.cpp
├── OutputManager.h
├── PixelShader.hlsl
├── RecordingManager.cpp
├── RecordingManager.h
├── Resizer.cpp
├── Resizer.h
├── ScreenCaptureBase.h
├── ScreenCaptureManager.cpp
├── ScreenCaptureManager.h
├── ScreenRecorderLibNative.vcxproj
├── ScreenRecorderLibNative.vcxproj.filters
├── SourceReaderBase.cpp
├── SourceReaderBase.h
├── TextureManager.cpp
├── TextureManager.h
├── Util.cpp
├── VertexShader.hlsl
├── VideoReader.cpp
├── VideoReader.h
├── WASAPICapture.cpp
├── WASAPICapture.h
├── WASAPINotify.cpp
├── WASAPINotify.h
├── WWMFResampler.cpp
├── WWMFResampler.h
├── WindowsGraphicsCapture.cpp
├── WindowsGraphicsCapture.h
├── WindowsGraphicsCapture.util.cpp
├── WindowsGraphicsCapture.util.h
├── cleanup.h
├── fifo_map.h
├── log.h
├── native.h
├── screengrab.cpp
├── screengrab.h
└── util.h
├── TestApp
├── App.config
├── App.xaml
├── App.xaml.cs
├── BytesToKilobytesConverter.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── OverlayModel.cs
├── OverlayTemplateSelector.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── RecordingSourceTemplateSelector.cs
├── Sources
│ ├── CheckableRecordableCamera.cs
│ ├── CheckableRecordableDisplay.cs
│ ├── CheckableRecordableImage.cs
│ ├── CheckableRecordableVideo.cs
│ ├── CheckableRecordableWindow.cs
│ └── ICheckableRecordingSource.cs
├── TestApp.csproj
└── packages.config
├── TestAppWinforms
├── App.config
├── Form1.Designer.cs
├── Form1.cs
├── Form1.resx
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
└── TestAppWinforms.csproj
├── TestConsoleApp
├── App.config
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── TestConsoleApp.csproj
├── TestConsoleAppCpp
├── Demo.cpp
├── TestConsoleAppCpp.vcxproj
└── TestConsoleAppCpp.vcxproj.filters
├── TestConsoleAppDotNetCore
├── Program.cs
├── Properties
│ └── launchSettings.json
└── TestConsoleAppDotNetCore.csproj
├── Testmedia
├── alphatest.png
├── cat.mp4
├── cat2.mp4
├── earth.gif
├── giftest.gif
└── renault.png
└── Tests
├── Properties
└── AssemblyInfo.cs
├── ScreenRecorderTests.cs
├── Tests.csproj
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/msbuild.yml:
--------------------------------------------------------------------------------
1 | name: MSBuild
2 |
3 | on: [push, pull_request]
4 |
5 | env:
6 | SOLUTION_NAME: ScreenRecorderLib
7 | PROJECT_NAME: TestApp
8 |
9 | jobs:
10 | build:
11 | name: Build ${{ matrix.platform }}
12 | runs-on: windows-2022
13 | strategy:
14 | matrix:
15 | platform: [x64, x86]
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | - uses: microsoft/setup-msbuild@v1.1
20 | - run: nuget restore ${{ env.SOLUTION_NAME }}.sln
21 | - run: msbuild /m /p:Configuration=Release /p:Platform="${{ matrix.platform }}" ${{ env.SOLUTION_NAME }}.sln
22 | - name: Upload artifact
23 | uses: actions/upload-artifact@v3
24 | with:
25 | name: ${{ env.SOLUTION_NAME }}-${{ matrix.platform }}-${{ github.sha }}
26 | path: ${{ env.PROJECT_NAME }}\bin\${{ matrix.platform }}\Release
27 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | tags:
7 | description: 'tag'
8 | push:
9 | tags:
10 | - "v*"
11 |
12 | env:
13 | SOLUTION_NAME: ScreenRecorderLib
14 | PROJECT_NAME: ScreenRecorderLib
15 |
16 | jobs:
17 | build:
18 | name: Build ${{ matrix.platform }}
19 | runs-on: windows-2022
20 | strategy:
21 | matrix:
22 | platform: [x64, x86]
23 |
24 | steps:
25 | - uses: actions/checkout@v4
26 | - uses: microsoft/setup-msbuild@v1.1
27 | - run: nuget restore ${{ env.SOLUTION_NAME }}.sln
28 | - run: msbuild /m /p:Configuration=Release /p:Platform="${{ matrix.platform }}" ${{ env.SOLUTION_NAME }}.sln
29 |
30 | - uses: actions/upload-artifact@v4
31 | with:
32 | name: ScreenRecorderLib.${{matrix.platform}}
33 | path: ${{ env.PROJECT_NAME }}\bin\${{ matrix.platform }}\Release\ScreenRecorderLib.dll
34 |
35 | release:
36 | name: Upload Release
37 | runs-on: windows-2022
38 | needs : build
39 | steps:
40 | - uses: actions/download-artifact@v4
41 | with:
42 | name: ScreenRecorderLib.x86
43 | path: ScreenRecorderLib.x86.zip
44 | - uses: actions/download-artifact@v4
45 | with:
46 | name: ScreenRecorderLib.x64
47 | path: ScreenRecorderLib.x64.zip
48 | - name: Display structure of downloaded files
49 | run: ls -R
50 | - uses: marvinpinto/action-automatic-releases@latest
51 | with:
52 | repo_token: "${{ secrets.GITHUB_TOKEN }}"
53 | prerelease: false
54 | files: |
55 | ScreenRecorderLib.x86.zip
56 | ScreenRecorderLib.x64.zip
57 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Windows Store app package directory
170 | AppPackages/
171 | BundleArtifacts/
172 |
173 | # Visual Studio cache files
174 | # files ending in .cache can be ignored
175 | *.[Cc]ache
176 | # but keep track of directories ending in .cache
177 | !*.[Cc]ache/
178 |
179 | # Others
180 | ClientBin/
181 | [Ss]tyle[Cc]op.*
182 | ~$*
183 | *~
184 | *.dbmdl
185 | *.dbproj.schemaview
186 | *.pfx
187 | *.publishsettings
188 | node_modules/
189 | orleans.codegen.cs
190 |
191 | # RIA/Silverlight projects
192 | Generated_Code/
193 |
194 | # Backup & report files from converting an old project file
195 | # to a newer Visual Studio version. Backup files are not needed,
196 | # because we have git ;-)
197 | _UpgradeReport_Files/
198 | Backup*/
199 | UpgradeLog*.XML
200 | UpgradeLog*.htm
201 |
202 | # SQL Server files
203 | *.mdf
204 | *.ldf
205 |
206 | # Business Intelligence projects
207 | *.rdl.data
208 | *.bim.layout
209 | *.bim_*.settings
210 |
211 | # Microsoft Fakes
212 | FakesAssemblies/
213 |
214 | # GhostDoc plugin setting file
215 | *.GhostDoc.xml
216 |
217 | # Node.js Tools for Visual Studio
218 | .ntvs_analysis.dat
219 |
220 | # Visual Studio 6 build log
221 | *.plg
222 |
223 | # Visual Studio 6 workspace options file
224 | *.opt
225 |
226 | # Visual Studio LightSwitch build output
227 | **/*.HTMLClient/GeneratedArtifacts
228 | **/*.DesktopClient/GeneratedArtifacts
229 | **/*.DesktopClient/ModelManifest.xml
230 | **/*.Server/GeneratedArtifacts
231 | **/*.Server/ModelManifest.xml
232 | _Pvt_Extensions
233 |
234 | # LightSwitch generated files
235 | GeneratedArtifacts/
236 | ModelManifest.xml
237 |
238 | # Paket dependency manager
239 | .paket/paket.exe
240 |
241 | # FAKE - F# Make
242 | .fake/
243 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Sverre Skodje
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Nuget/ScreenRecorderLib.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ScreenRecorderLib
5 | 6.5.1
6 | Sverre Kristoffer Skodje
7 | MIT
8 | https://github.com/sskodje/ScreenRecorderLib
9 | false
10 | A .NET library for screen recording in Windows, using Microsoft Media Foundation for realtime encoding to video or image files.
11 |
12 | README.md
13 |
14 | • Fixed bug where monitors with negative coordinates (to the left of main monitor) did not record properly.
15 |
16 | Copyright © Sverre Kristoffer Skodje 2025
17 | en-GB
18 | Screen Recording Windows .NET
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Nuget/ScreenRecorderLib.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | $(MSBuildThisFileDirectory)x86\ScreenRecorderLib.dll
13 |
14 |
15 | $(MSBuildThisFileDirectory)x86\ScreenRecorderLib.dll
16 |
17 |
18 | $(MSBuildThisFileDirectory)x64\ScreenRecorderLib.dll
19 |
20 |
21 | $(MSBuildThisFileDirectory)ARM64\ScreenRecorderLib.dll
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Nuget/nuget.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sskodje/ScreenRecorderLib/5611b7266a5a87477313e892dd997bf720c1c5e4/Nuget/nuget.exe
--------------------------------------------------------------------------------
/Nuget/pack.cmd:
--------------------------------------------------------------------------------
1 | nuget.exe pack ScreenRecorderLib.nuspec
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ScreenRecorderLib
2 | A .NET library for screen recording in Windows, using native Microsoft Media Foundation for realtime encoding to h264 video or PNG images. This library requires Windows 8 or higher to function, as well as Visual C++ Redistributable [x64](https://aka.ms/vs/17/release/vc_redist.x64.exe) or [x86](https://aka.ms/vs/17/release/vc_redist.x86.exe) installed, depending on platform compiled for. This library also requires Media Foundation to work, which have to be installed from Server Manager if run on Windows Server, or from the respective "Media Feature Pack" if run on a Windows N or KN version.
3 |
4 | Available on [NuGet](https://www.nuget.org/packages/ScreenRecorderLib/).
5 |
6 | **Basic usage:**
7 |
8 | This will start a video recording to a file, using the default settings:
9 |
10 | ```csharp
11 | using ScreenRecorderLib;
12 |
13 | Recorder _rec;
14 | void CreateRecording()
15 | {
16 | string videoPath = Path.Combine(Path.GetTempPath(), "test.mp4");
17 | _rec = Recorder.CreateRecorder();
18 | _rec.OnRecordingComplete += Rec_OnRecordingComplete;
19 | _rec.OnRecordingFailed += Rec_OnRecordingFailed;
20 | _rec.OnStatusChanged += Rec_OnStatusChanged;
21 | //Record to a file
22 | string videoPath = Path.Combine(Path.GetTempPath(), "test.mp4");
23 | _rec.Record(videoPath);
24 | }
25 | void EndRecording()
26 | {
27 | _rec.Stop();
28 | }
29 | private void Rec_OnRecordingComplete(object sender, RecordingCompleteEventArgs e)
30 | {
31 | //Get the file path if recorded to a file
32 | string path = e.FilePath;
33 | }
34 | private void Rec_OnRecordingFailed(object sender, RecordingFailedEventArgs e)
35 | {
36 | string error = e.Error;
37 | }
38 | private void Rec_OnStatusChanged(object sender, RecordingStatusEventArgs e)
39 | {
40 | RecorderStatus status = e.Status;
41 | }
42 | ```
43 |
44 | For more info and examples, see the [quickstart guide](https://github.com/sskodje/ScreenRecorderLib/wiki/Quickstart-guide-v5.x.x-and-newer), or check out the sample projects.
45 |
46 | ## Donation
47 | If this project is useful to you, please consider supporting the development with a donation :)
48 |
49 | [](https://www.paypal.com/donate/?business=RBE7933GCPLZU&no_recurring=0&item_name=Thanks+for+supporting+my+open+source+work%21¤cy_code=USD)
50 |
--------------------------------------------------------------------------------
/ScreenRecorderLib/.editorconfig:
--------------------------------------------------------------------------------
1 | # Visual Studio generated .editorconfig file with C++ settings.
2 | root = true
3 |
4 | [*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
5 |
6 | # Visual C++ Code Style settings
7 |
8 | cpp_generate_documentation_comments = xml
9 |
10 | # Visual C++ Formatting settings
11 |
12 | cpp_indent_braces = false
13 | cpp_indent_multi_line_relative_to = innermost_parenthesis
14 | cpp_indent_within_parentheses = indent
15 | cpp_indent_preserve_within_parentheses = true
16 | cpp_indent_case_contents = true
17 | cpp_indent_case_labels = true
18 | cpp_indent_case_contents_when_block = false
19 | cpp_indent_lambda_braces_when_parameter = true
20 | cpp_indent_goto_labels = one_left
21 | cpp_indent_preprocessor = leftmost_column
22 | cpp_indent_access_specifiers = false
23 | cpp_indent_namespace_contents = true
24 | cpp_indent_preserve_comments = false
25 | cpp_new_line_before_open_brace_namespace = ignore
26 | cpp_new_line_before_open_brace_type = ignore
27 | cpp_new_line_before_open_brace_function = ignore
28 | cpp_new_line_before_open_brace_block = ignore
29 | cpp_new_line_before_open_brace_lambda = ignore
30 | cpp_new_line_scope_braces_on_separate_lines = false
31 | cpp_new_line_close_brace_same_line_empty_type = false
32 | cpp_new_line_close_brace_same_line_empty_function = false
33 | cpp_new_line_before_catch = true
34 | cpp_new_line_before_else = true
35 | cpp_new_line_before_while_in_do_while = false
36 | cpp_space_before_function_open_parenthesis = remove
37 | cpp_space_within_parameter_list_parentheses = false
38 | cpp_space_between_empty_parameter_list_parentheses = false
39 | cpp_space_after_keywords_in_control_flow_statements = true
40 | cpp_space_within_control_flow_statement_parentheses = false
41 | cpp_space_before_lambda_open_parenthesis = false
42 | cpp_space_within_cast_parentheses = false
43 | cpp_space_after_cast_close_parenthesis = false
44 | cpp_space_within_expression_parentheses = false
45 | cpp_space_before_block_open_brace = true
46 | cpp_space_between_empty_braces = false
47 | cpp_space_before_initializer_list_open_brace = false
48 | cpp_space_within_initializer_list_braces = true
49 | cpp_space_preserve_in_initializer_list = true
50 | cpp_space_before_open_square_bracket = false
51 | cpp_space_within_square_brackets = false
52 | cpp_space_before_empty_square_brackets = false
53 | cpp_space_between_empty_square_brackets = false
54 | cpp_space_group_square_brackets = true
55 | cpp_space_within_lambda_brackets = false
56 | cpp_space_between_empty_lambda_brackets = false
57 | cpp_space_before_comma = false
58 | cpp_space_after_comma = true
59 | cpp_space_remove_around_member_operators = true
60 | cpp_space_before_inheritance_colon = true
61 | cpp_space_before_constructor_colon = true
62 | cpp_space_remove_before_semicolon = true
63 | cpp_space_after_semicolon = true
64 | cpp_space_remove_around_unary_operator = true
65 | cpp_space_around_binary_operator = insert
66 | cpp_space_around_assignment_operator = insert
67 | cpp_space_pointer_reference_alignment = left
68 | cpp_space_around_ternary_operator = insert
69 | cpp_wrap_preserve_blocks = one_liners
70 |
--------------------------------------------------------------------------------
/ScreenRecorderLib/AssemblyInfo.cpp:
--------------------------------------------------------------------------------
1 | using namespace System;
2 | using namespace System::Reflection;
3 | using namespace System::Runtime::CompilerServices;
4 | using namespace System::Runtime::InteropServices;
5 | using namespace System::Security::Permissions;
6 |
7 | //
8 | // General Information about an assembly is controlled through the following
9 | // set of attributes. Change these attribute values to modify the information
10 | // associated with an assembly.
11 | //
12 | [assembly:AssemblyTitleAttribute(L"ScreenRecorderLib")];
13 | [assembly:AssemblyDescriptionAttribute(L"")];
14 | [assembly:AssemblyConfigurationAttribute(L"")];
15 | [assembly:AssemblyCompanyAttribute(L"Sverre Kristoffer Skodje")];
16 | [assembly:AssemblyProductAttribute(L"ScreenRecorder")];
17 | [assembly:AssemblyCopyrightAttribute(L"Copyright (c) 2017")];
18 | [assembly:AssemblyTrademarkAttribute(L"")];
19 | [assembly:AssemblyCultureAttribute(L"")];
20 |
21 | //
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 | // You can specify all the value or you can default the Revision and Build Numbers
30 | // by using the '*' as shown below:
31 |
32 | [assembly:AssemblyVersionAttribute("1.0.*")];
33 |
34 | [assembly:ComVisible(false)];
35 |
36 | [assembly:CLSCompliantAttribute(true)];
--------------------------------------------------------------------------------
/ScreenRecorderLib/AudioDevice.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | using namespace System;
3 | namespace ScreenRecorderLib {
4 | public ref class AudioDevice {
5 | public:
6 | AudioDevice() {};
7 | AudioDevice(String^ deviceName, String^ friendlyName) {
8 | DeviceName = deviceName;
9 | FriendlyName = friendlyName;
10 | }
11 | virtual property String^ DeviceName;
12 | virtual property String^ FriendlyName;
13 | };
14 | }
--------------------------------------------------------------------------------
/ScreenRecorderLib/Callback.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | using namespace System;
4 | using namespace System::Collections::Generic;
5 |
6 | namespace ScreenRecorderLib {
7 | public enum class RecorderStatus {
8 | Idle,
9 | Recording,
10 | Paused,
11 | Finishing
12 | };
13 | public ref class FrameData {
14 | public:
15 | property String^ Path;
16 | property int Delay;
17 | FrameData() {}
18 | FrameData(String^ path, int delay) {
19 | Path = path;
20 | Delay = delay;
21 | }
22 | };
23 |
24 | public ref class FrameBitmapData {
25 | public:
26 | property int Stride;
27 | property int Width;
28 | property int Height;
29 | property IntPtr Data;
30 | property int Length;
31 | FrameBitmapData() {}
32 | FrameBitmapData(int stride, byte* data, int length, int width, int height) {
33 | Stride = stride;
34 | Data = IntPtr(data);
35 | Length = length;
36 | Width = width;
37 | Height = height;
38 | }
39 | };
40 |
41 | public ref class RecordingStatusEventArgs :System::EventArgs {
42 | public:
43 | property RecorderStatus Status;
44 | RecordingStatusEventArgs(RecorderStatus status) {
45 | Status = status;
46 | }
47 | };
48 | public ref class RecordingCompleteEventArgs :System::EventArgs {
49 | public:
50 | property String^ FilePath;
51 | property List^ FrameInfos;
52 | RecordingCompleteEventArgs(String^ path, List^ frameInfos) {
53 | FilePath = path;
54 | FrameInfos = frameInfos;
55 | }
56 | };
57 | public ref class RecordingFailedEventArgs :System::EventArgs {
58 | public:
59 | property String^ Error;
60 | property String^ FilePath;
61 | RecordingFailedEventArgs(String^ error, String^ path) {
62 | Error = error;
63 | FilePath = path;
64 | }
65 | };
66 |
67 | public ref class SnapshotSavedEventArgs :System::EventArgs {
68 | public:
69 | property String^ SnapshotPath;
70 | SnapshotSavedEventArgs(String^ path) {
71 | SnapshotPath = path;
72 | }
73 | };
74 | public ref class FrameRecordedEventArgs :System::EventArgs {
75 | public:
76 | property int FrameNumber;
77 | property INT64 Timestamp;
78 | FrameBitmapData^ BitmapData;
79 | FrameRecordedEventArgs() {}
80 | FrameRecordedEventArgs(int frameNumber, INT64 timestamp) {
81 | FrameNumber = frameNumber;
82 | Timestamp = timestamp;
83 | }
84 | FrameRecordedEventArgs(int frameNumber, INT64 timestamp, FrameBitmapData^ bitmapData) {
85 | FrameNumber = frameNumber;
86 | Timestamp = timestamp;
87 | BitmapData = bitmapData;
88 | }
89 | };
90 |
91 | public ref class FrameDataRecordedEventArgs :System::EventArgs {
92 | public:
93 | property FrameBitmapData^ BitmapData;
94 | FrameDataRecordedEventArgs() {}
95 | FrameDataRecordedEventArgs(FrameBitmapData^ bitmapData)
96 | {
97 | this->BitmapData = bitmapData;
98 | }
99 | FrameDataRecordedEventArgs(int stride, byte* data, int length, int width, int height) {
100 | this->BitmapData = gcnew FrameBitmapData(stride, data, length, width, height);
101 | }
102 | };
103 | }
--------------------------------------------------------------------------------
/ScreenRecorderLib/ManagedIStream.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include "ManagedStreamWrapper.h"
6 |
7 | namespace ScreenRecorderLib {
8 | private class ManagedIStream : public IStream
9 | {
10 | public:
11 | ManagedIStream(System::IO::Stream^ stream)
12 | : refCount(1)
13 | {
14 | this->baseStream = gcnew ManagedStreamWrapper(stream);
15 |
16 | /* https://stackoverflow.com/a/39712297/2129964
17 | * We need to call all functions on the managed stream through delegates,
18 | * or we get errors if the code is running in a non-default AppDomain.*/
19 | m_pSeekFnc = baseStream->GetSeekFunctionPointer();
20 | m_pWriteFnc = baseStream->GetWriteFunctionPointer();
21 | m_pReadFnc = baseStream->GetReadFunctionPointer();
22 | m_pCanWriteFnc = baseStream->GetCanWriteFunctionPointer();
23 | m_pCanReadFnc = baseStream->GetCanReadFunctionPointer();
24 | m_pCanSeekFnc = baseStream->GetCanSeekFunctionPointer();
25 | m_pSetLengthFnc = baseStream->GetSetLengthFunctionPointer();
26 | m_pGetLengthFnc = baseStream->GetLengthFunctionPointer();
27 | }
28 |
29 | public:
30 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
31 | {
32 | if (riid == __uuidof (IStream)) { *ppvObject = this; AddRef(); return S_OK; }
33 | else { *ppvObject = NULL; return E_NOINTERFACE; }
34 | }
35 | virtual ULONG STDMETHODCALLTYPE AddRef(void) { return InterlockedIncrement(&refCount); }
36 | virtual ULONG STDMETHODCALLTYPE Release(void)
37 | {
38 | ULONG temp = InterlockedDecrement(&refCount);
39 | if (temp == 0) delete this;
40 | return temp;
41 | }
42 |
43 | public:
44 | // IStream
45 | virtual HRESULT STDMETHODCALLTYPE Read(void* pv, _In_ ULONG cb, _Out_opt_ ULONG* pcbRead)override
46 | {
47 | if (!m_pCanReadFnc())
48 | return E_ACCESSDENIED;
49 |
50 | int bytesRead = m_pReadFnc(System::IntPtr(pv), 0, cb);
51 | if (pcbRead != nullptr) *pcbRead = bytesRead;
52 | return S_OK;
53 | }
54 | virtual HRESULT STDMETHODCALLTYPE Write(const void* pv, ULONG cb, ULONG* pcbWritten) override
55 | {
56 | if (!m_pCanWriteFnc())
57 | return E_ACCESSDENIED;
58 |
59 | m_pWriteFnc(System::IntPtr((void*)pv), 0, cb);
60 | if (pcbWritten != nullptr) *pcbWritten = cb;
61 | return S_OK;
62 | }
63 | virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, _Out_opt_ ULARGE_INTEGER* plibNewPosition) override
64 | {
65 | if (!m_pCanSeekFnc())
66 | return E_ACCESSDENIED;
67 | System::IO::SeekOrigin seekOrigin;
68 |
69 | switch (dwOrigin)
70 | {
71 | case 0: seekOrigin = System::IO::SeekOrigin::Begin; break;
72 | case 1: seekOrigin = System::IO::SeekOrigin::Current; break;
73 | case 2: seekOrigin = System::IO::SeekOrigin::End; break;
74 | default: throw gcnew System::ArgumentOutOfRangeException("dwOrigin");
75 | }
76 |
77 | long long position = m_pSeekFnc(dlibMove.QuadPart, seekOrigin);
78 | if (plibNewPosition != nullptr)
79 | plibNewPosition->QuadPart = position;
80 | return S_OK;
81 | }
82 | virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize)
83 | {
84 | m_pSetLengthFnc(libNewSize.QuadPart);
85 | return S_OK;
86 | }
87 | virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) override
88 | {
89 | return E_NOTIMPL;
90 | }
91 | virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) override { return E_NOTIMPL; }
92 | virtual HRESULT STDMETHODCALLTYPE Revert(void) override { return E_NOTIMPL; }
93 | virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) override { return E_NOTIMPL; }
94 | virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) override { return E_NOTIMPL; }
95 |
96 | virtual HRESULT STDMETHODCALLTYPE Stat(::STATSTG* pstatstg, DWORD grfStatFlag) override
97 | {
98 | memset(pstatstg, 0, sizeof(::STATSTG));
99 | pstatstg->type = STGTY_STREAM;
100 | pstatstg->cbSize.QuadPart = m_pGetLengthFnc();
101 |
102 | if (m_pCanReadFnc() && m_pCanWriteFnc())
103 | pstatstg->grfMode |= STGM_READWRITE;
104 | else if (m_pCanReadFnc())
105 | pstatstg->grfMode |= STGM_READ;
106 | else if (m_pCanWriteFnc())
107 | pstatstg->grfMode |= STGM_WRITE;
108 | else throw gcnew System::IO::IOException();
109 | return S_OK;
110 | }
111 | virtual HRESULT STDMETHODCALLTYPE Clone(IStream** ppstm) override { return E_NOTIMPL; }
112 |
113 | private:
114 | ULONG refCount;
115 | gcroot baseStream;
116 |
117 | SeekFnc* m_pSeekFnc;
118 | ReadFnc* m_pReadFnc;
119 | WriteFnc* m_pWriteFnc;
120 | CanReadFnc* m_pCanReadFnc;
121 | CanWriteFnc* m_pCanWriteFnc;
122 | CanSeekFnc* m_pCanSeekFnc;
123 | SetLengthFnc* m_pSetLengthFnc;
124 | GetLengthFnc* m_pGetLengthFnc;
125 | };
126 | }
127 |
--------------------------------------------------------------------------------
/ScreenRecorderLib/ManagedStreamWrapper.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | typedef bool(__stdcall CanReadFnc)();
3 | typedef bool(__stdcall CanWriteFnc)();
4 | typedef bool(__stdcall CanSeekFnc)();
5 | typedef long long(__stdcall SeekFnc)(long long offset, System::IO::SeekOrigin origin);
6 | typedef int(__stdcall ReadFnc)(System::IntPtr dest, int offset, int count);
7 | typedef void(__stdcall WriteFnc)(System::IntPtr, int offset, int count);
8 | typedef void(__stdcall SetLengthFnc)(long long value);
9 | typedef long long(__stdcall GetLengthFnc)();
10 |
11 | namespace ScreenRecorderLib {
12 | public ref class ManagedStreamWrapper
13 | {
14 | public:
15 | ManagedStreamWrapper(System::IO::Stream^ stream);
16 |
17 |
18 | SeekFnc* GetSeekFunctionPointer()
19 | {
20 | return (SeekFnc*)(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_SeekDelegate).ToPointer());
21 | }
22 |
23 | WriteFnc* GetWriteFunctionPointer()
24 | {
25 | return (WriteFnc*)(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_WriteDelegate).ToPointer());
26 | }
27 |
28 | ReadFnc* GetReadFunctionPointer()
29 | {
30 | return (ReadFnc*)(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_ReadDelegate).ToPointer());
31 | }
32 |
33 | SetLengthFnc* GetSetLengthFunctionPointer()
34 | {
35 | return (SetLengthFnc*)(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_SetLengthDelegate).ToPointer());
36 | }
37 |
38 | GetLengthFnc* GetLengthFunctionPointer()
39 | {
40 | return (GetLengthFnc*)(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_GetLengthDelegate).ToPointer());
41 | }
42 | CanReadFnc* GetCanReadFunctionPointer()
43 | {
44 | return (CanReadFnc*)(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_CanReadDelegate).ToPointer());
45 | }
46 | CanWriteFnc* GetCanWriteFunctionPointer()
47 | {
48 | return (CanWriteFnc*)(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_CanWriteDelegate).ToPointer());
49 | }
50 | CanSeekFnc* GetCanSeekFunctionPointer()
51 | {
52 | return (CanSeekFnc*)(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_CanSeekDelegate).ToPointer());
53 | }
54 |
55 |
56 | private:
57 | System::IO::Stream^ m_Stream;
58 | delegate long long LongDelegate();
59 | delegate long long SeekDelegate(long long offset, System::IO::SeekOrigin origin);
60 | delegate int ReadDelegate(System::IntPtr dest, int offset, int count);
61 | delegate void WriteDelegate(System::IntPtr source, int offset, int count);
62 | delegate void SetLengthDelegate(long long value);
63 | delegate int IntDelegate();
64 | delegate bool BoolDelegate();
65 | delegate cli::array^ BufferDelegate();
66 |
67 | LongDelegate^ m_GetLengthDelegate;
68 | BoolDelegate^ m_CanWriteDelegate;
69 | BoolDelegate^ m_CanReadDelegate;
70 | BoolDelegate^ m_CanSeekDelegate;
71 | SeekDelegate^ m_SeekDelegate;
72 | ReadDelegate^ m_ReadDelegate;
73 | WriteDelegate^ m_WriteDelegate;
74 | SetLengthDelegate^ m_SetLengthDelegate;
75 |
76 | long long GetLength() {
77 | return m_Stream->Length;
78 | }
79 | bool GetCanWrite() {
80 | return m_Stream->CanWrite;
81 | }
82 | bool GetCanRead() {
83 | return m_Stream->CanRead;
84 | }
85 | bool GetCanSeek() {
86 | return m_Stream->CanSeek;
87 | }
88 | long long Seek(long long offset, System::IO::SeekOrigin origin) {
89 | return m_Stream->Seek(offset, origin);
90 | };
91 | int Read(System::IntPtr dest, int offset, int count) {
92 | auto tempBytes = gcnew cli::array(count);
93 | int bytesRead = m_Stream->Read(tempBytes, offset, count);
94 | System::Runtime::InteropServices::Marshal::Copy(tempBytes, 0, dest, count);
95 | return bytesRead;
96 | };
97 | void Write(System::IntPtr source, int offset, int count) {
98 | auto tempBytes = gcnew cli::array(count);
99 | System::Runtime::InteropServices::Marshal::Copy(source, tempBytes, 0, count);
100 | return m_Stream->Write(tempBytes, offset, count);
101 | };
102 | void SetLength(long long value) {
103 | return m_Stream->SetLength(value);
104 | };
105 | };
106 |
107 |
108 | ManagedStreamWrapper::ManagedStreamWrapper(System::IO::Stream^ stream)
109 | {
110 | m_Stream = stream;
111 | m_GetLengthDelegate = gcnew LongDelegate(this, &ManagedStreamWrapper::GetLength);
112 | m_CanWriteDelegate = gcnew BoolDelegate(this, &ManagedStreamWrapper::GetCanWrite);
113 | m_CanReadDelegate = gcnew BoolDelegate(this, &ManagedStreamWrapper::GetCanRead);
114 | m_CanSeekDelegate = gcnew BoolDelegate(this, &ManagedStreamWrapper::GetCanSeek);
115 | m_SeekDelegate = gcnew SeekDelegate(this, &ManagedStreamWrapper::Seek);
116 | m_ReadDelegate = gcnew ReadDelegate(this, &ManagedStreamWrapper::Read);
117 | m_WriteDelegate = gcnew WriteDelegate(this, &ManagedStreamWrapper::Write);
118 | m_SetLengthDelegate = gcnew SetLengthDelegate(this, &ManagedStreamWrapper::SetLength);
119 | }
120 | }
--------------------------------------------------------------------------------
/ScreenRecorderLib/ScreenRecorderLib.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files
35 |
36 |
37 | Header Files
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files
47 |
48 |
49 | Header Files
50 |
51 |
52 | Header Files
53 |
54 |
55 | Header Files
56 |
57 |
58 |
59 |
60 | Source Files
61 |
62 |
63 | Source Files
64 |
65 |
66 |
67 |
68 | Resource Files
69 |
70 |
71 |
72 |
73 | Resource Files
74 |
75 |
76 |
--------------------------------------------------------------------------------
/ScreenRecorderLib/VideoCaptureFormat.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | namespace ScreenRecorderLib {
3 | public enum class VideoNominalRange {
4 | MFNominalRange_Unknown = 0,
5 | MFNominalRange_Normal = 1,
6 | MFNominalRange_Wide = 2,
7 | MFNominalRange_0_255 = 1,
8 | MFNominalRange_16_235 = 2,
9 | MFNominalRange_48_208 = 3,
10 | MFNominalRange_64_127 = 4
11 | };
12 |
13 | public enum class VideoInterlaceMode {
14 | MFVideoInterlace_Unknown = 0,
15 | MFVideoInterlace_Progressive = 2,
16 | MFVideoInterlace_FieldInterleavedUpperFirst = 3,
17 | MFVideoInterlace_FieldInterleavedLowerFirst = 4,
18 | MFVideoInterlace_FieldSingleUpper = 5,
19 | MFVideoInterlace_FieldSingleLower = 6,
20 | MFVideoInterlace_MixedInterlaceOrProgressive = 7
21 | };
22 |
23 | public enum VideoTransferMatrix {
24 | MFVideoTransferMatrix_Unknown = 0,
25 | MFVideoTransferMatrix_BT709 = 1,
26 | MFVideoTransferMatrix_BT601 = 2,
27 | MFVideoTransferMatrix_SMPTE240M = 3,
28 | MFVideoTransferMatrix_BT2020_10 = 4,
29 | MFVideoTransferMatrix_BT2020_12 = 5
30 | };
31 |
32 | public ref class VideoCaptureFormat {
33 | public:
34 | VideoCaptureFormat() {
35 |
36 | };
37 | property int Index;
38 | property Guid VideoFormat;
39 | property String^ VideoFormatName;
40 | property double Framerate;
41 | property ScreenSize^ FrameSize;
42 | property int AverageBitrate;
43 | property VideoTransferMatrix YUVMatrix;
44 | property VideoInterlaceMode InterlaceMode;
45 | property VideoNominalRange NominalRange;
46 |
47 | virtual String^ ToString() override {
48 | return String::Format("{0} - [{1},{2}] {3}fps", VideoFormatName, FrameSize->Width, FrameSize->Height, Framerate);
49 | }
50 | private:
51 |
52 | };
53 | }
--------------------------------------------------------------------------------
/ScreenRecorderLib/VideoEncoders.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | using namespace System;
3 | using namespace System::Runtime::InteropServices;
4 |
5 | namespace ScreenRecorderLib {
6 | public enum class H264BitrateControlMode {
7 | ///Constant bitrate. Faster encoding than VBR, but produces larger files with consistent size. This setting might not work on software encoding.
8 | CBR = 0,
9 | ///Default is unconstrained variable bitrate. Overall bitrate will average towards the Bitrate property, but can fluctuate greatly over and under it.
10 | UnconstrainedVBR = 2,
11 | ///Quality-based VBR encoding. The encoder selects the bit rate to match a specified quality level. Set Quality level in VideoEncoderOptions from 1-100. Default is 70.
12 | Quality = 3
13 | };
14 | public enum class H265BitrateControlMode {
15 | ///Constant bitrate. Faster encoding than VBR, but produces larger files with consistent size. This setting might not work on software encoding.
16 | CBR = 0,
17 | ///Quality-based VBR encoding. The encoder selects the bit rate to match a specified quality level. Set Quality level in VideoEncoderOptions from 1-100. Default is 70.
18 | Quality = 3
19 | };
20 |
21 | public enum class H264Profile {
22 | Baseline = 66,
23 | Main = 77,
24 | High = 100
25 | };
26 | public enum class H265Profile {
27 | Main = 1,
28 | };
29 |
30 | public enum class VideoEncoderFormat {
31 | ///H.264/AVC encoder.
32 | H264,
33 | ///H.265/HEVC encoder.
34 | H265
35 | };
36 |
37 | public interface class IVideoEncoder {
38 | public:
39 | property VideoEncoderFormat EncodingFormat {
40 | VideoEncoderFormat get();
41 | }
42 | UInt32 GetEncoderProfile();
43 | UInt32 GetBitrateMode();
44 | };
45 |
46 | ///
47 | /// Encode video with H264 encoder.
48 | ///
49 | public ref class H264VideoEncoder : public IVideoEncoder, INotifyPropertyChanged {
50 | private:
51 | H264Profile _encoderProfile;
52 | H264BitrateControlMode _bitrateMode;
53 | public:
54 | H264VideoEncoder() {
55 | EncoderProfile = H264Profile::High;
56 | BitrateMode = H264BitrateControlMode::Quality;
57 | }
58 | virtual event PropertyChangedEventHandler^ PropertyChanged;
59 | void OnPropertyChanged(String^ info)
60 | {
61 | PropertyChanged(this, gcnew PropertyChangedEventArgs(info));
62 | }
63 | virtual property VideoEncoderFormat EncodingFormat {
64 | VideoEncoderFormat get() {
65 | return VideoEncoderFormat::H264;
66 | }
67 | }
68 | ///
69 | ///The capabilities the h264 video encoder.
70 | ///Lesser profiles may increase playback compatibility and use less resources with older decoders and hardware at the cost of quality.
71 | ///
72 | property H264Profile EncoderProfile {
73 | H264Profile get() {
74 | return _encoderProfile;
75 | }
76 | void set(H264Profile value) {
77 | _encoderProfile = value;
78 | OnPropertyChanged("EncoderProfile");
79 | }
80 | }
81 | ///
82 | ///The bitrate control mode of the video encoder. Default is Quality.
83 | ///
84 | property H264BitrateControlMode BitrateMode {
85 | H264BitrateControlMode get() {
86 | return _bitrateMode;
87 | }
88 | void set(H264BitrateControlMode value) {
89 | _bitrateMode = value;
90 | OnPropertyChanged("BitrateMode");
91 | }
92 | }
93 |
94 | virtual UInt32 GetEncoderProfile() { return (UInt32)EncoderProfile; }
95 | virtual UInt32 GetBitrateMode() { return (UInt32)BitrateMode; }
96 | };
97 |
98 | ///
99 | /// Encode video with H265/HEVC encoder.
100 | ///
101 | public ref class H265VideoEncoder : public IVideoEncoder, INotifyPropertyChanged{
102 | private:
103 | H265Profile _encoderProfile;
104 | H265BitrateControlMode _bitrateMode;
105 | public:
106 | H265VideoEncoder() {
107 | EncoderProfile = H265Profile::Main;
108 | BitrateMode = H265BitrateControlMode::Quality;
109 | }
110 | virtual event PropertyChangedEventHandler^ PropertyChanged;
111 | void OnPropertyChanged(String^ info)
112 | {
113 | PropertyChanged(this, gcnew PropertyChangedEventArgs(info));
114 | }
115 | virtual property VideoEncoderFormat EncodingFormat {
116 | VideoEncoderFormat get() {
117 | return VideoEncoderFormat::H265;
118 | }
119 | }
120 | ///
121 | ///The capabilities the h265 video encoder. At the moment only Main is supported
122 | ///
123 | property H265Profile EncoderProfile {
124 | H265Profile get() {
125 | return _encoderProfile;
126 | }
127 | void set(H265Profile value) {
128 | _encoderProfile = value;
129 | OnPropertyChanged("EncoderProfile");
130 | }
131 | }
132 | ///
133 | ///The bitrate control mode of the video encoder. Default is Quality.
134 | ///
135 | property H265BitrateControlMode BitrateMode {
136 | H265BitrateControlMode get() {
137 | return _bitrateMode;
138 | }
139 | void set(H265BitrateControlMode value) {
140 | _bitrateMode = value;
141 | OnPropertyChanged("BitrateMode");
142 | }
143 | }
144 |
145 | virtual UInt32 GetEncoderProfile() { return (UInt32)EncoderProfile; }
146 | virtual UInt32 GetBitrateMode() { return (UInt32)BitrateMode; }
147 | };
148 | }
--------------------------------------------------------------------------------
/ScreenRecorderLib/Win32WindowEnumeration.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | struct Window
7 | {
8 | public:
9 | Window(nullptr_t) {}
10 | Window(HWND hwnd, std::wstring const& title, std::wstring& className)
11 | {
12 | m_hwnd = hwnd;
13 | m_title = title;
14 | m_className = className;
15 | }
16 |
17 | HWND Hwnd() const noexcept { return m_hwnd; }
18 | std::wstring Title() const noexcept { return m_title; }
19 | std::wstring ClassName() const noexcept { return m_className; }
20 |
21 | private:
22 | HWND m_hwnd;
23 | std::wstring m_title;
24 | std::wstring m_className;
25 | };
26 |
27 | std::wstring GetClassName(HWND hwnd)
28 | {
29 | std::array className;
30 |
31 | ::GetClassName(hwnd, className.data(), (int)className.size());
32 |
33 | std::wstring title(className.data());
34 | return title;
35 | }
36 |
37 | std::wstring GetWindowText(HWND hwnd)
38 | {
39 | std::array windowText;
40 |
41 | ::GetWindowText(hwnd, windowText.data(), (int)windowText.size());
42 |
43 | std::wstring title(windowText.data());
44 | return title;
45 | }
46 |
47 | bool IsRecordableWindow(Window const& window)
48 | {
49 | HWND hwnd = window.Hwnd();
50 | HWND shellWindow = GetShellWindow();
51 |
52 | auto title = window.Title();
53 | auto className = window.ClassName();
54 |
55 | if (hwnd == shellWindow)
56 | {
57 | return false;
58 | }
59 |
60 | if (title.length() == 0)
61 | {
62 | return false;
63 | }
64 |
65 | if (!IsWindowVisible(hwnd))
66 | {
67 | return false;
68 | }
69 |
70 | if (GetAncestor(hwnd, GA_ROOT) != hwnd)
71 | {
72 | return false;
73 | }
74 |
75 | LONG style = GetWindowLong(hwnd, GWL_STYLE);
76 | if (!((style & WS_DISABLED) != WS_DISABLED))
77 | {
78 | return false;
79 | }
80 |
81 | DWORD cloaked = FALSE;
82 | HRESULT hrTemp = DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked));
83 | if (SUCCEEDED(hrTemp) &&
84 | cloaked == DWM_CLOAKED_SHELL)
85 | {
86 | return false;
87 | }
88 |
89 | return true;
90 | }
91 |
92 | BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
93 | {
94 | auto class_name = GetClassName(hwnd);
95 | auto title = GetWindowText(hwnd);
96 |
97 | auto window = Window(hwnd, title, class_name);
98 |
99 | if (IsRecordableWindow(window))
100 | {
101 | std::vector& windows = *reinterpret_cast*>(lParam);
102 | windows.push_back(window);
103 | }
104 | return TRUE;
105 | }
106 |
107 | const std::vector EnumerateWindows()
108 | {
109 | std::vector windows;
110 | EnumWindows(EnumWindowsProc, reinterpret_cast(&windows));
111 |
112 | return windows;
113 | }
--------------------------------------------------------------------------------
/ScreenRecorderLib/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sskodje/ScreenRecorderLib/5611b7266a5a87477313e892dd997bf720c1c5e4/ScreenRecorderLib/app.ico
--------------------------------------------------------------------------------
/ScreenRecorderLib/app.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sskodje/ScreenRecorderLib/5611b7266a5a87477313e892dd997bf720c1c5e4/ScreenRecorderLib/app.rc
--------------------------------------------------------------------------------
/ScreenRecorderLib/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by app.rc
4 |
--------------------------------------------------------------------------------
/ScreenRecorderLibNative/.editorconfig:
--------------------------------------------------------------------------------
1 | # Visual Studio generated .editorconfig file with C++ settings.
2 | root = true
3 |
4 | [*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
5 |
6 | # Visual C++ Code Style settings
7 |
8 | cpp_generate_documentation_comments = xml
9 |
10 | # Visual C++ Formatting settings
11 |
12 | cpp_indent_braces = false
13 | cpp_indent_multi_line_relative_to = innermost_parenthesis
14 | cpp_indent_within_parentheses = indent
15 | cpp_indent_preserve_within_parentheses = true
16 | cpp_indent_case_contents = true
17 | cpp_indent_case_labels = true
18 | cpp_indent_case_contents_when_block = false
19 | cpp_indent_lambda_braces_when_parameter = true
20 | cpp_indent_goto_labels = one_left
21 | cpp_indent_preprocessor = leftmost_column
22 | cpp_indent_access_specifiers = false
23 | cpp_indent_namespace_contents = true
24 | cpp_indent_preserve_comments = false
25 | cpp_new_line_before_open_brace_namespace = ignore
26 | cpp_new_line_before_open_brace_type = ignore
27 | cpp_new_line_before_open_brace_function = ignore
28 | cpp_new_line_before_open_brace_block = ignore
29 | cpp_new_line_before_open_brace_lambda = ignore
30 | cpp_new_line_scope_braces_on_separate_lines = false
31 | cpp_new_line_close_brace_same_line_empty_type = false
32 | cpp_new_line_close_brace_same_line_empty_function = false
33 | cpp_new_line_before_catch = true
34 | cpp_new_line_before_else = true
35 | cpp_new_line_before_while_in_do_while = false
36 | cpp_space_before_function_open_parenthesis = remove
37 | cpp_space_within_parameter_list_parentheses = false
38 | cpp_space_between_empty_parameter_list_parentheses = false
39 | cpp_space_after_keywords_in_control_flow_statements = true
40 | cpp_space_within_control_flow_statement_parentheses = false
41 | cpp_space_before_lambda_open_parenthesis = false
42 | cpp_space_within_cast_parentheses = false
43 | cpp_space_after_cast_close_parenthesis = false
44 | cpp_space_within_expression_parentheses = false
45 | cpp_space_before_block_open_brace = true
46 | cpp_space_between_empty_braces = false
47 | cpp_space_before_initializer_list_open_brace = false
48 | cpp_space_within_initializer_list_braces = true
49 | cpp_space_preserve_in_initializer_list = true
50 | cpp_space_before_open_square_bracket = false
51 | cpp_space_within_square_brackets = false
52 | cpp_space_before_empty_square_brackets = false
53 | cpp_space_between_empty_square_brackets = false
54 | cpp_space_group_square_brackets = true
55 | cpp_space_within_lambda_brackets = false
56 | cpp_space_between_empty_lambda_brackets = false
57 | cpp_space_before_comma = false
58 | cpp_space_after_comma = true
59 | cpp_space_remove_around_member_operators = true
60 | cpp_space_before_inheritance_colon = true
61 | cpp_space_before_constructor_colon = true
62 | cpp_space_remove_before_semicolon = true
63 | cpp_space_after_semicolon = true
64 | cpp_space_remove_around_unary_operator = true
65 | cpp_space_around_binary_operator = insert
66 | cpp_space_around_assignment_operator = insert
67 | cpp_space_pointer_reference_alignment = right
68 | cpp_space_around_ternary_operator = insert
69 | cpp_wrap_preserve_blocks = one_liners
70 |
--------------------------------------------------------------------------------
/ScreenRecorderLibNative/AudioManager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "WASAPICapture.h"
4 | #include "CommonTypes.h"
5 | class AudioManager
6 | {
7 | public:
8 | AudioManager();
9 | ~AudioManager();
10 | HRESULT Initialize(_In_ std::shared_ptr &audioOptions);
11 | void ClearRecordedBytes();
12 | HRESULT StartCapture();
13 | HRESULT StopCapture();
14 | std::vector GrabAudioFrame(_In_ UINT64 durationHundredNanos);
15 | private:
16 | CRITICAL_SECTION m_CriticalSection;
17 | std::shared_ptr m_AudioOptions;
18 | //Output loopback capture, e.g. system audio.
19 | std::unique_ptr m_AudioOutputCapture;
20 | //Audio input, i.e. microphone
21 | std::unique_ptr m_AudioInputCapture;
22 |
23 | bool m_IsCaptureEnabled;
24 |
25 | AUDIO_OPTIONS *GetAudioOptions() { return m_AudioOptions.get(); }
26 |
27 | HRESULT StartDeviceCapture(WASAPICapture *pCapture, std::wstring deviceId, EDataFlow flow);
28 | HRESULT StopDeviceCapture(WASAPICapture *pCapture);
29 | HRESULT ConfigureAudioCapture();
30 |
31 | std::thread m_OptionsListenerThread;
32 | HANDLE m_OptionsListenerStopEvent = nullptr;
33 | void OnOptionsChanged();
34 | HRESULT StopOptionsChangeListenerThread();
35 |
36 | std::vector MixAudio(_In_ std::vector const &first, _In_ std::vector const &second, _In_ float firstVolume, _In_ float secondVolume);
37 | };
--------------------------------------------------------------------------------
/ScreenRecorderLibNative/CMFSinkWriterCallback.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | class CMFSinkWriterCallback : public IMFSinkWriterCallback {
7 |
8 | public:
9 | CMFSinkWriterCallback(_In_ HANDLE hFinalizeEvent, _In_opt_ HANDLE hMarkerEvent) :
10 | m_nRefCount(1),
11 | m_hFinalizeEvent(hFinalizeEvent),
12 | m_hMarkerEvent(hMarkerEvent) {}
13 | virtual ~CMFSinkWriterCallback()
14 | {
15 | }
16 | // IMFSinkWriterCallback methods
17 | STDMETHODIMP OnFinalize(HRESULT hrStatus) {
18 | LOG_DEBUG(L"CMFSinkWriterCallback::OnFinalize");
19 | if (m_hFinalizeEvent != NULL) {
20 | SetEvent(m_hFinalizeEvent);
21 | }
22 | return hrStatus;
23 | }
24 |
25 | STDMETHODIMP OnMarker(DWORD dwStreamIndex, LPVOID pvContext) {
26 | LOG_DEBUG(L"CMFSinkWriterCallback::OnMarker");
27 | if (m_hMarkerEvent != NULL) {
28 | SetEvent(m_hMarkerEvent);
29 | }
30 | return S_OK;
31 | }
32 |
33 | // IUnknown methods
34 | STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {
35 | static const QITAB qit[] = {
36 | QITABENT(CMFSinkWriterCallback, IMFSinkWriterCallback),
37 | {0}
38 | };
39 | return QISearch(this, qit, riid, ppv);
40 | }
41 |
42 | STDMETHODIMP_(ULONG) AddRef() {
43 | return InterlockedIncrement(&m_nRefCount);
44 | }
45 |
46 | STDMETHODIMP_(ULONG) Release() {
47 | ULONG refCount = InterlockedDecrement(&m_nRefCount);
48 | if (refCount == 0) {
49 | delete this;
50 | }
51 | return refCount;
52 | }
53 |
54 | private:
55 | volatile long m_nRefCount;
56 | HANDLE m_hFinalizeEvent;
57 | HANDLE m_hMarkerEvent;
58 | };
--------------------------------------------------------------------------------
/ScreenRecorderLibNative/CameraCapture.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "SourceReaderBase.h"
3 | #include "MF.util.h"
4 |
5 | class CameraCapture : public SourceReaderBase
6 | {
7 | public:
8 | CameraCapture();
9 | virtual ~CameraCapture();
10 | virtual inline std::wstring Name() override { return L"CameraCapture"; };
11 | protected:
12 | virtual HRESULT InitializeSourceReader(
13 | _In_ std::wstring source,
14 | _In_ std::optional sourceFormatIndex,
15 | _Out_ long *pStreamIndex,
16 | _Outptr_ IMFSourceReader **ppSourceReader,
17 | _Outptr_ IMFMediaType **ppInputMediaType,
18 | _Outptr_opt_ IMFMediaType **ppOutputMediaType,
19 | _Outptr_opt_result_maybenull_ IMFTransform **ppMediaTransform) override;
20 |
21 | virtual HRESULT InitializeSourceReader(
22 | _In_ IStream *pSourceStream,
23 | _In_ std::optional sourceFormatIndex,
24 | _Out_ long *pStreamIndex,
25 | _Outptr_ IMFSourceReader **ppSourceReader,
26 | _Outptr_ IMFMediaType **ppInputMediaType,
27 | _Outptr_opt_ IMFMediaType **ppOutputMediaType,
28 | _Outptr_opt_result_maybenull_ IMFTransform **ppMediaTransform) override;
29 |
30 | private:
31 | HRESULT InitializeMediaSource(
32 | _In_ CComPtr pDevice,
33 | _In_ std::optional sourceFormatIndex,
34 | _Out_ long *pStreamIndex,
35 | _Outptr_ IMFSourceReader **ppSourceReader,
36 | _Outptr_ IMFMediaType **ppInputMediaType,
37 | _Outptr_opt_ IMFMediaType **ppOutputMediaType,
38 | _Outptr_opt_result_maybenull_ IMFTransform **ppMediaTransform
39 | );
40 | HRESULT SetDeviceFormat(_In_ CComPtr pDevice, _In_ DWORD dwFormatIndex);
41 | std::wstring m_DeviceName;
42 | std::wstring m_DeviceSymbolicLink;
43 | };
44 |
--------------------------------------------------------------------------------
/ScreenRecorderLibNative/CaptureBase.cpp:
--------------------------------------------------------------------------------
1 | #include "CaptureBase.h"
2 | #include "cleanup.h"
3 |
4 |
5 | CaptureBase::CaptureBase() :
6 | m_LastGrabTimeStamp{},
7 | m_Device(nullptr),
8 | m_DeviceContext(nullptr),
9 | m_RecordingSource(nullptr),
10 | m_TextureManager(nullptr),
11 | m_FrameDataCallbackTexture(nullptr)
12 | {
13 | RtlZeroMemory(&m_FrameDataCallbackTextureDesc, sizeof(m_FrameDataCallbackTextureDesc));
14 | }
15 | CaptureBase::~CaptureBase()
16 | {
17 | SafeRelease(&m_Device);
18 | SafeRelease(&m_DeviceContext);
19 | SafeRelease(&m_FrameDataCallbackTexture);
20 | }
21 | SIZE CaptureBase::GetContentOffset(_In_ ContentAnchor anchor, _In_ RECT parentRect, _In_ RECT contentRect)
22 | {
23 | int leftMargin;
24 | int topMargin;
25 | switch (anchor)
26 | {
27 | case ContentAnchor::TopLeft:
28 | default: {
29 | leftMargin = 0;
30 | topMargin = 0;
31 | break;
32 | }
33 | case ContentAnchor::TopRight: {
34 | leftMargin = (int)max(0, round(((double)RectWidth(parentRect) - (double)RectWidth(contentRect))));
35 | topMargin = 0;
36 | break;
37 | }
38 | case ContentAnchor::Center: {
39 | leftMargin = (int)max(0, round(((double)RectWidth(parentRect) - (double)RectWidth(contentRect))) / 2);
40 | topMargin = (int)max(0, round(((double)RectHeight(parentRect) - (double)RectHeight(contentRect))) / 2);
41 | break;
42 | }
43 | case ContentAnchor::BottomLeft: {
44 | leftMargin = 0;
45 | topMargin = (int)max(0, round(((double)RectHeight(parentRect) - (double)RectHeight(contentRect))));
46 | break;
47 | }
48 | case ContentAnchor::BottomRight: {
49 | leftMargin = (int)max(0, round(((double)RectWidth(parentRect) - (double)RectWidth(contentRect))));
50 | topMargin = (int)max(0, round(((double)RectHeight(parentRect) - (double)RectHeight(contentRect))));
51 | break;
52 | }
53 | }
54 | return SIZE{ leftMargin,topMargin };
55 | }
56 |
57 | HRESULT CaptureBase::SendBitmapCallback(_In_ ID3D11Texture2D *pTexture) {
58 | HRESULT hr = S_FALSE;
59 | CComPtr< ID3D11Texture2D> pProcessedTexture = nullptr;
60 | if (m_RecordingSource->IsVideoFramePreviewEnabled.value_or(false) && m_RecordingSource->HasRegisteredCallbacks()) {
61 | D3D11_TEXTURE2D_DESC textureDesc;
62 | pTexture->GetDesc(&textureDesc);
63 | if (m_RecordingSource->VideoFramePreviewSize.has_value()) {
64 | long cx = m_RecordingSource->VideoFramePreviewSize.value().cx;
65 | long cy = m_RecordingSource->VideoFramePreviewSize.value().cy;
66 | if (cx > 0 && cy == 0) {
67 | cy = static_cast(round((static_cast(textureDesc.Height) / static_cast(textureDesc.Width)) * cx));
68 | }
69 | else if (cx == 0 && cy > 0) {
70 | cx = static_cast(round((static_cast(textureDesc.Width) / static_cast(textureDesc.Height)) * cy));
71 | }
72 | ID3D11Texture2D *pResizedTexture;
73 | RETURN_ON_BAD_HR(hr = m_TextureManager->ResizeTexture(pTexture, SIZE{ cx,cy }, TextureStretchMode::Uniform, &pResizedTexture));
74 | pProcessedTexture.Attach(pResizedTexture);
75 | pResizedTexture->GetDesc(&textureDesc);
76 | }
77 | else {
78 | pProcessedTexture.Attach(pTexture);
79 | pTexture->AddRef();
80 | }
81 | int width = textureDesc.Width;
82 | int height = textureDesc.Height;
83 |
84 | if (m_FrameDataCallbackTextureDesc.Width != width || m_FrameDataCallbackTextureDesc.Height != height) {
85 | SafeRelease(&m_FrameDataCallbackTexture);
86 | textureDesc.Usage = D3D11_USAGE_STAGING;
87 | textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
88 | textureDesc.MiscFlags = 0;
89 | textureDesc.BindFlags = 0;
90 | RETURN_ON_BAD_HR(m_Device->CreateTexture2D(&textureDesc, nullptr, &m_FrameDataCallbackTexture));
91 | m_FrameDataCallbackTextureDesc = textureDesc;
92 | }
93 |
94 | m_DeviceContext->CopyResource(m_FrameDataCallbackTexture, pProcessedTexture);
95 | D3D11_MAPPED_SUBRESOURCE map;
96 | m_DeviceContext->Map(m_FrameDataCallbackTexture, 0, D3D11_MAP_READ, 0, &map);
97 |
98 | int bytesPerPixel = map.RowPitch / width;
99 | int len = map.DepthPitch;
100 | int stride = map.RowPitch;
101 | BYTE *data = static_cast(map.pData);
102 |
103 | m_RecordingSource->NotifyNewFrameDataCallbacks(abs(stride), data, len, width, height);
104 | m_DeviceContext->Unmap(m_FrameDataCallbackTexture, 0);
105 | }
106 | return hr;
107 | }
--------------------------------------------------------------------------------
/ScreenRecorderLibNative/CaptureBase.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "CommonTypes.h"
3 | #include "TextureManager.h"
4 | class CaptureBase abstract
5 | {
6 | public:
7 | CaptureBase();
8 | virtual ~CaptureBase();
9 | virtual HRESULT Initialize(_In_ ID3D11DeviceContext *pDeviceContext, _In_ ID3D11Device *pDevice) abstract;
10 | virtual HRESULT StartCapture(_In_ RECORDING_SOURCE_BASE &source) abstract;
11 | virtual HRESULT AcquireNextFrame(_In_ DWORD timeoutMillis, _Outptr_opt_ ID3D11Texture2D **ppFrame) abstract;
12 | virtual HRESULT WriteNextFrameToSharedSurface(_In_ DWORD timeoutMillis, _Inout_ ID3D11Texture2D *pSharedSurf, INT offsetX, INT offsetY, _In_ RECT destinationRect, _In_opt_ ID3D11Texture2D *pTexture = nullptr) abstract;
13 | virtual HRESULT GetNativeSize(_In_ RECORDING_SOURCE_BASE &recordingSource, _Out_ SIZE *nativeMediaSize) abstract;
14 | virtual HRESULT GetMouse(_Inout_ PTR_INFO *pPtrInfo, _In_ RECT frameCoordinates, _In_ int offsetX, _In_ int offsetY) abstract;
15 | virtual std::wstring Name() abstract;
16 | virtual HRESULT SendBitmapCallback(_In_ ID3D11Texture2D *pTexture);
17 | ///
18 | /// Calculate the offset used to position the content withing the parent frame based on the given anchor.
19 | ///
20 | ///
21 | ///
22 | ///
23 | ///
24 | virtual SIZE GetContentOffset(_In_ ContentAnchor anchor, _In_ RECT parentRect, _In_ RECT contentRect);
25 | protected:
26 |
27 | ID3D11Device *m_Device;
28 | ID3D11DeviceContext *m_DeviceContext;
29 | std::unique_ptr m_TextureManager;
30 | RECORDING_SOURCE_BASE *m_RecordingSource;
31 | LARGE_INTEGER m_LastGrabTimeStamp;
32 |
33 | private:
34 | ID3D11Texture2D *m_FrameDataCallbackTexture;
35 | D3D11_TEXTURE2D_DESC m_FrameDataCallbackTextureDesc;
36 | };
--------------------------------------------------------------------------------
/ScreenRecorderLibNative/CoreAudio.util.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "CommonTypes.h"
3 | #include
4 | #include