├── LICENSE
├── NetworkVideoEncoder
├── .gitignore
├── Client
│ ├── App.config
│ ├── Client.csproj
│ ├── JobHandler.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Resources.cs
│ └── RunFFMPEG.cs
├── NetworkVideoEncoder.sln
├── Server
│ ├── App.config
│ ├── ClientDataBlock.cs
│ ├── ClientObject.cs
│ ├── DLL
│ │ └── AbstractTCPlib.dll
│ ├── DownStream.cs
│ ├── Job.cs
│ ├── JobDataBlock.cs
│ ├── JobProvider.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Server.csproj
│ ├── StreamHelper.cs
│ └── UpStream.cs
└── SharedTypes
│ ├── Headers.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ └── SharedTypes.csproj
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Jonathan Van den broeck
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 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Client/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Client/Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {6B1FA431-2D8A-4DC0-8633-A8D8182D0014}
8 | Exe
9 | Client
10 | Client
11 | v4.5.2
12 | 512
13 | true
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 | ..\Server\DLL\AbstractTCPlib.dll
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | {825f525f-54b6-4fb3-9339-9b17e1ad922b}
60 | SharedTypes
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Client/JobHandler.cs:
--------------------------------------------------------------------------------
1 | using AbstractTCPlib;
2 | using SharedTypes;
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 |
9 | namespace Client
10 | {
11 | public class JobHandler
12 | {
13 | private TCPgeneral gen;
14 | private string ffmpegCommand;
15 | private string job;
16 | private FileStream stream;
17 | private RunFFMPEG ffmpeg;
18 | private string outputFile;
19 | private bool sendCompleted;
20 | private ManualResetEvent reset;
21 |
22 | public JobHandler(TCPgeneral gen)
23 | {
24 | reset = new ManualResetEvent(false);
25 | sendCompleted = false;
26 | this.gen = gen;
27 | gen.OnRawDataRecieved += OnRecieved;
28 | gen.OnError += OnError;
29 | }
30 | public void Start()
31 | {
32 | gen.Start();
33 |
34 |
35 | reset.WaitOne();
36 |
37 | reset.Reset();
38 |
39 | }
40 | private void SendVidPiece()
41 | {
42 | if (sendCompleted)
43 | {
44 | gen.SendTCP(Headers.SendCompleted);
45 | stream.Close();
46 | File.Delete(Path.Combine(Resources.OutputFolder, outputFile));
47 |
48 | sendCompleted = false;
49 | ffmpegCommand = null;
50 | job = null;
51 |
52 | reset.Set();
53 |
54 | }
55 | else
56 | {
57 | int l = 10000000; // = 10MB
58 | byte[] data = new byte[l];
59 |
60 | int read = stream.Read(data, 0, l);
61 | if (read != l)
62 | {
63 | byte[] cropped = new byte[read];
64 | Array.Copy(data, 0, cropped, 0, read);
65 | gen.SendTCP(Headers.AssembleHeader(Headers.PieceOfVideo, cropped));
66 | sendCompleted = true;
67 | }
68 | else
69 | {
70 | gen.SendTCP(Headers.AssembleHeader(Headers.PieceOfVideo, data));
71 | }
72 | }
73 | }
74 | private void OnRecieved(int id, byte[] rawData)
75 | {
76 | byte[] header = Headers.GetHeaderFromData(rawData);
77 |
78 | if (Headers.FfmpegCommand.SequenceEqual(header))
79 | {
80 | byte[] data;
81 | Headers.SplitData(rawData, out header, out data);
82 | ffmpegCommand = @Encoding.ASCII.GetString(data);
83 |
84 | string formatted = ffmpegCommand.Replace(Resources.ffmpegDATA, Path.Combine(Resources.InputFolder, @job));
85 |
86 | Guid uniqueName = Guid.NewGuid();
87 | outputFile = uniqueName.ToString();
88 | int ind = formatted.IndexOf(Resources.ffmpegOUT);
89 | ind += 3;
90 |
91 | for (int i = ind; i < formatted.Length; i++)
92 | {
93 | if (formatted[i] != '"')
94 | {
95 | outputFile += formatted[i];
96 | }
97 | else
98 | {
99 | break;
100 | }
101 | }
102 |
103 | formatted = formatted.Replace(Resources.ffmpegOUT, Path.Combine(Resources.OutputFolder, uniqueName.ToString()));
104 |
105 | ffmpeg = new RunFFMPEG(formatted);
106 | Console.WriteLine("command:" + formatted);
107 | }
108 | else if (Headers.Job.SequenceEqual(header))
109 | {
110 | byte[] data;
111 | Headers.SplitData(rawData, out header, out data);
112 | stream = new FileStream(Path.Combine(Resources.InputFolder, Encoding.ASCII.GetString(data)), FileMode.Append);
113 | job = @Encoding.ASCII.GetString(data);
114 | Console.WriteLine("job " + job);
115 | }
116 | else if (Headers.PieceOfVideo.SequenceEqual(header))
117 | {
118 | byte[] vid;
119 | Headers.SplitData(rawData, out header, out vid);
120 | stream.Write(vid, 0, vid.Length);
121 | gen.SendTCP(Headers.SendNext);
122 | }
123 | else if (Headers.SendCompleted.SequenceEqual(header))
124 | {
125 | stream.Close();
126 | stream = null;
127 | Console.WriteLine("Recieved all");
128 | ffmpeg.Start();
129 | stream = new FileStream(Path.Combine(Resources.OutputFolder, outputFile), FileMode.Open);
130 | File.Delete(Path.Combine(Resources.InputFolder, @job));
131 | gen.SendTCP(Headers.RenderCompleted);
132 | }
133 | else if (Headers.SendNext.SequenceEqual(header))
134 | {
135 | SendVidPiece();
136 | }
137 | }
138 |
139 | private void OnError(int id, ErrorTypes type, string error)
140 | {
141 | Console.WriteLine("error: " + type.ToString() + " " + error);
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Client/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using AbstractTCPlib;
3 | using AbstractTCPlib.UDPdiscovery;
4 | using System.Net.Sockets;
5 | using System.IO;
6 |
7 | namespace Client
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | if (args.Length != 1)
14 | {
15 | Console.WriteLine(Resources.Usage);
16 | Console.ReadLine();
17 | Environment.Exit(0);
18 | }
19 | int port;
20 |
21 | bool ok = int.TryParse(args[0], out port);
22 |
23 | if (!ok)
24 | {
25 | Console.WriteLine(Resources.Usage);
26 | Console.ReadLine();
27 | Environment.Exit(0);
28 | }
29 |
30 | UDPclient udp = new UDPclient(Resources.BroadCast, port);
31 | TcpClient client;
32 | while (true)
33 | {
34 | client = udp.Broadcast();
35 |
36 | if (client != null)
37 | {
38 | client.SendBufferSize = 64000;
39 | client.ReceiveBufferSize = 64000; //needed for linux
40 | break;
41 | }
42 | }
43 |
44 | CreateFolders(Resources.InputFolder);
45 | CreateFolders(Resources.OutputFolder);
46 |
47 | ClearFolder(Resources.InputFolder);
48 | ClearFolder(Resources.OutputFolder);
49 |
50 | TCPgeneral gen = new TCPgeneral(client, 0);
51 |
52 | JobHandler job = new JobHandler(gen);
53 |
54 | while (true)
55 | {
56 | job.Start();
57 | }
58 | }
59 |
60 | private static void CreateFolders(string folder)
61 | {
62 | if (!Directory.Exists(folder))
63 | {
64 | Directory.CreateDirectory(folder);
65 | }
66 | }
67 |
68 | private static void ClearFolder(string folder)
69 | {
70 | var files = Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, folder));
71 |
72 | foreach (var file in files)
73 | {
74 | File.Delete(file);
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Client/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Client")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Client")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("6b1fa431-2d8a-4dc0-8633-a8d8182d0014")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Client/Resources.cs:
--------------------------------------------------------------------------------
1 | namespace Client
2 | {
3 | public static class Resources
4 | {
5 | public static string BroadCast = "networkVideoEncoder";
6 | public static string Usage = "command line input: udpPort";
7 | public static string OutputFolder = "OUTPUT";
8 | public static string InputFolder = "INPUT";
9 | public static string ffmpegDATA = "DATA";
10 | public static string ffmpegOUT = "OUT";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Client/RunFFMPEG.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 |
4 | namespace Client
5 | {
6 | public class RunFFMPEG
7 | {
8 | private string binLocationL = @"/usr/bin/ffmpeg";
9 | private Process ffmpegProcess;
10 | private string binaryW = @"ffmpeg.exe";
11 |
12 | public RunFFMPEG(string command)
13 | {
14 | ffmpegProcess = new Process();
15 | if (IsLinux())
16 | {
17 | ffmpegProcess.StartInfo.FileName = binLocationL;
18 | ffmpegProcess.StartInfo.CreateNoWindow = true;
19 | ffmpegProcess.StartInfo.UseShellExecute = false;
20 | }
21 | else
22 | {
23 | ffmpegProcess.StartInfo.FileName = binaryW;
24 | ffmpegProcess.StartInfo.CreateNoWindow = false;
25 | ffmpegProcess.StartInfo.UseShellExecute = true;
26 | }
27 | ffmpegProcess.StartInfo.Arguments = command;
28 | }
29 |
30 | public void Start()
31 | {
32 | ffmpegProcess.Start();
33 | ffmpegProcess.WaitForExit();
34 | }
35 |
36 | private bool IsLinux()
37 | {
38 | int p = (int)Environment.OSVersion.Platform;
39 | return (p == 4) || (p == 6) || (p == 128);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/NetworkVideoEncoder.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26430.13
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{A4A128D8-1E40-49C7-876A-A1376188C1B7}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedTypes", "SharedTypes\SharedTypes.csproj", "{825F525F-54B6-4FB3-9339-9B17E1AD922B}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{6B1FA431-2D8A-4DC0-8633-A8D8182D0014}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {A4A128D8-1E40-49C7-876A-A1376188C1B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {A4A128D8-1E40-49C7-876A-A1376188C1B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {A4A128D8-1E40-49C7-876A-A1376188C1B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {A4A128D8-1E40-49C7-876A-A1376188C1B7}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {825F525F-54B6-4FB3-9339-9B17E1AD922B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {825F525F-54B6-4FB3-9339-9B17E1AD922B}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {825F525F-54B6-4FB3-9339-9B17E1AD922B}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {825F525F-54B6-4FB3-9339-9B17E1AD922B}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {6B1FA431-2D8A-4DC0-8633-A8D8182D0014}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {6B1FA431-2D8A-4DC0-8633-A8D8182D0014}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {6B1FA431-2D8A-4DC0-8633-A8D8182D0014}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {6B1FA431-2D8A-4DC0-8633-A8D8182D0014}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | EndGlobal
35 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/ClientDataBlock.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Server
4 | {
5 | public static class ClientDataBlock
6 | {
7 | private static object locker = new object();
8 |
9 | private static List _clients = new List();
10 |
11 | public static List Clients
12 | {
13 | get
14 | {
15 | lock (locker)
16 | {
17 | return _clients;
18 | }
19 | }
20 | set
21 | {
22 | lock (locker)
23 | {
24 | _clients = value;
25 | }
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/ClientObject.cs:
--------------------------------------------------------------------------------
1 | using AbstractTCPlib;
2 | using System;
3 |
4 | namespace Server
5 | {
6 | public class ClientObject
7 | {
8 | public Action OnFinished;
9 |
10 | public TCPgeneral socket { get; set; }
11 | public bool HasJob { get; set; }
12 | public DateTime LastSeen { get; set; }
13 | public string CurrentJob { get; set; }
14 | public DateTime JobStarted { get; set; }
15 | public bool isDone { get; set; }
16 |
17 | public void Finished()
18 | {
19 | if (OnFinished != null)
20 | {
21 | OnFinished(this);
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/DLL/AbstractTCPlib.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathan2266/NetworkVideoEncoder/5ca53c008085cd99f1a4cad66359756194082ca6/NetworkVideoEncoder/Server/DLL/AbstractTCPlib.dll
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/DownStream.cs:
--------------------------------------------------------------------------------
1 | using AbstractTCPlib;
2 | using SharedTypes;
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Threading;
7 |
8 | namespace Server
9 | {
10 | public class DownStream
11 | {
12 | private ClientObject obj;
13 | private FileStream stream;
14 | private byte[] pieceOfVideo;
15 | private string output;
16 | private AutoResetEvent waitHandle;
17 |
18 | public DownStream(ClientObject obj, string output, string extenstion)
19 | {
20 | waitHandle = new AutoResetEvent(false);
21 | this.output = output;
22 | pieceOfVideo = null;
23 | this.obj = obj;
24 | stream = File.OpenWrite(Path.Combine(output, Path.GetFileNameWithoutExtension(obj.CurrentJob) + extenstion));
25 | obj.socket.OnRawDataRecieved += OnRecieved;
26 | obj.socket.OnError += OnError;
27 | }
28 | public void Start()
29 | {
30 | obj.socket.SendTCP(Headers.SendNext);
31 |
32 | waitHandle.WaitOne();
33 |
34 | stream.Close();
35 |
36 | }
37 | private void OnRecieved(int id, byte[] rawData)
38 | {
39 | byte[] header = Headers.GetHeaderFromData(rawData);
40 |
41 | if (Headers.PieceOfVideo.SequenceEqual(header))
42 | {
43 | Headers.SplitData(rawData, out header, out pieceOfVideo);
44 |
45 | try
46 | {
47 | stream.Write(pieceOfVideo, 0, pieceOfVideo.Length);
48 | obj.socket.SendTCP(Headers.SendNext);
49 | }
50 | catch (Exception e)
51 | {
52 | Console.WriteLine("Downstream write exception: " + e.Message);
53 | stream.Close();
54 | }
55 | }
56 | else if (Headers.SendCompleted.SequenceEqual(header))
57 | {
58 | waitHandle.Set();
59 |
60 | lock (ClientDataBlock.Clients)
61 | {
62 | obj.socket.OnRawDataRecieved -= OnRecieved;
63 | obj.socket.OnError -= OnError;
64 | obj.isDone = true;
65 | obj.Finished();
66 | }
67 | }
68 | }
69 | private void OnError(int id, ErrorTypes type, string message)
70 | {
71 | waitHandle.Set();
72 |
73 | lock (ClientDataBlock.Clients)
74 | {
75 | obj.socket.OnRawDataRecieved -= OnRecieved;
76 | obj.socket.OnError -= OnError;
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/Job.cs:
--------------------------------------------------------------------------------
1 | namespace Server
2 | {
3 | public class Job
4 | {
5 | public string JobURL { get; set; }
6 | public int ClientID { get; set; }
7 | public bool IsGivenAsJob { get; set; }
8 | public bool IsDone { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/JobDataBlock.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Server
4 | {
5 | public static class JobDataBlock
6 | {
7 | private static object locker = new object();
8 |
9 | private static List _jobs = new List();
10 | public static List Jobs
11 | {
12 | get
13 | {
14 | lock (locker)
15 | {
16 | return _jobs;
17 | }
18 | }
19 | set
20 | {
21 | lock (locker)
22 | {
23 | _jobs = value;
24 | }
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/JobProvider.cs:
--------------------------------------------------------------------------------
1 | using AbstractTCPlib;
2 | using System;
3 | using System.Text;
4 | using System.IO;
5 | using SharedTypes;
6 | using System.Linq;
7 | using System.Threading;
8 |
9 | namespace Server
10 | {
11 | public class JobProvider
12 | {
13 | private string output;
14 | private string ffmpegCommand;
15 | private StreamHelper streamer;
16 | private ManualResetEvent mainLoopWait;
17 | private string extension;
18 |
19 | public JobProvider(string ffmpeg, string source, string output)
20 | {
21 | this.output = output;
22 |
23 | string[] files = Directory.GetFiles(source);
24 |
25 | for (int i = 0; i < files.Length; i++)
26 | {
27 | files[i] = Path.GetFileName(files[i]);
28 | }
29 |
30 | for (int i = 0; i < files.Length; i++)
31 | {
32 | JobDataBlock.Jobs.Add(new Job
33 | {
34 | IsGivenAsJob = false,
35 | JobURL = files[i],
36 | ClientID = -1,
37 | IsDone = false
38 | });
39 | }
40 |
41 | StreamReader reader = new StreamReader(ffmpeg);
42 | ffmpegCommand = reader.ReadToEnd();
43 | reader.Close();
44 |
45 | int ind = ffmpegCommand.IndexOf("OUT");
46 | ind += 3;
47 |
48 | for (int i = ind; i < ffmpegCommand.Length; i++)
49 | {
50 | if (ffmpegCommand[i] != '"')
51 | {
52 | extension += ffmpegCommand[i];
53 | }
54 | else
55 | {
56 | break;
57 | }
58 | }
59 |
60 | streamer = new StreamHelper(4, source, output, extension);
61 |
62 | mainLoopWait = new ManualResetEvent(false);
63 | }
64 |
65 | public void RunJobs()
66 | {
67 | GiveJobs();
68 |
69 | mainLoopWait.WaitOne();
70 |
71 | streamer.Dispose();
72 | }
73 | private void GiveJobs()
74 | {
75 | lock (ClientDataBlock.Clients)
76 | {
77 | lock (JobDataBlock.Jobs)
78 | {
79 | foreach (var client in ClientDataBlock.Clients)
80 | {
81 | if (!client.HasJob && client.socket.IsAlive)
82 | {
83 | foreach (var job in JobDataBlock.Jobs)
84 | {
85 | if (!job.IsGivenAsJob)
86 | {
87 | job.IsGivenAsJob = true;
88 | job.ClientID = client.socket.ID;
89 | client.HasJob = true;
90 | client.CurrentJob = job.JobURL;
91 | client.socket.SendTCP(Headers.AssembleHeader(Headers.Job, Encoding.ASCII.GetBytes(job.JobURL)));
92 | client.socket.SendTCP(Headers.AssembleHeader(Headers.FfmpegCommand, Encoding.ASCII.GetBytes(ffmpegCommand)));
93 | streamer.AddClientToSendQeue(client);
94 | break;
95 | }
96 | }
97 | }
98 | }
99 | }
100 | }
101 | }
102 |
103 | public void AddClient(TCPgeneral client)
104 | {
105 | lock (ClientDataBlock.Clients)
106 | {
107 | client.OnError = OnError;
108 | client.OnRawDataRecieved += RecievedData;
109 | client.Start();
110 |
111 | ClientObject obj = new ClientObject
112 | {
113 | socket = client,
114 | HasJob = false,
115 | LastSeen = DateTime.Now,
116 | JobStarted = DateTime.MinValue,
117 | isDone = false
118 | };
119 | obj.OnFinished += ClientFinished;
120 | ClientDataBlock.Clients.Add(obj);
121 |
122 | GiveJobs();
123 | }
124 | }
125 |
126 | private void RecievedData(int id, byte[] data)
127 | {
128 | byte[] header = Headers.GetHeaderFromData(data);
129 |
130 | if (header.SequenceEqual(Headers.HelloUpdate))
131 | {
132 | lock (ClientDataBlock.Clients)
133 | {
134 | ClientObject obj = ClientDataBlock.Clients.Where(s => s.socket.ID == id).FirstOrDefault();
135 | obj.LastSeen = DateTime.Now;
136 | }
137 | }
138 | else if (header.SequenceEqual(Headers.RenderCompleted))
139 | {
140 | lock (ClientDataBlock.Clients)
141 | {
142 | streamer.AddClientToRecieveQeue(ClientDataBlock.Clients.Where(s => s.socket.ID == id).FirstOrDefault());
143 | Console.WriteLine("ID: " + id + " renderCompleted");
144 | }
145 | }
146 | else if (header.SequenceEqual(Headers.RenderError))
147 | {
148 | lock (ClientDataBlock.Clients)
149 | {
150 | lock (JobDataBlock.Jobs)
151 | {
152 | // log job from being bad or maybe ffmpeg command being bad
153 | Console.WriteLine("ID: " + id + " renderError");
154 |
155 | ClientObject obj = ClientDataBlock.Clients.Where(client => client.socket.ID == id).FirstOrDefault();
156 | if (obj != null)
157 | {
158 | Job jo = JobDataBlock.Jobs.Where(j => j.ClientID == obj.socket.ID).FirstOrDefault();
159 |
160 | if (jo != null)
161 | {
162 | jo.IsGivenAsJob = false;
163 | jo.IsDone = false;
164 | jo.ClientID = -1;
165 | }
166 | }
167 | }
168 | }
169 | }
170 | }
171 |
172 | private void OnError(int id, ErrorTypes type, string message)
173 | {
174 | lock (ClientDataBlock.Clients)
175 | {
176 | lock (JobDataBlock.Jobs)
177 | {
178 | Console.WriteLine("lost connection with:" + id + " " + type.ToString() + " " + message);
179 |
180 | ClientObject obj = ClientDataBlock.Clients.Where(client => client.socket.ID == id).FirstOrDefault();
181 | if (obj != null)
182 | {
183 | lock (obj)
184 | {
185 | Job jo = JobDataBlock.Jobs.Where(j => j.ClientID == obj.socket.ID).FirstOrDefault();
186 |
187 | if (jo != null)
188 | {
189 | jo.IsGivenAsJob = false;
190 | jo.IsDone = false;
191 | jo.ClientID = -1;
192 | }
193 | obj.socket.Dispose();
194 |
195 | ClientDataBlock.Clients.Remove(obj);
196 | }
197 | }
198 | }
199 | }
200 | }
201 | private void ClientFinished(ClientObject obj)
202 | {
203 | lock (ClientDataBlock.Clients)
204 | {
205 | lock (JobDataBlock.Jobs)
206 | {
207 | Job jo = JobDataBlock.Jobs.Where(j => j.ClientID == obj.socket.ID).FirstOrDefault();
208 |
209 | if (jo != null)
210 | {
211 | Console.WriteLine("job: " + jo.JobURL + " is done");
212 | jo.IsDone = true;
213 | jo.ClientID = -1;
214 | obj.HasJob = false;
215 | obj.isDone = true;
216 | obj.JobStarted = DateTime.MinValue;
217 | obj.LastSeen = DateTime.Now;
218 | }
219 | }
220 | }
221 |
222 | GiveJobs();
223 |
224 | IsAllDone();
225 | }
226 | private void IsAllDone()
227 | {
228 | lock (JobDataBlock.Jobs)
229 | {
230 | int incompleted = JobDataBlock.Jobs.Where(job => job.IsDone == false).Count();
231 |
232 | if (incompleted > 0)
233 | {
234 | return;
235 | }
236 |
237 | int stillWorking = ClientDataBlock.Clients.Where(client => client.HasJob == true).Count();
238 |
239 | if (stillWorking > 0)
240 | {
241 | return;
242 | }
243 |
244 | Console.WriteLine("All jobs completed");
245 |
246 | mainLoopWait.Set();
247 | }
248 | }
249 | }
250 | }
251 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using AbstractTCPlib;
4 | using AbstractTCPlib.UDPdiscovery;
5 | using System.Threading;
6 | using System.Net.Sockets;
7 |
8 | namespace Server
9 | {
10 | class Program
11 | {
12 | static int currentID = 0;
13 | static string usage = "command line input: ffmpeg_command_file source_folder output_folder udpPort";
14 | static string broadCast = "networkVideoEncoder";
15 | static string ffmpeg;
16 | static string source;
17 | static string output;
18 | static int port;
19 |
20 | static JobProvider provider;
21 |
22 | static void Main(string[] args)
23 | {
24 | if (args.Length != 4)
25 | {
26 | Console.WriteLine(usage);
27 | Console.ReadLine();
28 | Environment.Exit(0);
29 | }
30 |
31 | ffmpeg = args[0];
32 | source = args[1];
33 | if (!Directory.Exists(source))
34 | {
35 | Console.WriteLine("input directory does not excist");
36 | Console.WriteLine(usage);
37 | Environment.Exit(0);
38 | }
39 | output = args[2];
40 | if (!Directory.Exists(output))
41 | {
42 | Console.WriteLine("output directory does not excist");
43 | Console.WriteLine(usage);
44 | Environment.Exit(0);
45 | }
46 | if (!int.TryParse(args[3], out port))
47 | {
48 | Console.WriteLine("port should be in an int");
49 | Console.WriteLine(usage);
50 | Environment.Exit(0);
51 | }
52 |
53 | provider = new JobProvider(ffmpeg, source, output);
54 |
55 | Thread listentoClients = new Thread(new ThreadStart(Listen));
56 | listentoClients.IsBackground = true;
57 | listentoClients.Start();
58 |
59 | provider.RunJobs();
60 |
61 | }
62 |
63 | private static void Listen()
64 | {
65 | UDPmaster master = new UDPmaster(broadCast, port);
66 |
67 | while (true)
68 | {
69 | TcpClient client = master.Listen();
70 | if (client != null)
71 | {
72 | Console.WriteLine("new client found");
73 | client.SendBufferSize = 64000;
74 | client.ReceiveBufferSize = 64000; //needed for linux
75 | provider.AddClient(new TCPgeneral(client, currentID++));
76 | }
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Server")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Server")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("a4a128d8-1e40-49c7-876a-a1376188c1b7")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/Server.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {A4A128D8-1E40-49C7-876A-A1376188C1B7}
8 | Exe
9 | Server
10 | Server
11 | v4.5.2
12 | 512
13 | true
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 | False
37 | DLL\AbstractTCPlib.dll
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | {825F525F-54B6-4FB3-9339-9B17E1AD922B}
69 | SharedTypes
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/StreamHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Threading;
4 |
5 | namespace Server
6 | {
7 | public class StreamHelper: IDisposable
8 | {
9 | private ConcurrentQueue SendWaiting;
10 | private ConcurrentQueue RecieveWaiting;
11 | private int maxStreams;
12 | private Thread streamSendWorker;
13 | private Thread streamRecieveWorker;
14 | private volatile int currentStreams;
15 | private string source;
16 | private string output;
17 | private string extenstion;
18 | private ManualResetEvent recieveBlock;
19 | private ManualResetEvent sendBlock;
20 |
21 | public StreamHelper(int maxConcurrentStreams, string source, string output, string extenstion)
22 | {
23 | this.source = source;
24 | this.output = output;
25 | this.extenstion = extenstion;
26 | SendWaiting = new ConcurrentQueue();
27 | RecieveWaiting = new ConcurrentQueue();
28 | maxStreams = maxConcurrentStreams;
29 | currentStreams = 0;
30 |
31 | recieveBlock = new ManualResetEvent(false);
32 | sendBlock = new ManualResetEvent(false);
33 |
34 | streamSendWorker = new Thread(new ThreadStart(SendWorker))
35 | {
36 | IsBackground = true
37 | };
38 | streamSendWorker.Start();
39 |
40 | streamRecieveWorker = new Thread(new ThreadStart(RecieveWorker))
41 | {
42 | IsBackground = true
43 | };
44 | streamRecieveWorker.Start();
45 | }
46 | private void RecieveWorker()
47 | {
48 | ClientObject obj;
49 |
50 | while (true)
51 | {
52 | recieveBlock.WaitOne();
53 |
54 | if (currentStreams < maxStreams && RecieveWaiting.Count > 0 && RecieveWaiting.TryDequeue(out obj))
55 | {
56 | currentStreams++;
57 | Thread streamThread = new Thread(() => {
58 | recieveBlock.Reset();
59 | new DownStream(obj, output, extenstion).Start();
60 | currentStreams--;
61 | });
62 | streamThread.IsBackground = true;
63 | streamThread.Start();
64 |
65 | lock (RecieveWaiting)
66 | {
67 | if (RecieveWaiting.IsEmpty)
68 | {
69 | recieveBlock.Reset();
70 | }
71 | }
72 | }
73 | }
74 | }
75 | private void SendWorker()
76 | {
77 | ClientObject obj;
78 |
79 | while (true)
80 | {
81 | sendBlock.WaitOne();
82 |
83 | if (currentStreams < maxStreams && SendWaiting.Count > 0 && SendWaiting.TryDequeue(out obj))
84 | {
85 | currentStreams++;
86 | Thread streamThread = new Thread(() => {
87 | new UpStream(obj, source).Start(); });
88 | currentStreams--;
89 | streamThread.IsBackground = true;
90 | streamThread.Start();
91 |
92 | lock (SendWaiting)
93 | {
94 | if (SendWaiting.IsEmpty)
95 | {
96 | sendBlock.Reset();
97 | }
98 | }
99 | }
100 | }
101 | }
102 | public void AddClientToSendQeue(ClientObject obj)
103 | {
104 | if (obj != null)
105 | {
106 | lock (SendWaiting)
107 | {
108 | SendWaiting.Enqueue(obj);
109 | sendBlock.Set();
110 | }
111 | }
112 | }
113 | public void AddClientToRecieveQeue(ClientObject obj)
114 | {
115 | if (obj != null)
116 | {
117 | lock (RecieveWaiting)
118 | {
119 | RecieveWaiting.Enqueue(obj);
120 | recieveBlock.Set();
121 | }
122 | }
123 | }
124 | public void Dispose()
125 | {
126 | streamSendWorker.Abort();
127 | streamRecieveWorker.Abort();
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/Server/UpStream.cs:
--------------------------------------------------------------------------------
1 | using AbstractTCPlib;
2 | using SharedTypes;
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Threading;
7 |
8 | namespace Server
9 | {
10 | public class UpStream
11 | {
12 | private ClientObject obj;
13 | private FileStream stream;
14 | private volatile bool isDone;
15 | private int l = 10000000; // = 10MB
16 | private byte[] data;
17 | private AutoResetEvent reset;
18 |
19 | public UpStream(ClientObject obj, string source)
20 | {
21 | reset = new AutoResetEvent(false);
22 | data = new byte[l];
23 | this.obj = obj;
24 | obj.socket.OnRawDataRecieved += OnRecieve;
25 | obj.socket.OnError += OnError;
26 | try
27 | {
28 | stream = File.OpenRead(Path.Combine(source, obj.CurrentJob));
29 | }
30 | catch (Exception)
31 | {
32 | //stop
33 | }
34 |
35 | isDone = false;
36 | }
37 | public void Start()
38 | {
39 | SendNextPiece();
40 |
41 | reset.WaitOne();
42 |
43 | stream.Close();
44 |
45 | lock (ClientDataBlock.Clients)
46 | {
47 | obj.socket.OnRawDataRecieved -= OnRecieve;
48 | obj.socket.OnError -= OnError;
49 | }
50 | }
51 | private void SendNextPiece()
52 | {
53 | if (isDone)
54 | {
55 | obj.socket.SendTCP(Headers.SendCompleted);
56 | obj.JobStarted = DateTime.Now;
57 | reset.Set();
58 | }
59 | else
60 | {
61 | try
62 | {
63 | int read = stream.Read(data, 0, l);
64 | if (read != l)
65 | {
66 | byte[] cropped = new byte[read];
67 | Array.Copy(data, 0, cropped, 0, read);
68 | obj.socket.SendTCP(Headers.AssembleHeader(Headers.PieceOfVideo, cropped));
69 | isDone = true;
70 | }
71 | else
72 | {
73 | obj.socket.SendTCP(Headers.AssembleHeader(Headers.PieceOfVideo, data));
74 | }
75 | }
76 | catch (Exception e)
77 | {
78 | Console.WriteLine("Exception in upstream: " + e.Message);
79 | stream.Close();
80 | }
81 | }
82 |
83 |
84 | }
85 | private void OnRecieve(int id, byte[] rawData)
86 | {
87 | byte[] header = Headers.GetHeaderFromData(rawData);
88 |
89 | if (Headers.SendNext.SequenceEqual(header))
90 | {
91 | SendNextPiece();
92 | }
93 | }
94 | private void OnError(int id, ErrorTypes type, string message)
95 | {
96 | reset.Set();
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/SharedTypes/Headers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SharedTypes
4 | {
5 | public static class Headers
6 | {
7 | public static byte[] ID { get { return new byte[] { 0, 0, 0, 0 }; } }
8 | public static byte[] Job { get { return new byte[] { 0, 0, 0, 1 }; } }
9 | public static byte[] PieceOfVideo { get { return new byte[] { 0, 0, 0, 2 }; } }
10 | public static byte[] SendNext { get { return new byte[] { 0, 0, 0, 3 }; } }
11 | public static byte[] HelloUpdate { get { return new byte[] { 0, 0, 0, 4 }; } }
12 | public static byte[] SendCompleted { get { return new byte[] { 0, 0, 0, 5 }; } }
13 | public static byte[] RenderCompleted { get { return new byte[] { 0, 0, 0, 6 }; } }
14 | public static byte[] RenderError { get { return new byte[] { 0, 0, 0, 7 }; } }
15 | public static byte[] FfmpegCommand { get { return new byte[] { 0, 0, 0, 8 }; } }
16 |
17 | public static byte[] AssembleHeader(byte[] header, byte[] data)
18 | {
19 | byte[] fin = new byte[header.Length + data.Length];
20 | Array.Copy(header, 0, fin, 0, header.Length);
21 | Array.Copy(data, 0, fin, header.Length, data.Length);
22 | return fin;
23 | }
24 | public static byte[] GetHeaderFromData(byte[] data)
25 | {
26 | byte[] header = new byte[4];
27 |
28 | if (data.Length >= 4)
29 | {
30 | Array.Copy(data, 0, header, 0, 4);
31 | return header;
32 | }
33 | else
34 | {
35 | return null;
36 | }
37 | }
38 | public static void SplitData(byte[] rawData, out byte[] header, out byte[] data)
39 | {
40 | header = new byte[4];
41 | data = new byte[rawData.Length - 4];
42 |
43 | if (rawData.Length >= 4)
44 | {
45 | Array.Copy(rawData, 0, header, 0, 4);
46 | Array.Copy(rawData, 4, data, 0, rawData.Length - 4);
47 | }
48 | else
49 | {
50 | header = null;
51 | data = null;
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/SharedTypes/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("SharedTypes")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("SharedTypes")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("825f525f-54b6-4fb3-9339-9b17e1ad922b")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/NetworkVideoEncoder/SharedTypes/SharedTypes.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {825F525F-54B6-4FB3-9339-9B17E1AD922B}
8 | Library
9 | Properties
10 | SharedTypes
11 | SharedTypes
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NetworkVideoEncoder
2 | Using c# and ffmpeg to encode a batch of video's or music over a network both in mono and windows.
3 |
4 | **early version but works!!**
5 |
6 | ## Usage
7 |
8 | * Linux requires that the ffmpeg binary is under /usr/bin/
9 | * Windows requires that the ffmpeg.exe binary is supplied locally next to the client.exe
10 | * Running the **Server** or the **Client** binaries will output the correct input arguments
11 | * ffmpeg command file example
12 | * File location given to the **Server** binary. The Client then uses this as input arguments for ffmpeg.
13 | ```bash
14 | -i "DATA" -c:v libx264 -preset fast -crf 50 -map 0:0 -map 0:1 -c:s copy -c:a copy "OUT.extension"
15 | ```
16 | * Both "DATA" and "OUT" have to be in the command. The program will replace them when needed. The extension has be changed to mp4, mkv,... determines the extension in the result.
17 |
18 | ### Server
19 |
20 | Server c:\ffmpeg.txt D:\videoFolder D:\outputFolder 8081
21 |
22 | Server ffmpeg_command videoFolder outputFolder tcpPort
23 |
24 |
25 | ### Client
26 |
27 | Client 8081
28 |
29 | Client tcpPort
30 |
31 | ## Limitations
32 |
33 | * Video to pictures is not supported
34 | * The Server has to be started **before** the Clients.
35 | * UDP discovery can be improved
36 |
37 | ## Future
38 |
39 | * detect and handle an ffmpeg crash or y/n statement
40 |
--------------------------------------------------------------------------------