├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ └── dotnet.yml
├── .gitignore
├── Jenkinsfile.majorsilence
├── MediaPlayer.webp
├── MplayerTests.nunit
├── Readme.md
├── Release-Builds
├── build-release.ps1
├── prepare-files-for-release.sh
└── tools
│ └── AssemblyInfoUtil.exe
├── build.sh
├── build_dockerimage.sh
├── deploy.sh
├── gpl-2.0.txt
├── lgpl-2.1.txt
├── majorsilence-media-web.service
├── majorsilence-media-workerservice.service
└── src
├── .dockerignore
├── .idea
├── .gitignore
├── .idea.MPlayerControl
│ └── .idea
│ │ ├── .gitignore
│ │ ├── indexLayout.xml
│ │ ├── projectSettingsUpdater.xml
│ │ └── vcs.xml
├── .idea.MPlayerGtkWidget
│ └── .idea
│ │ └── workspace.xml
├── .idea.Majorsilence.Avalonia.UI
│ └── .idea
│ │ ├── .gitignore
│ │ ├── .name
│ │ ├── avalonia.xml
│ │ ├── encodings.xml
│ │ ├── indexLayout.xml
│ │ └── vcs.xml
├── .idea.Majorsilence.Media.Web
│ └── .idea
│ │ ├── .gitignore
│ │ ├── .name
│ │ ├── encodings.xml
│ │ ├── indexLayout.xml
│ │ └── vcs.xml
└── .idea.Majorsilence.Winforms.MPlayerControl
│ └── .idea
│ ├── .gitignore
│ ├── .name
│ ├── encodings.xml
│ ├── indexLayout.xml
│ └── vcs.xml
├── Directory.Build.props
├── LibMPlayerWinform
├── LibMPlayerWinform.csproj
├── WinFormMPlayerControl.Designer.cs
├── WinFormMPlayerControl.cs
└── WinFormMPlayerControl.resx
├── Majorsilence.Avalonia.UI.sln
├── Majorsilence.Media.Desktop.UI
├── .gitignore
├── App.axaml
├── App.axaml.cs
├── App.config
├── MainWindow.axaml
├── MainWindow.axaml.cs
├── Majorsilence.Media.Desktop.UI.csproj
├── PlayerProperties.axaml
├── PlayerProperties.axaml.cs
├── Program.cs
├── Properties
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── VideoControl.cs
└── app.manifest
├── Majorsilence.Media.Images
├── Filters.cs
├── ImageResize.cs
└── Majorsilence.Media.Images.csproj
├── Majorsilence.Media.NunitTests
├── DiscoverTestCaseSource.cs
├── Discover_Test.cs
├── GlobalVariables.cs
├── ImageResize_Test.cs
├── MPlayer_Test.cs
├── Majorsilence.Media.NunitTests.csproj
├── Mencoder2_Test.cs
├── Properties
│ └── AssemblyInfo.cs
├── SetupInitialize.cs
├── SlideShow_Test.cs
├── TestVideos
│ ├── 1.jpg
│ ├── 2.jpg
│ ├── 3.jpg
│ ├── 4.jpg
│ ├── 5.jpg
│ ├── 6.jpg
│ ├── audio_license.txt
│ ├── doxent_-_Sunset_Boulevard-edit.mp3
│ ├── video1.mp4
│ └── video2.mp4
├── VideoEncoderTestCaseSource.cs
└── VideoEncoder_Test.cs
├── Majorsilence.Media.Videos
├── AspectRatio.cs
├── AudioType.cs
├── BackendPrograms.cs
├── Discover.cs
├── DiscoverFactory.cs
├── Exceptions
│ └── MPlayerControlException.cs
├── Ffmpeg.cs
├── FfmpegDiscover.cs
├── Globals.cs
├── IVideoEncoder.cs
├── Logging.cs
├── MPlayer.cs
├── MPlayerDiscover.cs
├── Majorsilence.Media.Videos.csproj
├── MediaStatus.cs
├── Mencoder.cs
├── MplayerBackends.cs
├── MplayerEvent.cs
├── Mpv.cs
├── MpvDiscover.cs
├── MpvPlayer.cs
├── PlatformCheck.cs
├── Player.cs
├── PlayerFactory.cs
├── RegionType.cs
├── Seek.cs
├── SlideShow.cs
├── TimeConversion.cs
└── VideoType.cs
├── Majorsilence.Media.Web.sln
├── Majorsilence.Media.Web
├── Controllers
│ └── ConvertController.cs
├── Dockerfile
├── JwtSecrets.cs
├── Majorsilence.Media.Web.csproj
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Settings.cs
├── appsettings.Development.json
└── appsettings.json
├── Majorsilence.Media.WorkerService.Tests
├── GlobalUsings.cs
├── Majorsilence.Media.WorkerService.Tests.csproj
└── TranscodingManagerTest.cs
├── Majorsilence.Media.WorkerService
├── Dockerfile
├── Majorsilence.Media.WorkerService.csproj
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Settings.cs
├── StreamTypes.cs
├── TranscodingManager.cs
├── Worker.cs
├── appsettings.Development.json
└── appsettings.json
├── Majorsilence.Winforms.MPlayerControl.sln
├── MediaPlayer
├── MediaPlayer.csproj
├── Player.Designer.cs
├── Player.cs
├── Player.resx
├── PlayerProperties.Designer.cs
├── PlayerProperties.cs
├── PlayerProperties.resx
├── Program.cs
├── Properties
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Resources
│ ├── audio-volume-medium.png
│ ├── audio-volume-muted.png
│ ├── config.png
│ ├── document-open.png
│ ├── fastforward.png
│ ├── pause.png
│ ├── play.png
│ ├── rewind.png
│ ├── stop.png
│ └── volume-down.png
└── app.config
├── SlideShow
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.resx
├── Program.cs
├── Properties
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── SlideShow.csproj
└── app.config
└── Test
├── Form1.Designer.cs
├── Form1.cs
├── Form1.resx
├── Program.cs
├── Properties
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── Test.csproj
└── Test2.cs
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Description
4 |
5 |
6 | ## Motivation and Context
7 |
8 |
9 |
10 | ## How Has This Been Tested?
11 |
12 |
13 |
14 |
15 | ## Screenshots (if appropriate):
16 |
17 | ## Types of changes
18 |
19 | - [ ] Bug fix (non-breaking change which fixes an issue)
20 | - [ ] New feature (non-breaking change which adds functionality)
21 | - [ ] Breaking change (fix or feature that would cause existing functionality to change)
22 |
23 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "nuget" # See documentation for possible values
9 | directory: "/src" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | windows-build:
11 | runs-on: windows-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | - name: Setup .NET
15 | uses: actions/setup-dotnet@v4
16 | with:
17 | dotnet-version: 8.0.x
18 | - name: Build
19 | run: cd src && dotnet build Majorsilence.Winforms.MPlayerControl.sln -c Release
20 |
21 | linux-build:
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/checkout@v4
25 | - name: Setup .NET
26 | uses: actions/setup-dotnet@v4
27 | with:
28 | dotnet-version: 8.0.x
29 | - name: Build Avalonia
30 | run: cd src && dotnet build Majorsilence.Avalonia.UI.sln -c Release
31 | - name: Build Web
32 | run: cd src && dotnet build Majorsilence.Media.Web.sln -c Release
33 | - name: Install mplayer and mencoder and mpv
34 | run: sudo apt-get install -y mplayer mencoder mpv libmpv1 ffmpeg
35 | - name: Test
36 | run: cd src && dotnet test Majorsilence.Media.Web.sln --collect:"XPlat Code Coverage" --logger:"nunit"
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | ### VisualStudio ###
4 | ## Ignore Visual Studio temporary files, build results, and
5 | ## files generated by popular Visual Studio add-ons.
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Roslyn cache directories
26 | *.ide/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | #NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # If using the old MSBuild-Integrated Package Restore, uncomment this:
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | sql/
155 | *.Cache
156 | ClientBin/
157 | [Ss]tyle[Cc]op.*
158 | ~$*
159 | *~
160 | *.dbmdl
161 | *.dbproj.schemaview
162 | *.pfx
163 | *.publishsettings
164 | node_modules/
165 |
166 | # RIA/Silverlight projects
167 | Generated_Code/
168 |
169 | # Backup & report files from converting an old project file
170 | # to a newer Visual Studio version. Backup files are not needed,
171 | # because we have git ;-)
172 | _UpgradeReport_Files/
173 | Backup*/
174 | UpgradeLog*.XML
175 | UpgradeLog*.htm
176 |
177 | # SQL Server files
178 | *.mdf
179 | *.ldf
180 |
181 | # Business Intelligence projects
182 | *.rdl.data
183 | *.bim.layout
184 | *.bim_*.settings
185 |
186 | # Microsoft Fakes
187 | FakesAssemblies/
188 |
189 |
190 | ### XamarinStudio ###
191 | bin/
192 | obj/
193 | *.userprefs
194 |
195 | Release-Builds/build-output
196 | Release-Builds/nuget/MPlayerControl/lib
197 | Release-Builds/nuget/MPlayerControl/content
198 | Release-Builds/nuget/MPlayerControl-Winform/lib
199 | Release-Builds/nuget/MPlayerControl-Gtk/lib
200 | Release-Builds/nunit-result.xml
201 | TestRun
202 | /.vs
203 | /src/.vs
204 | .DS_Store
205 |
--------------------------------------------------------------------------------
/Jenkinsfile.majorsilence:
--------------------------------------------------------------------------------
1 | pipeline {
2 | agent none
3 | environment {
4 | DOTNET_CLI_HOME = '/tmp/DOTNET_CLI_HOME'
5 | DEPLOY_TARGET = credentials('majorsilence_media_host') // it will be something like example1.example.local
6 | }
7 | stages {
8 | stage('build and test') {
9 | agent {
10 | docker {
11 | image 'mcr.microsoft.com/dotnet/sdk:8.0'
12 | // args '-u root:sudo'
13 | }
14 | }
15 | steps {
16 | echo 'building'
17 | sh '''
18 | #apt update && apt install -y mplayer mencoder mpv libmpv1
19 | ./build.sh
20 | '''
21 |
22 | stash includes: 'build/linux-x64/**/*.tar.gz', name: 'linux-x64'
23 | //nunit testResultsPattern: '**/TestResults/*.xml'
24 | //recordCoverage(tools: [[parser: 'COBERTURA', pattern: '**/TestResults/**/*cobertura.xml']])
25 | }
26 | }
27 | // Uncomment to build docker image
28 | //stage('build linux image') {
29 | // agent { label 'linux-x64' }
30 | // steps {
31 | // echo 'building'
32 | // sh '''
33 | // ./build_dockerimage.sh
34 | // '''
35 | // stash includes: "build/docker-images/**/*.tar.gz", name: 'docker-images'
36 | // }
37 | //}
38 |
39 | stage('Publish') {
40 | when {
41 | expression { return env.BRANCH_NAME.startsWith('PR-') == false }
42 | }
43 | steps {
44 | timeout(time:180, unit:'MINUTES') {
45 | input message:'Deploy?'
46 | node('linux-x64') {
47 | echo "Deploying linux-x64 media-web and media-worker systemd service ${env.BRANCH_NAME}...."
48 | unstash 'linux-x64'
49 |
50 | withCredentials([usernamePassword(credentialsId: 'media-web-ssh', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
51 | sh '''
52 | ./deploy.sh remote_systemd_deploy "$USERNAME" "$PASSWORD" "$DEPLOY_TARGET"
53 | '''
54 | }
55 | }
56 | }
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/MediaPlayer.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/MediaPlayer.webp
--------------------------------------------------------------------------------
/MplayerTests.nunit:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Release-Builds/build-release.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 | $ErrorActionPreference = "Stop"
3 | $CURRENTPATH = $pwd.Path
4 |
5 |
6 | function delete_files_and_folders([string]$path) {
7 | If (Test-Path $path) {
8 | Write-Host "Deleting path $path" -ForegroundColor Green
9 | Remove-Item -recurse -force $path
10 | }
11 | }
12 |
13 | delete_files_and_folders "$CURRENTPATH/build-output"
14 |
15 |
16 | # BUILD
17 | cd ../src
18 | dotnet restore Majorsilence.Winforms.MPlayerControl.sln
19 | dotnet build Majorsilence.Winforms.MPlayerControl.sln -p:Configuration="Release"
20 |
21 |
22 | # TESTS
23 | cd "$CURRENTPATH/../src/MplayerUnitTests/bin/Release/net6.0/"
24 |
25 | dotnet vstest "$CURRENTPATH/../src/MplayerUnitTests/bin/Release/net6.0/MplayerUnitTests.dll" --logger:"nunit;LogFileName=$CURRENTPATH/../src/MplayerUnitTests/bin/Release/net6.0/nunit-result.xml"
26 |
27 | cd "$CURRENTPATH"
28 | echo "tests finished"
29 |
30 |
31 | # OLD SCHOOL PACKAGE
32 | $PACKAGEDIR="MPlayerControl-dot-net-6.0"
33 | mkdir -p "./build-output/$PACKAGEDIR"
34 |
35 | Copy-Item ../src/Majorsilence.Media.Images/bin/Release/netstandard2.0/Majorsilence.Media.Images.dll -Destination "./build-output/$PACKAGEDIR/Majorsilence.Media.Images.dll"
36 | Copy-Item ../src/Majorsilence.Media.Videos/bin/Release/netstandard2.0/Majorsilence.Media.Videos.dll -Destination "./build-output/$PACKAGEDIR/Majorsilence.Media.Videos.dll"
37 | Copy-Item ../src/MediaPlayer/bin/Release/net6.0-windows/MediaPlayer.exe -Destination "./build-output/$PACKAGEDIR/MediaPlayer.exe"
38 | Copy-Item ../src/LibMPlayerWinform/bin/Release/net6.0-windows/LibMPlayerWinform.dll -Destination "./build-output/$PACKAGEDIR/LibMPlayerWinform.dll"
39 | Copy-Item ../src/SlideShow/bin/Release/net6.0-windows/SlideShow.exe -Destination "./build-output/$PACKAGEDIR/SlideShow.exe"
40 |
41 |
42 | cd build-output
43 | 7za a -t7z "$PACKAGEDIR.7z" -r $PACKAGEDIR -bd
44 | cd ..
45 |
46 | # NUGET
47 |
48 | cd "$CURRENTPATH/../src"
49 | Get-ChildItem -Recurse *.nupkg | Copy-Item -Destination "$CURRENTPATH\build-output"
50 |
51 | cd "$CURRENTPATH"
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Release-Builds/prepare-files-for-release.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e # exit on first error
3 | set -u # exit on using unset variable
4 |
5 | CURRENTPATH=`pwd`
6 |
7 |
8 | getos()
9 | {
10 | if [ "$(expr $(uname -s))" = "windows32" ]; then
11 | echo "windows"
12 | elif [ "$(expr substr $(uname -s) 1 5)" = "MINGW" ]; then
13 | echo "windows"
14 | else
15 | echo "linux"
16 | fi
17 | }
18 |
19 | read osversion junk <<< $(getos; echo $?)
20 | if [ "$osversion" = 'windows' ];
21 | then
22 | # Increment minor number by 1
23 | # See http://www.codeproject.com/Articles/31236/How-To-Update-Assembly-Version-Number-Automaticall
24 | ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../LibImages/Properties/AssemblyInfo.cs"
25 | ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../LibMPlayerCommon/Properties/AssemblyInfo.cs"
26 | ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../MediaPlayer/Properties/AssemblyInfo.cs"
27 | ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../LibMPlayerWinform/Properties/AssemblyInfo.cs"
28 | ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../MPlayerGtkWidget/AssemblyInfo.cs"
29 | ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../SlideShow/Properties/AssemblyInfo.cs"
30 | ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../WpfMPlayer/Properties/AssemblyInfo.cs"
31 | else
32 | mono ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../LibImages/Properties/AssemblyInfo.cs"
33 | mono ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../LibMPlayerCommon/Properties/AssemblyInfo.cs"
34 | mono ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../MediaPlayer/Properties/AssemblyInfo.cs"
35 | mono ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../LibMPlayerWinform/Properties/AssemblyInfo.cs"
36 | mono ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../MPlayerGtkWidget/AssemblyInfo.cs"
37 | mono ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../SlideShow/Properties/AssemblyInfo.cs"
38 | mono ./tools/AssemblyInfoUtil.exe -inc:2 "$CURRENTPATH/../WpfMPlayer/Properties/AssemblyInfo.cs"
39 | fi
40 |
41 | VERSION_FULL_LINE=$(grep -F "AssemblyVersion" "$CURRENTPATH/../LibMPlayerCommon/Properties/AssemblyInfo.cs")
42 | VERSION_WITH_ASTERIK=$(echo $VERSION_FULL_LINE | awk -F\" '{print $(NF-1)}')
43 | VERSION="${VERSION_WITH_ASTERIK%??}"
44 |
45 |
46 | cd ..
47 | cd Release-Builds
48 |
49 | # Update NUGET spec files
50 | sed -i "5s/.*/ $VERSION<\/version>/" "$CURRENTPATH/nuget/MPlayerControl/MPlayerControl.nuspec"
51 | sed -i "5s/.*/ $VERSION<\/version>/" "$CURRENTPATH/nuget/MPlayerControl-Winform/MPlayerControl-Winform.nuspec"
52 | sed -i "21s/.*/ /" "$CURRENTPATH/nuget/MPlayerControl-Winform/MPlayerControl-Winform.nuspec"
53 | sed -i "5s/.*/ $VERSION<\/version>/" "$CURRENTPATH/nuget/MPlayerControl-Gtk/MPlayerControl-Gtk.nuspec"
54 | sed -i "21s/.*/ /" "$CURRENTPATH/nuget/MPlayerControl-Gtk/MPlayerControl-Gtk.nuspec"
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Release-Builds/tools/AssemblyInfoUtil.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/Release-Builds/tools/AssemblyInfoUtil.exe
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e # exit on first error
3 | set -u # exit on using unset variable
4 |
5 | #export LC_ALL=en_US.UTF-8
6 | CURRENTPATH=`pwd`
7 | VERSION=`cat src/Majorsilence.Media.Web/Majorsilence.Media.Web.csproj | grep "" | sed 's/[^0-9.]*//g'`
8 |
9 | clean_build(){
10 | rm -rf ./build
11 |
12 | # Delete "bin" and "obj" folders
13 | rm -rf `find -type d -name bin`
14 | rm -rf `find -type d -name obj`
15 | rm -rf `find -type d -name TestResults`
16 | }
17 |
18 |
19 | remove_bom_from_file_encoding()
20 | {
21 | # hack to remove character encoding BOM if it exists
22 | STARTING_PATH=$1
23 | NAME_WILDCARD=$2
24 | # Find the first file matching the pattern
25 | file=$(find $STARTING_PATH -name "*cobertura.xml" | head -n 1)
26 |
27 | # Check if a file was found
28 | if [ -n "$file" ]; then
29 | # Remove the BOM and overwrite the original file
30 | /usr/bin/sed -i '1s/^\xEF\xBB\xBF//' "$file"
31 | echo "BOM removed from $file"
32 | else
33 | echo "No file matching the pattern was found."
34 | fi
35 | }
36 |
37 | systemd_package_build()
38 | {
39 | mkdir -p build/linux-x64
40 | dotnet restore src/Majorsilence.Media.Web.sln
41 | dotnet build -c Release src/Majorsilence.Media.Web.sln
42 | dotnet build "src/Majorsilence.Media.Web" -c Release -r linux-x64
43 | dotnet publish "src/Majorsilence.Media.Web" -c Release -r linux-x64 --self-contained true -o build/linux-x64/media-web-linux-x64-$VERSION
44 | #dotnet test src/Majorsilence.Media.Web.sln --collect:"XPlat Code Coverage" --logger:"nunit"
45 | #remove_bom_from_file_encoding "./src/Majorsilence.Media.Web/TestResults" "*cobertura.xml"
46 | dotnet build "src/Majorsilence.Media.WorkerService" -c Release -r linux-x64
47 | dotnet publish "src/Majorsilence.Media.WorkerService" -c Release -r linux-x64 --self-contained true -o build/linux-x64/media-workerservice-linux-x64-$VERSION
48 |
49 | cd build/linux-x64
50 | tar -czvf media-web-linux-x64-$VERSION.tar.gz media-web-linux-x64-$VERSION
51 | tar -czvf media-workerservice-linux-x64-$VERSION.tar.gz media-workerservice-linux-x64-$VERSION
52 | cd $CURRENTPATH
53 | }
54 |
55 | clean_build
56 | systemd_package_build
57 |
--------------------------------------------------------------------------------
/build_dockerimage.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e # exit on first error
3 | set -u # exit on using unset variable
4 |
5 | CURRENTPATH=`pwd`
6 | VERSION=`cat src/Majorsilence.Media.Web/Majorsilence.Media.Web.csproj | grep "" | sed 's/[^0-9.]*//g'`
7 |
8 | clean_build(){
9 | rm -rf ./build/docker-images
10 |
11 | # Delete "bin" and "obj" folders
12 | rm -rf `find -type d -name bin`
13 | rm -rf `find -type d -name obj`
14 | }
15 |
16 | docker_build()
17 | {
18 | mkdir -p build/docker-images
19 | GITHASH="$(git rev-parse --short HEAD)"
20 | docker build -f ./src/Majorsilence.Media.Web/Majorsilence.Media.Web/Dockerfile -t majorsilence/media_web$GITHASH --rm=true .
21 | docker save majorsilence/media_web$GITHASH | gzip > ./build/docker-images/media_web.tar.gz
22 | docker rmi majorsilence/media_web$GITHASH
23 |
24 | docker build -f ./src/Majorsilence.Media.Web/Majorsilence.Media.Web/Dockerfile -t majorsilence/media_workerservice$GITHASH --rm=true .
25 | docker save majorsilence/media_workerservice$GITHASH | gzip > ./build/docker-images/media_workerservice.tar.gz
26 | docker rmi majorsilence/media_workerservice$GITHASH
27 | }
28 |
29 | clean_build
30 | docker_build
31 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e # exit on first error
3 | set -u # exit on using unset variable
4 |
5 | CURRENTPATH=$(pwd)
6 | VERSION=$(cat src/Majorsilence.Media.Web/Majorsilence.Media.Web.csproj | grep "" | sed 's/[^0-9.]*//g')
7 |
8 | echo "Deploying version $VERSION"
9 |
10 | USER=$2
11 | PASSWORD=$3
12 | SERVER=$4
13 |
14 | publish_server() {
15 | echo "deploy docker media_web"
16 | scp "$CURRENTPATH/build/media_web.tar.gz" $USER@$SERVER:/root
17 |
18 | ssh $USER@$SERVER '/snap/bin/docker stop media_web || true && /snap/bin/docker rm media_web || true \
19 | && zcat /root/media_web.tar.gz | /snap/bin/docker load \
20 | && /snap/bin/docker run -d -p 32001:8080 -v /root:/mediadata --restart always --name media_web majorsilence/media_web'
21 |
22 | echo "deploy docker media_workerservice"
23 | scp "$CURRENTPATH/build/media_workerservice.tar.gz" $USER@$SERVER:/root
24 |
25 | ssh $USER@$SERVER '/snap/bin/docker stop media_workerservice || true && /snap/bin/docker rm media_workerservice || true \
26 | && zcat /root/media_workerservice.tar.gz | /snap/bin/docker load \
27 | && /snap/bin/docker run -d -v /root:/mediadata --restart always --name media_workerservice majorsilence/media_workerservice'
28 | }
29 |
30 | remote_systemd_deploy() {
31 | echo "deploy systemd media-web"
32 | sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -l $USER $SERVER "cd /home/$USER && rm -rf ./media-web-*"
33 |
34 | sshpass -p "$PASSWORD" scp "$CURRENTPATH/build/linux-x64/media-web-linux-x64-$VERSION.tar.gz" $USER@$SERVER:/home/$USER
35 |
36 | sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -l $USER $SERVER "cd /home/$USER \
37 | && tar xvf media-web-linux-x64-$VERSION.tar.gz \
38 | && echo $PASSWORD | sudo -S rm -rf /opt/majorsilence/media-web/app \
39 | && echo $PASSWORD | sudo -S mkdir -p /opt/majorsilence/media-web/app \
40 | && echo $PASSWORD | sudo -S mkdir -p /opt/majorsilence/media-web/data/uploads \
41 | && echo $PASSWORD | sudo -S cp --recursive /home/$USER/media-web-linux-x64-$VERSION/* /opt/majorsilence/media-web/app \
42 | && rm -rf /home/$USER/media-web-* \
43 | && echo $PASSWORD | sudo -S chown media-web:media-web -R /opt/majorsilence/media-web \
44 | && echo $PASSWORD | sudo -S chmod +x /opt/majorsilence/media-web/app \
45 | && echo $PASSWORD | sudo -S systemctl restart majorsilence-media-web"
46 |
47 | echo "deploy systemd media-workerservice"
48 | sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -l $USER $SERVER "cd /home/$USER && rm -rf ./media-workerservice-*"
49 |
50 | sshpass -p "$PASSWORD" scp "$CURRENTPATH/build/linux-x64/media-workerservice-linux-x64-$VERSION.tar.gz" $USER@$SERVER:/home/$USER
51 |
52 | sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -l $USER $SERVER "cd /home/$USER \
53 | && tar xvf media-workerservice-linux-x64-$VERSION.tar.gz \
54 | && echo $PASSWORD | sudo -S rm -rf /opt/majorsilence/media-workerservice/app \
55 | && echo $PASSWORD | sudo -S mkdir -p /opt/majorsilence/media-workerservice/app \
56 | && echo $PASSWORD | sudo -S mkdir -p /opt/majorsilence/media-workerservice/data/converted \
57 | && echo $PASSWORD | sudo -S cp --recursive /home/$USER/media-workerservice-linux-x64-$VERSION/* /opt/majorsilence/media-workerservice/app \
58 | && rm -rf /home/$USER/media-workerservice-* \
59 | && echo $PASSWORD | sudo -S chown media-workerservice:media-workerservice -R /opt/majorsilence/media-workerservice \
60 | && echo $PASSWORD | sudo -S chmod +x /opt/majorsilence/media-workerservice/app \
61 | && echo $PASSWORD | sudo -S systemctl restart majorsilence-media-workerservice"
62 | }
63 |
64 | if [ "$1" = "remote_docker_deploy" ]; then
65 | publish_server
66 | elif [ "$1" = "remote_systemd_deploy" ]; then
67 | remote_systemd_deploy
68 | elif [ "$1" = "local_systemd_deploy" ]; then
69 | local_systemd_deploy
70 | else
71 | echo "Only \"local_docker_install\", \"remote_docker_deploy\", \"remote_systemd_deploy\", or \"local_systemd_deploy\" supported."
72 | fi
73 |
--------------------------------------------------------------------------------
/majorsilence-media-web.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Majorsilence Media Web API
3 | Wants=network-online.target
4 | After=network-online.target
5 |
6 | # How to install:
7 | # Copy /etc/systemd/system/majorsilence-media-web.service
8 | # systemctl daemon-reload
9 | # systemctl enable majorsilence-media-web.service
10 | # systemctl start majorsilence-media-web.service
11 | # Certificates
12 | # Production: use letsencrypt
13 | # Dev: self signed certs, change localhost to the host address
14 | # openssl req -x509 -newkey rsa:4096 -keyout /opt/majorsilence/media-web/certs/selfsigned.key -out /opt/majorsilence/media-web/certs/selfsigned.crt -days 365 -nodes -subj '/CN=localhost'
15 | # sudo -S chown media-web:media-web -R /opt/majorsilence/media-web
16 |
17 | [Service]
18 | # In production use a dedicated user/group.
19 | # sudo useradd -m media-web
20 | # To update permissions, use 'chown media-web:media-web -R /opt/majorsilence/media-web' to take ownership of the folder and files,
21 | # Use 'chmod +x /opt/majorsilence/media-web/app' to allow execution of the executable file.
22 | User=media-web
23 |
24 | ExecStart=/opt/majorsilence/media-web/app/Majorsilence.Media.Web
25 | Restart=always
26 | RestartSec=10 # Restart service after 10 seconds if node service crashes
27 | StandardOutput=syslog # Output to syslog" >> /etc/systemd/system/majorsilence-media-web.service
28 | StandardError=syslog # Output to syslog" >> /etc/systemd/system/majorsilence-media-web.service
29 | SyslogIdentifier=majorsilence-media-web
30 | WorkingDirectory=/opt/majorsilence/media-web/app
31 |
32 | # https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-8.0&tabs=linux-ubuntu
33 | KillSignal=SIGINT
34 | Environment=ASPNETCORE_ENVIRONMENT=Production
35 | Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
36 | Environment=ASPNETCORE_URLS="http://+:8082"
37 | # if using certs comment out above line and uncomment the line below
38 | #Environment=ASPNETCORE_URLS="https://+:8083;http://+:8082"
39 | # if using a pfx uncomment the following two lines
40 | #Environment=ASPNETCORE_Kestrel__Certificates__Default__Password="testing_cert_password"
41 | #Environment=ASPNETCORE_Kestrel__Certificates__Default__Path="/opt/majorsilence/media-web/certs/majorsilence-media-web-certs.pfx"
42 | # if using crt and key uncomment following two lines
43 | #Environment=ASPNETCORE_Kestrel__Certificates__Default__Path="/opt/majorsilence/media-web/certs/selfsigned.crt"
44 | #Environment=ASPNETCORE_Kestrel__Certificates__Default__KeyPath="/opt/majorsilence/media-web/certs/selfsigned.key"
45 | Environment=ApiSettings__UploadFolder=/opt/majorsilence/media-web/data/uploads
46 | Environment=ApiSettings__PermittedCORS__0="https://*.majorsilence.com"
47 | Environment=ApiSettings__Jwt__Secret="PLACEHOLDER"
48 | Environment=ApiSettings__Jwt__Issuer="https://PLACEHOLDER"
49 | Environment=ApiSettings__Jwt__Audience="https://PLACEHOLDER"
50 |
51 | # https://www.freedesktop.org/software/systemd/man/systemd.exec.html
52 | NoNewPrivileges=yes
53 | PrivateTmp=yes
54 | ProtectSystem=full
55 | ProtectHome=yes
56 |
57 | [Install]
58 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/majorsilence-media-workerservice.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Majorsilence Media WorkerService API
3 | Wants=network-online.target
4 | After=network-online.target
5 |
6 | # How to install:
7 | # Copy /etc/systemd/system/majorsilence-media-workerservice.service
8 | # systemctl daemon-reload
9 | # systemctl enable majorsilence-media-workerservice.service
10 | # systemctl start majorsilence-media-workerservice.service
11 |
12 |
13 | [Service]
14 | # In production use a dedicated user/group.
15 | # sudo useradd -m media-workerservice
16 | # To update permissions, use 'chown media-workerservice:media-workerservice -R /opt/majorsilence/media-workerservice' to take ownership of the folder and files,
17 | # Use 'chmod +x /opt/majorsilence/media-workerservice/app' to allow execution of the executable file.
18 | User=media-workerservice
19 |
20 | ExecStart=/opt/majorsilence/media-workerservice/app/Majorsilence.Media.WorkerService
21 | Restart=always
22 | RestartSec=10 # Restart service after 10 seconds if node service crashes
23 | StandardOutput=syslog # Output to syslog" >> /etc/systemd/system/majorsilence-media-workerservice.service
24 | StandardError=syslog # Output to syslog" >> /etc/systemd/system/majorsilence-media-workerservice.service
25 | SyslogIdentifier=majorsilence-media-workerservice
26 | WorkingDirectory=/opt/majorsilence/media-workerservice/app
27 |
28 | # https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-8.0&tabs=linux-ubuntu
29 | KillSignal=SIGINT
30 | Environment=ASPNETCORE_ENVIRONMENT=Production
31 | Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
32 | # UploadFolder should match the upload folder of Majorsilence.Media.Web
33 | # UploadFolder, give media-workerservice access in addition to media-web
34 | # sudo setfacl -R -m u:media-workerservice:rwx /opt/majorsilence/media-web/data/uploads
35 | # sudo setfacl -R -m d:u:media-workerservice:rwx /opt/majorsilence/media-web/data/uploads
36 | Environment=ApiSettings__UploadFolder=/opt/majorsilence/media-web/data/uploads
37 | Environment=ApiSettings__ConvertedFolder=/opt/majorsilence/media-workerservice/data/converted
38 | Environment=ApiSettings__FfmpegPath=/usr/bin/ffmpeg
39 | # Valid ConversionTypes are "streaming", "download", or "all"
40 | Environment=ApiSettings__ConversionType=streaming
41 | Environment=ApiSettings__StreamingTypes__MpegDash=
42 | Environment=ApiSettings__StreamingTypes__Hls=-i [PLACEHOLDER_INPUT] -map 0:v -map 0:a -s:v:0 426x240 -c:v:0 libx264 -b:v:0 250k -s:v:1 640x360 -c:v:1 libx264 -b:v:1 800k -s:v:2 854x480 -c:v:2 libx264 -b:v:2 1400k -s:v:3 1280x720 -c:v:3 libx264 -b:v:3 2800k -s:v:4 1920x1080 -c:v:4 libx264 -b:v:4 5000k -c:a aac -b:a 128k -hls_time 4 -hls_playlist_type vod -hls_segment_filename [PLACEHOLDER_OUTPUT]_%03d.ts [PLACEHOLDER_OUTPUT].m3u8
43 |
44 | # https://www.freedesktop.org/software/systemd/man/systemd.exec.html
45 | NoNewPrivileges=yes
46 | PrivateTmp=yes
47 | ProtectSystem=full
48 | ProtectHome=yes
49 |
50 | [Install]
51 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/src/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.classpath
2 | **/.dockerignore
3 | **/.env
4 | **/.git
5 | **/.gitignore
6 | **/.project
7 | **/.settings
8 | **/.toolstarget
9 | **/.vs
10 | **/.vscode
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/bin
16 | **/charts
17 | **/docker-compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | LICENSE
25 | README.md
--------------------------------------------------------------------------------
/src/.idea/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/.idea/.gitignore
--------------------------------------------------------------------------------
/src/.idea/.idea.MPlayerControl/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /workspace.xml
--------------------------------------------------------------------------------
/src/.idea/.idea.MPlayerControl/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/.idea/.idea.MPlayerControl/.idea/projectSettingsUpdater.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/.idea/.idea.MPlayerControl/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Avalonia.UI/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /projectSettingsUpdater.xml
6 | /modules.xml
7 | /.idea.MPlayerGtkWidget.iml
8 | /contentModel.xml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Avalonia.UI/.idea/.name:
--------------------------------------------------------------------------------
1 | Majorsilence.Avalonia.UI
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Avalonia.UI/.idea/avalonia.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Avalonia.UI/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Avalonia.UI/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Avalonia.UI/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Media.Web/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /projectSettingsUpdater.xml
6 | /contentModel.xml
7 | /.idea.Majorsilence.Media.Web.iml
8 | /modules.xml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 | # GitHub Copilot persisted chat sessions
15 | /copilot/chatSessions
16 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Media.Web/.idea/.name:
--------------------------------------------------------------------------------
1 | Majorsilence.Media.Web
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Media.Web/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Media.Web/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Media.Web/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Winforms.MPlayerControl/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /contentModel.xml
6 | /.idea.Majorsilence.Winforms.MPlayerControl.iml
7 | /projectSettingsUpdater.xml
8 | /modules.xml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 | # GitHub Copilot persisted chat sessions
15 | /copilot/chatSessions
16 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Winforms.MPlayerControl/.idea/.name:
--------------------------------------------------------------------------------
1 | Majorsilence.Winforms.MPlayerControl
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Winforms.MPlayerControl/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Winforms.MPlayerControl/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/.idea/.idea.Majorsilence.Winforms.MPlayerControl/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | true
5 | https://github.com/majorsilence/MPlayerControl
6 | 1.9.0
7 | 1.9.0
8 | 1.9.0
9 | true
10 | Majorsilence Media
11 | Copyright © 2025 majorsilence (Peter Gill) and other contributors
12 | latest
13 | Media player control and server for dotnet. Winforms, avalonia desktop controls for playback via mplayer or mpv.
14 | Server side process video files using ffmpeg.
15 |
16 |
--------------------------------------------------------------------------------
/src/LibMPlayerWinform/LibMPlayerWinform.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0-windows;net8.0-windows;net9.0-windows
4 | enable
5 | true
6 | enable
7 | LibMPlayerWinform
8 | LibMPlayerWinform
9 | True
10 |
11 |
12 | full
13 | bin\$(Configuration)\
14 | 1591
15 | bin\$(Configuration)\LibMPlayerWinform.xml
16 |
17 |
18 | bin\$(Configuration)\
19 | 1591
20 | bin\$(Configuration)\LibMPlayerWinform.xml
21 |
22 |
23 |
24 |
25 | WinFormMPlayerControl.cs
26 |
27 |
28 |
29 |
30 | WinFormMPlayerControl.cs
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/LibMPlayerWinform/WinFormMPlayerControl.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace LibMPlayerWinform
2 | {
3 | partial class WinFormMPlayerControl
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Component Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.panelVideo = new System.Windows.Forms.Panel();
32 | this.buttonPlay = new System.Windows.Forms.Button();
33 | this.buttonStop = new System.Windows.Forms.Button();
34 | this.SuspendLayout();
35 | //
36 | // panelVideo
37 | //
38 | this.panelVideo.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
39 | | System.Windows.Forms.AnchorStyles.Left)
40 | | System.Windows.Forms.AnchorStyles.Right)));
41 | this.panelVideo.Location = new System.Drawing.Point(0, 0);
42 | this.panelVideo.Name = "panelVideo";
43 | this.panelVideo.Size = new System.Drawing.Size(537, 222);
44 | this.panelVideo.TabIndex = 0;
45 | //
46 | // buttonPlay
47 | //
48 | this.buttonPlay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
49 | this.buttonPlay.Location = new System.Drawing.Point(462, 228);
50 | this.buttonPlay.Name = "buttonPlay";
51 | this.buttonPlay.Size = new System.Drawing.Size(75, 23);
52 | this.buttonPlay.TabIndex = 1;
53 | this.buttonPlay.Text = "Play";
54 | this.buttonPlay.UseVisualStyleBackColor = true;
55 | this.buttonPlay.Click += new System.EventHandler(this.buttonPlay_Click);
56 | //
57 | // buttonStop
58 | //
59 | this.buttonStop.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
60 | this.buttonStop.Location = new System.Drawing.Point(367, 228);
61 | this.buttonStop.Name = "buttonStop";
62 | this.buttonStop.Size = new System.Drawing.Size(75, 23);
63 | this.buttonStop.TabIndex = 2;
64 | this.buttonStop.Text = "Stop";
65 | this.buttonStop.UseVisualStyleBackColor = true;
66 | this.buttonStop.Click += new System.EventHandler(this.buttonStop_Click);
67 | //
68 | // WinFormMPlayerControl
69 | //
70 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
71 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
72 | this.Controls.Add(this.buttonStop);
73 | this.Controls.Add(this.buttonPlay);
74 | this.Controls.Add(this.panelVideo);
75 | this.Name = "WinFormMPlayerControl";
76 | this.Size = new System.Drawing.Size(540, 255);
77 | this.SizeChanged += new System.EventHandler(this.WinFormMPlayerControl_SizeChanged);
78 | this.ResumeLayout(false);
79 |
80 | }
81 |
82 | #endregion
83 |
84 | private System.Windows.Forms.Panel panelVideo;
85 | private System.Windows.Forms.Button buttonPlay;
86 | private System.Windows.Forms.Button buttonStop;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/LibMPlayerWinform/WinFormMPlayerControl.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Drawing;
5 | using System.Data;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Windows.Forms;
10 | using Majorsilence.Media.Videos;
11 |
12 | namespace LibMPlayerWinform
13 | {
14 | public partial class WinFormMPlayerControl : UserControl
15 | {
16 | Player _play;
17 |
18 | public WinFormMPlayerControl()
19 | {
20 | InitializeComponent();
21 | }
22 |
23 | public WinFormMPlayerControl(Player play)
24 | {
25 | InitializeComponent();
26 |
27 | _play = play;
28 | }
29 |
30 | public void SetPlayer(Player play)
31 | {
32 | _play = play;
33 | }
34 |
35 | public long Handle
36 | {
37 | get
38 | {
39 | return this.panelVideo.Handle.ToInt64();
40 | }
41 | }
42 |
43 | private void buttonStop_Click(object sender, EventArgs e)
44 | {
45 | if (_play != null)
46 | {
47 | _play.Stop();
48 | }
49 | }
50 |
51 | private void buttonPlay_Click(object sender, EventArgs e)
52 | {
53 | if (_play != null)
54 | {
55 | _play.Stop();
56 | }
57 |
58 | if (_play == null)
59 | {
60 | throw new InvalidDataException("The player is not set. You must set it with the constructor or through the SetPlayer method.");
61 | }
62 | else if (System.IO.File.Exists(MPlayerPath) == false && _play is Majorsilence.Media.Videos.MPlayer)
63 | {
64 | throw new System.IO.FileNotFoundException("File not found", MPlayerPath);
65 | }
66 | else if (System.IO.File.Exists(MPlayerPath) == false && _play is Majorsilence.Media.Videos.MpvPlayer)
67 | {
68 | throw new System.IO.FileNotFoundException("File not found", MPlayerPath);
69 | }
70 |
71 |
72 | if (System.IO.File.Exists(VideoPath) == false && VideoPath.StartsWith("http") == false)
73 | {
74 | throw new System.IO.FileNotFoundException("File not found", VideoPath);
75 | }
76 |
77 | _play.Play(VideoPath);
78 | }
79 |
80 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
81 | public string MPlayerPath { get; set; }
82 |
83 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
84 | public string VideoPath { get; set; }
85 |
86 | private void WinFormMPlayerControl_SizeChanged(object sender, EventArgs e)
87 | {
88 |
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/Majorsilence.Avalonia.UI.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32630.192
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Images", "Majorsilence.Media.Images\Majorsilence.Media.Images.csproj", "{C859FA27-7882-4814-9202-9C9D807C2CE5}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Videos", "Majorsilence.Media.Videos\Majorsilence.Media.Videos.csproj", "{5D3616D0-160D-4601-AB67-E1ED9111C676}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Desktop.UI", "Majorsilence.Media.Desktop.UI\Majorsilence.Media.Desktop.UI.csproj", "{39B2C523-7644-491A-9D46-4D4C948150B4}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.NunitTests", "Majorsilence.Media.NunitTests\Majorsilence.Media.NunitTests.csproj", "{5E050A99-68E9-4F34-82BD-4E04EAF64CA7}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {39B2C523-7644-491A-9D46-4D4C948150B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {39B2C523-7644-491A-9D46-4D4C948150B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {39B2C523-7644-491A-9D46-4D4C948150B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {39B2C523-7644-491A-9D46-4D4C948150B4}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {5E050A99-68E9-4F34-82BD-4E04EAF64CA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {5E050A99-68E9-4F34-82BD-4E04EAF64CA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {5E050A99-68E9-4F34-82BD-4E04EAF64CA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {5E050A99-68E9-4F34-82BD-4E04EAF64CA7}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {5238B2E8-5295-47DF-B781-F6760E906214}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/App.axaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls.ApplicationLifetimes;
3 | using Avalonia.Markup.Xaml;
4 |
5 | namespace Majorsilence.Media.Desktop.UI
6 | {
7 | public partial class App : Application
8 | {
9 | public override void Initialize()
10 | {
11 | AvaloniaXamlLoader.Load(this);
12 | }
13 |
14 | public override void OnFrameworkInitializationCompleted()
15 | {
16 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
17 | {
18 | desktop.MainWindow = new MainWindow();
19 | }
20 |
21 | base.OnFrameworkInitializationCompleted();
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/MainWindow.axaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using Avalonia.Controls;
4 | using Avalonia.Interactivity;
5 | using Majorsilence.Media.Videos;
6 |
7 | namespace Majorsilence.Media.Desktop.UI
8 | {
9 | public partial class MainWindow : Window
10 | {
11 | Player _play;
12 |
13 | public MainWindow()
14 | {
15 | InitializeComponent();
16 | this.Opened += MainWindow_Opened;
17 | }
18 |
19 | private async void MainWindow_Opened(object sender, EventArgs e)
20 | {
21 | var b = new BackendPrograms();
22 | if (System.IO.File.Exists(Properties.Settings.Default.MPlayerPath) == false
23 | && System.IO.File.Exists(b.MPlayer) == false)
24 | {
25 | var dlg = new PlayerProperties();
26 | await dlg.ShowDialog(this);
27 | }
28 |
29 | this._play = PlayerFactory.Get(videoWidget.Handle.ToInt64(), Properties.Settings.Default.MPlayerPath);
30 | this._play.VideoExited += new MplayerEventHandler(play_VideoExited);
31 | }
32 |
33 | public async void buttonPlay_Click(object sender, RoutedEventArgs e)
34 | {
35 | if (this._play.CurrentStatus != MediaStatus.Stopped)
36 | {
37 | this._play.Stop();
38 | }
39 |
40 | var openFileDialog = new OpenFileDialog
41 | {
42 | AllowMultiple = false
43 | };
44 |
45 | var result = await openFileDialog.ShowAsync(this);
46 | if (result == null || result.Length == 0)
47 | {
48 | return;
49 | }
50 |
51 | string filePath = result[0].ToString();
52 | if (string.IsNullOrWhiteSpace(filePath))
53 | {
54 | return;
55 | }
56 |
57 | this._play.Play(filePath);
58 | }
59 |
60 | private void play_VideoExited(object sender, MplayerEvent e)
61 | {
62 | this._play.Stop();
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/Majorsilence.Media.Desktop.UI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 | net6.0;net8.0;net9.0
5 | enable
6 |
7 | copyused
8 | true
9 | app.manifest
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | True
35 | True
36 | Settings.settings
37 |
38 |
39 |
40 |
41 | SettingsSingleFileGenerator
42 | Settings.Designer.cs
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/PlayerProperties.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/PlayerProperties.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Interactivity;
4 | using Avalonia.Markup.Xaml;
5 |
6 | namespace Majorsilence.Media.Desktop.UI;
7 |
8 | public partial class PlayerProperties : Window
9 | {
10 | public PlayerProperties()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | private async void OnBrowseButtonClick(object? sender, RoutedEventArgs e)
16 | {
17 | var openFileDialog = new OpenFileDialog
18 | {
19 | AllowMultiple = false
20 | };
21 |
22 | var result = await openFileDialog.ShowAsync(this);
23 | if (result != null && result.Length > 0)
24 | {
25 | PlayerPathTextBox.Text = result[0];
26 | }
27 | }
28 |
29 | private void OnSaveButtonClick(object? sender, RoutedEventArgs e)
30 | {
31 | Properties.Settings.Default.MPlayerPath = PlayerPathTextBox.Text.Trim();
32 | Properties.Settings.Default.Save();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/Program.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using System;
3 |
4 | namespace Majorsilence.Media.Desktop.UI
5 | {
6 | class Program
7 | {
8 | // Initialization code. Don't use any Avalonia, third-party APIs or any
9 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
10 | // yet and stuff might break.
11 | [STAThread]
12 | public static void Main(string[] args)
13 | {
14 | string path = "";
15 | for (int i = 0; i <= args.Length - 1; i++)
16 | {
17 | if (args[i] == "-path")
18 | {
19 | path = Environment.GetCommandLineArgs()[i + 1].Trim();
20 | }
21 | }
22 |
23 | if (!string.IsNullOrWhiteSpace(path))
24 | {
25 | Properties.Settings.Default.MPlayerPath = path;
26 | Properties.Settings.Default.Save();
27 | }
28 |
29 | BuildAvaloniaApp()
30 | .StartWithClassicDesktopLifetime(args);
31 | }
32 |
33 | // Avalonia configuration, don't remove; also used by visual designer.
34 | public static AppBuilder BuildAvaloniaApp()
35 | => AppBuilder.Configure()
36 | .UsePlatformDetect()
37 | .LogToTrace();
38 | }
39 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Majorsilence.Media.Desktop.UI.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.12.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.UserScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("")]
29 | public string MPlayerPath {
30 | get {
31 | return ((string)(this["MPlayerPath"]));
32 | }
33 | set {
34 | this["MPlayerPath"] = value;
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/VideoControl.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia.Controls;
3 | using Avalonia.Platform;
4 |
5 | namespace Majorsilence.Media.Desktop.UI;
6 |
7 | public class VideoControl : NativeControlHost
8 | {
9 | public IntPtr Handle { get; private set; }
10 |
11 | protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
12 | {
13 | var handle = base.CreateNativeControlCore(parent);
14 | Handle = handle.Handle;
15 | return handle;
16 | }
17 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Desktop.UI/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
62 |
63 |
64 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Images/ImageResize.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2011 (C) Peter Gill
4 |
5 | This file is part of LibImages.
6 |
7 | LibImages is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | LibImages is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with LibImages. If not, see .
19 |
20 | */
21 |
22 | using SixLabors.ImageSharp;
23 | using SixLabors.ImageSharp.Processing;
24 |
25 | namespace Majorsilence.Media.Images;
26 |
27 | public class ImageResize
28 | {
29 | ///
30 | /// Resize image and keep proportions
31 | ///
32 | /// string - path to file
33 | /// int
34 | /// int
35 | /// Image
36 | public static Image Resize(string file, int width, int height)
37 | {
38 | var image = Image.Load(file);
39 |
40 | image.Mutate(x => x
41 | .Resize(width, height));
42 | return image;
43 | }
44 |
45 | ///
46 | /// Resize image and keep proportions
47 | ///
48 | /// Image
49 | /// int
50 | /// int
51 | /// Image
52 | public static Image Resize(Image imgToResize, int width, int height)
53 | {
54 | imgToResize.Mutate(x => x
55 | .Resize(new ResizeOptions
56 | {
57 | Size = new Size(width, height),
58 | Mode = ResizeMode.Stretch
59 | }));
60 | return imgToResize;
61 | }
62 |
63 |
64 | public static Image ResizeBlackBar(string file, int width, int height)
65 | {
66 | var image = Image.Load(file);
67 | return ResizeBlackBar(image, width, height);
68 | }
69 |
70 | ///
71 | /// Resize image and keep proportions
72 | ///
73 | /// Image
74 | /// int
75 | /// int
76 | /// Image
77 | public static Image ResizeBlackBar(Image imgToResize, int width, int height)
78 | {
79 | if (imgToResize == null) return null;
80 |
81 | imgToResize.Mutate(x => x
82 | .Resize(new ResizeOptions
83 | {
84 | Size = new Size(width, height),
85 | Mode = ResizeMode.Pad
86 | }));
87 | return imgToResize;
88 | }
89 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Images/Majorsilence.Media.Images.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0;net8.0;net9.0
4 | Majorsilence.Media.Images
5 | Majorsilence.Media.Images
6 | true
7 | True
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/DiscoverTestCaseSource.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using Majorsilence.Media.Videos;
3 | using NUnit.Framework;
4 |
5 | namespace MplayerUnitTests;
6 |
7 | public static class DiscoverTestCaseSource
8 | {
9 | public static IEnumerable TestCasesVideo1
10 | {
11 | get
12 | {
13 | yield return new TestCaseData(new MPlayerDiscover(GlobalVariables.Video1Path, GlobalVariables.MplayerPath));
14 | #if !MACOS
15 | yield return new TestCaseData(new MpvDiscover(GlobalVariables.Video1Path, GlobalVariables.LibMpvPath));
16 | #endif
17 | yield return new TestCaseData(new FfmpegDiscover(GlobalVariables.Video1Path, GlobalVariables.FfprobePath));
18 | }
19 | }
20 |
21 | public static IEnumerable TestCasesVideo2
22 | {
23 | get
24 | {
25 | yield return new TestCaseData(new MPlayerDiscover(GlobalVariables.Video2Path, GlobalVariables.MplayerPath));
26 | #if !MACOS
27 | yield return new TestCaseData(new MpvDiscover(GlobalVariables.Video2Path, GlobalVariables.LibMpvPath));
28 | #endif
29 | yield return new TestCaseData(new FfmpegDiscover(GlobalVariables.Video2Path, GlobalVariables.FfprobePath));
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/Discover_Test.cs:
--------------------------------------------------------------------------------
1 | using Majorsilence.Media.Videos;
2 | using NUnit.Framework;
3 |
4 | namespace MplayerUnitTests;
5 |
6 | [TestFixture]
7 | public class Discover_Test
8 | {
9 | [Test, TestCaseSource(typeof(DiscoverTestCaseSource), "TestCasesVideo1")]
10 | public void Video1_Test(Discover discover)
11 | {
12 | using (discover)
13 | {
14 | discover.Execute();
15 | Assert.AreEqual(128, discover.AudioBitrate, "AudioBitrate");
16 | Assert.AreEqual(true, discover.Audio, "Audio");
17 | Assert.AreEqual(true, discover.Video, "Video");
18 | Assert.AreEqual("9:16", discover.AspectRatioString, "AspectRatioString");
19 | Assert.AreEqual(0.5625f, discover.AspectRatio, "AspectRatio");
20 | Assert.AreEqual(1, discover.AudioList.Count, "AudioList.Count");
21 | Assert.AreEqual(44100, discover.AudioSampleRate, "AudioSampleRate");
22 | Assert.AreEqual(29, discover.FPS, "FPS");
23 | Assert.AreEqual(1920, discover.Height, "Height");
24 | Assert.AreEqual(1080, discover.Width, "Width");
25 | Assert.AreEqual(2, discover.Length, "Length");
26 | Assert.AreEqual(3964, discover.VideoBitrate, "VideoBitrate");
27 | }
28 | }
29 |
30 | [Test, TestCaseSource(typeof(DiscoverTestCaseSource), "TestCasesVideo2")]
31 | public void Video2_Test(Discover discover)
32 | {
33 | using (discover)
34 | {
35 | discover.Execute();
36 | Assert.AreEqual(128, discover.AudioBitrate, "AudioBitrate");
37 | Assert.AreEqual(true, discover.Audio, "Audio");
38 | Assert.AreEqual(true, discover.Video, "Video");
39 | Assert.AreEqual(1.77777779f, discover.AspectRatio, "AspectRatio");
40 | Assert.AreEqual(1, discover.AudioList.Count, "AudioList.Count");
41 | Assert.AreEqual(44100, discover.AudioSampleRate, "AudioSampleRate");
42 | Assert.AreEqual(30, discover.FPS, "FPS");
43 | Assert.AreEqual(1080, discover.Height, "Height");
44 | Assert.AreEqual(1920, discover.Width, "Width");
45 | Assert.AreEqual(4, discover.Length, "Length");
46 | Assert.AreEqual(4650, discover.VideoBitrate, "VideoBitrate");
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/GlobalVariables.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MplayerUnitTests;
5 |
6 | public class GlobalVariables
7 | {
8 | // Test videos can be downloaded from:
9 | // http://files.majorsilence.com/TestVideos.zip
10 | // TODO: You must point the path to the mplayer.exe and the test videos to the location
11 | // were they exist on your computer.
12 |
13 | public static string BasePath => Path.Combine(Path.GetTempPath(), "MPlayerControl", "Tests", "TestVideos");
14 |
15 | private static string _mplayerPath;
16 |
17 | public static string MplayerPath
18 | {
19 | get
20 | {
21 | InitPath();
22 | return _mplayerPath;
23 | }
24 | private set { _mplayerPath = value; }
25 | }
26 |
27 | private static string _libMpvPath;
28 |
29 | public static string LibMpvPath
30 | {
31 | get
32 | {
33 | InitPath();
34 | return _libMpvPath;
35 | }
36 | private set { _libMpvPath = value; }
37 | }
38 |
39 | private static string _ffmpegPath;
40 |
41 | public static string FfmpegPath
42 | {
43 | get
44 | {
45 | InitPath();
46 | return _ffmpegPath;
47 | }
48 | private set { _ffmpegPath = value; }
49 | }
50 |
51 | private static string _ffprobePath;
52 |
53 | public static string FfprobePath
54 | {
55 | get
56 | {
57 | InitPath();
58 | return _ffprobePath;
59 | }
60 | private set { _ffprobePath = value; }
61 | }
62 |
63 | public static string Video2Path => Path.Combine(BasePath, "video2.mp4");
64 |
65 | public static string Video1Path => Path.Combine(BasePath, "video1.mp4");
66 |
67 | public static string OutputVideoWebM => Path.Combine(BasePath, "OutputVideoWebM.webm");
68 |
69 | public static string OutputVideoX264 => Path.Combine(BasePath, "OutputVideoX264.mp4");
70 |
71 | public static string OutputVideoX265 => Path.Combine(BasePath, "OutputVideoX265.mp4");
72 |
73 | public static string OutputVideoAv1 => Path.Combine(BasePath, "OutputVideoAv1.mp4");
74 | public static string OutputThumbnail => Path.Combine(BasePath, "OutputThumbnail.jpg");
75 | public static string OutputVideoDvdMpegPal => Path.Combine(BasePath, "OutputVideoDvdMpegPal.mpg");
76 |
77 | public static string OutputVideoDvdMpegNtsc => Path.Combine(BasePath, "OutputVideoDvdMpegNtsc.mpg");
78 |
79 | private static bool initCalled = false;
80 |
81 | private static void InitPath()
82 | {
83 | if (initCalled) return;
84 |
85 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
86 | {
87 | MplayerPath = @"mplayer.exe";
88 | LibMpvPath = @"mpv-1.dll";
89 | FfmpegPath = @"ffmpeg.exe";
90 | FfprobePath = @"ffprobe.exe";
91 | }
92 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
93 | {
94 | MplayerPath = "/opt/homebrew/bin/mplayer";
95 | LibMpvPath = "/opt/homebrew/lib/libmpv.2.dylib";
96 | FfmpegPath = "/opt/homebrew/bin/ffmpeg";
97 | FfprobePath = "/opt/homebrew/bin/ffprobe";
98 | }
99 | else
100 | {
101 | MplayerPath = "mplayer";
102 | LibMpvPath = "/usr/lib/x86_64-linux-gnu/libmpv.so.1";
103 | FfmpegPath = "/usr/bin/ffmpeg";
104 | FfprobePath = "/usr/bin/ffprobe";
105 | }
106 |
107 | initCalled = true;
108 | }
109 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/ImageResize_Test.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Majorsilence.Media.Images;
3 | using NUnit.Framework;
4 | using SixLabors.ImageSharp;
5 | using SixLabors.ImageSharp.Formats.Jpeg;
6 |
7 | namespace MplayerUnitTests;
8 |
9 | [TestFixture]
10 | public class ImageResize_Test
11 | {
12 | [Test]
13 | public void Test1()
14 | {
15 | var a = ImageResize.ResizeBlackBar(
16 | Path.Combine(GlobalVariables.BasePath,
17 | "1.jpg"), 720, 480);
18 |
19 | var jpgEncoder = new JpegEncoder();
20 | a.SaveAsJpeg(Path.Combine(GlobalVariables.BasePath,
21 | "test.jpg"), jpgEncoder);
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/MPlayer_Test.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Linq;
3 | using Majorsilence.Media.Videos;
4 | using NUnit.Framework;
5 |
6 | namespace MplayerUnitTests;
7 |
8 | [TestFixture]
9 | public class MPlayer_Test
10 | {
11 | [Test]
12 | public void MemoryLeak_Test()
13 | {
14 | for (var i = 0; i < 500; i++)
15 | using (var a = new MPlayer(-1, MplayerBackends.ASCII, GlobalVariables.MplayerPath))
16 | {
17 | a.Play(GlobalVariables.Video1Path);
18 | }
19 |
20 | var processes = Process.GetProcessesByName("mplayer");
21 | Assert.That(processes.Any(), Is.EqualTo(false), $"mplayer process count is {processes.Count()}");
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/Majorsilence.Media.NunitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net9.0
4 | MplayerUnitTests
5 |
6 |
7 | full
8 | bin\$(Configuration)\
9 |
10 |
11 |
12 |
13 |
14 | false
15 |
16 |
17 | pdbonly
18 | bin\$(Configuration)\
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | $(DefineConstants);MACOS
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | PreserveNewest
39 |
40 |
41 | PreserveNewest
42 |
43 |
44 | PreserveNewest
45 |
46 |
47 | PreserveNewest
48 |
49 |
50 |
51 |
52 | all
53 | runtime; build; native; contentfiles; analyzers; buildtransitive
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/Mencoder2_Test.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Majorsilence.Media.Videos;
3 | using NUnit.Framework;
4 |
5 | namespace MplayerUnitTests;
6 |
7 | [TestFixture]
8 | public class Mencoder2_Test
9 | {
10 | [Test]
11 | public void Convert2WebMTest()
12 | {
13 | using (var a = new Mencoder())
14 | {
15 | a.PercentCompleted += (s, e) =>
16 | {
17 | // Console.WriteLine ($"Convert2WebMTest Percent: {e.Value}");
18 | };
19 | a.Convert2WebM(GlobalVariables.Video1Path, GlobalVariables.OutputVideoWebM);
20 | }
21 | }
22 |
23 | [Test]
24 | public async Task Convert2WebMAsyncTest()
25 | {
26 | var a = new Mencoder();
27 | a.PercentCompleted += (s, e) =>
28 | {
29 | // Console.WriteLine ($"Convert2WebMAsyncTest Percent: {e.Value}");
30 | };
31 | await a.Convert2WebMAsync(GlobalVariables.Video1Path, GlobalVariables.OutputVideoWebM);
32 | }
33 |
34 |
35 | [Test]
36 | public void Convert2X264Test()
37 | {
38 | using (var a = new Mencoder())
39 | {
40 | a.Convert2X264(GlobalVariables.Video1Path, GlobalVariables.OutputVideoX264);
41 | }
42 | }
43 |
44 | [Test]
45 | public async Task Convert2X264AsyncTest()
46 | {
47 | using (var a = new Mencoder())
48 | {
49 | await a.Convert2X264Async(GlobalVariables.Video1Path, GlobalVariables.OutputVideoX264);
50 | }
51 | }
52 |
53 | [Test]
54 | public void Convert2DvdMpegPalTest()
55 | {
56 | using (var a = new Mencoder())
57 | {
58 | a.Convert2DvdMpeg(RegionType.PAL, GlobalVariables.Video1Path, GlobalVariables.OutputVideoDvdMpegPal);
59 | }
60 | }
61 |
62 | [Test]
63 | public async Task Convert2DvdMpegPalAsyncTest()
64 | {
65 | using (var a = new Mencoder())
66 | {
67 | await a.Convert2DvdMpegAsync(RegionType.PAL, GlobalVariables.Video1Path,
68 | GlobalVariables.OutputVideoDvdMpegPal);
69 | }
70 | }
71 |
72 | [Test]
73 | public void Convert2DvdMpegNtscTest()
74 | {
75 | using (var a = new Mencoder())
76 | {
77 | a.Convert2DvdMpeg(RegionType.NTSC, GlobalVariables.Video1Path, GlobalVariables.OutputVideoDvdMpegNtsc);
78 |
79 | a.ConversionComplete += a_ConversionComplete;
80 | }
81 | }
82 |
83 | [Test]
84 | public async Task Convert2DvdMpegNtscAsyncTest()
85 | {
86 | using (var a = new Mencoder())
87 | {
88 | await a.Convert2DvdMpegAsync(RegionType.NTSC, GlobalVariables.Video1Path,
89 | GlobalVariables.OutputVideoDvdMpegNtsc);
90 | }
91 | }
92 |
93 | private void a_ConversionComplete(object sender, MplayerEvent e)
94 | {
95 | using (var a = new MPlayerDiscover(GlobalVariables.OutputVideoDvdMpegNtsc, GlobalVariables.MplayerPath))
96 | {
97 | Assert.AreEqual(192, a.AudioBitrate);
98 | Assert.AreEqual(720, a.Width);
99 | Assert.AreEqual(480, a.Height);
100 | Assert.AreEqual(48000, a.AudioSampleRate);
101 | }
102 | }
103 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | // Setting ComVisible to false makes the types in this assembly not visible
4 | // to COM components. If you need to access a type in this assembly from
5 | // COM, set the ComVisible attribute to true on that type.
6 | [assembly: ComVisible(false)]
7 |
8 | // The following GUID is for the ID of the typelib if this project is exposed to COM
9 | [assembly: Guid("112fd936-6b5e-42c8-9e1b-166986263ad0")]
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/SetupInitialize.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using System.Runtime.InteropServices;
5 | using NUnit.Framework;
6 |
7 | namespace MplayerUnitTests;
8 |
9 | [SetUpFixture]
10 | public class SetupInitialize
11 | {
12 | private static string finalPath;
13 |
14 | [OneTimeSetUp]
15 | public void RunBeforeAnyTests()
16 | {
17 | finalPath = GlobalVariables.BasePath;
18 | FinalTearDown();
19 | if (!Directory.Exists(finalPath)) Directory.CreateDirectory(finalPath);
20 |
21 | var files = Directory.GetFiles(Path.Combine(ExecutingDirectory(), "TestVideos"));
22 | foreach (var file in files) File.Copy(file, Path.Combine(finalPath, Path.GetFileName(file)));
23 | }
24 |
25 | [OneTimeTearDown]
26 | public void FinalTearDown()
27 | {
28 | if (Directory.Exists(finalPath)) Directory.Delete(finalPath, true);
29 | }
30 |
31 | private static string ExecutingDirectory()
32 | {
33 | var location = Assembly.GetExecutingAssembly().Location;
34 | location = Path.GetDirectoryName(location);
35 | return location;
36 | }
37 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/SlideShow_Test.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Threading.Tasks;
4 | using Majorsilence.Media.Videos;
5 | using NUnit.Framework;
6 |
7 | namespace MplayerUnitTests;
8 |
9 | [TestFixture]
10 | public class SlideShow_Test
11 | {
12 | [Test]
13 | public void Test1()
14 | {
15 | var a = new SlideShow();
16 |
17 | var b = new List();
18 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
19 | "1.jpg"),
20 | SlideShowEffect.TimeWarp));
21 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
22 | "2.jpg"),
23 | SlideShowEffect.Moire));
24 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
25 | "3.jpg"),
26 | SlideShowEffect.Water));
27 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
28 | "4.jpg"),
29 | SlideShowEffect.RandomJitter));
30 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
31 | "5.jpg"),
32 | SlideShowEffect.Pixelate));
33 | a.CreateSlideShow(b,
34 | Path.Combine(GlobalVariables.BasePath, "helloworld.mpg"),
35 | Path.Combine(GlobalVariables.BasePath, @"doxent_-_Sunset_Boulevard-edit.mp3"),
36 | 5);
37 | }
38 |
39 | [Test]
40 | public async Task Async_Test1()
41 | {
42 | var a = new SlideShow();
43 |
44 | var b = new List();
45 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
46 | "1.jpg"),
47 | SlideShowEffect.TimeWarp));
48 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
49 | "2.jpg"),
50 | SlideShowEffect.Moire));
51 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
52 | "3.jpg"),
53 | SlideShowEffect.Water));
54 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
55 | "4.jpg"),
56 | SlideShowEffect.RandomJitter));
57 | b.Add(new SlideShowInfo(Path.Combine(GlobalVariables.BasePath,
58 | "5.jpg"),
59 | SlideShowEffect.Pixelate));
60 | await a.CreateSlideShowAsync(b,
61 | Path.Combine(GlobalVariables.BasePath, "helloworld_async_test.mpg"),
62 | Path.Combine(GlobalVariables.BasePath, @"doxent_-_Sunset_Boulevard-edit.mp3"),
63 | 5);
64 | }
65 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/1.jpg
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/2.jpg
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/3.jpg
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/4.jpg
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/5.jpg
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/6.jpg
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/audio_license.txt:
--------------------------------------------------------------------------------
1 | Sunset Boulevard by Doxent Zsigmond (c) copyright 2015
2 | Licensed under a Creative Commons Attribution Noncommercial (3.0) license.
3 | http://dig.ccmixter.org/files/doxent/50485 Ft: Siobhan Dakay, unreal_dm
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/doxent_-_Sunset_Boulevard-edit.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/doxent_-_Sunset_Boulevard-edit.mp3
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/video1.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/video1.mp4
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/TestVideos/video2.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/Majorsilence.Media.NunitTests/TestVideos/video2.mp4
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/VideoEncoderTestCaseSource.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using Majorsilence.Media.Videos;
3 | using NUnit.Framework;
4 |
5 | namespace MplayerUnitTests;
6 |
7 | public static class VideoEncoderTestCaseSource
8 | {
9 | public static IEnumerable TestCasesEncoders
10 | {
11 | get
12 | {
13 | yield return new TestCaseData(new Mencoder(GlobalVariables.MplayerPath));
14 | yield return new TestCaseData(new Ffmpeg(GlobalVariables.FfprobePath));
15 | }
16 | }
17 |
18 | public static IEnumerable TestCasesEncodersConvertAsync
19 | {
20 | get
21 | {
22 | yield return new TestCaseData(new Mencoder(GlobalVariables.MplayerPath), VideoType.vp9, AudioType.opus,
23 | VideoAspectRatios.p240);
24 | yield return new TestCaseData(new Mencoder(GlobalVariables.MplayerPath), VideoType.x264, AudioType.aac,
25 | VideoAspectRatios.p240);
26 | yield return new TestCaseData(new Ffmpeg(GlobalVariables.FfprobePath), VideoType.vp9, AudioType.opus,
27 | VideoAspectRatios.p240);
28 | yield return new TestCaseData(new Ffmpeg(GlobalVariables.FfprobePath), VideoType.x264, AudioType.aac,
29 | VideoAspectRatios.p240);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.NunitTests/VideoEncoder_Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Majorsilence.Media.Videos;
5 | using NUnit.Framework;
6 |
7 | namespace MplayerUnitTests;
8 |
9 | [TestFixture]
10 | public class VideoEncoder_Test
11 | {
12 | [Test, TestCaseSource(typeof(VideoEncoderTestCaseSource), "TestCasesEncoders")]
13 | public void Convert2WebMTest(IVideoEncoder encoder)
14 | {
15 | using (encoder as IDisposable)
16 | {
17 | encoder.Convert2WebM(GlobalVariables.Video1Path, GlobalVariables.OutputVideoWebM);
18 | }
19 | }
20 |
21 | [Test, TestCaseSource(typeof(VideoEncoderTestCaseSource), "TestCasesEncoders")]
22 | public void Convert2X264Test(IVideoEncoder encoder)
23 | {
24 | using (encoder as IDisposable)
25 | {
26 | encoder.Convert2X264(GlobalVariables.Video1Path, GlobalVariables.OutputVideoX264);
27 | }
28 | }
29 |
30 | [Test, TestCaseSource(typeof(VideoEncoderTestCaseSource), "TestCasesEncoders")]
31 | public void Convert2X265Test(IVideoEncoder encoder)
32 | {
33 | using (encoder as IDisposable)
34 | {
35 | encoder.Convert2X265(GlobalVariables.Video1Path, GlobalVariables.OutputVideoX265);
36 | }
37 | }
38 |
39 | [Test, TestCaseSource(typeof(VideoEncoderTestCaseSource), "TestCasesEncoders")]
40 | public void Convert2Av1Test(IVideoEncoder encoder)
41 | {
42 | using (encoder as IDisposable)
43 | {
44 | encoder.Convert2Av1(GlobalVariables.Video1Path, GlobalVariables.OutputVideoAv1);
45 | }
46 | }
47 |
48 | [Test, TestCaseSource(typeof(VideoEncoderTestCaseSource), "TestCasesEncoders")]
49 | public async Task ThumbnailTest(IVideoEncoder encoder)
50 | {
51 | using (encoder as IDisposable)
52 | {
53 | await encoder.ThumbnailAsync(GlobalVariables.Video1Path, GlobalVariables.OutputThumbnail,
54 | CancellationToken.None);
55 | }
56 | }
57 |
58 | [Test, TestCaseSource(typeof(VideoEncoderTestCaseSource), "TestCasesEncodersConvertAsync")]
59 | public async Task ConvertAsync(IVideoEncoder encoder, VideoType videoType, AudioType audioType,
60 | VideoAspectRatios aspectRatio)
61 | {
62 | using (encoder as IDisposable)
63 | {
64 | await encoder.ConvertAsync(videoType, audioType, aspectRatio, GlobalVariables.Video1Path,
65 | GlobalVariables.OutputVideoWebM,
66 | CancellationToken.None);
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/AspectRatio.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2010 (C) Peter Gill
4 |
5 | This file is part of Majorsilence.Media.Videos.
6 |
7 | Majorsilence.Media.Videos is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | Majorsilence.Media.Videos is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | namespace Majorsilence.Media.Videos;
23 |
24 | ///
25 | /// This class is used to hold different video aspect ratio values.
26 | ///
27 | public class ScreenAspectRatio
28 | {
29 | ///
30 | /// The float value of 4/3 aspect ratio.
31 | ///
32 | public static float FourThree => 4.0f / 3.0f;
33 |
34 | ///
35 | /// The float value of 16/9 aspect ratio.
36 | ///
37 | public static float SixteenNine => 16.0f / 9.0f;
38 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/AudioType.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.Videos;
2 |
3 | public enum AudioType
4 | {
5 | implementation_detail,
6 | ac3,
7 | mp3,
8 | mp2,
9 | vorbis,
10 | flac,
11 | wmav1,
12 | wmav2,
13 | opus,
14 | aac
15 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/BackendPrograms.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2010 (C) Peter Gill
4 |
5 | This file is part of Majorsilence.Media.Videos.
6 |
7 | Majorsilence.Media.Videos is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | Majorsilence.Media.Videos is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | using System;
23 | using System.IO;
24 | using System.Reflection;
25 |
26 | namespace Majorsilence.Media.Videos;
27 |
28 | public class BackendPrograms
29 | {
30 | private readonly string _mencoderPath;
31 |
32 | private readonly string _mplayerPath;
33 |
34 | public BackendPrograms()
35 | {
36 | _mplayerPath = "";
37 | _mencoderPath = "";
38 | }
39 |
40 | public BackendPrograms(string mplayerPath)
41 | {
42 | _mplayerPath = mplayerPath;
43 | _mencoderPath = "";
44 | }
45 |
46 | public BackendPrograms(string mplayerPath, string mencoderPath)
47 | {
48 | _mplayerPath = mplayerPath;
49 | _mencoderPath = mencoderPath;
50 | }
51 |
52 | public string MPlayer
53 | {
54 | get
55 | {
56 | if (OSPlatform() == "windows")
57 | {
58 | if (_mplayerPath != "") return _mplayerPath;
59 | return Path.Combine(CurrentAssemblyDirectory(), "mplayer.exe");
60 | }
61 |
62 | if (_mplayerPath != "") return _mplayerPath;
63 |
64 | return "mplayer";
65 | }
66 | }
67 |
68 | public string MEncoder
69 | {
70 | get
71 | {
72 | if (OSPlatform() == "windows")
73 | {
74 | if (_mencoderPath != "") return _mencoderPath;
75 |
76 | return Path.Combine(CurrentAssemblyDirectory(), "mencoder.exe");
77 | }
78 |
79 | if (_mencoderPath != "") return _mencoderPath;
80 |
81 | return "mencoder";
82 | }
83 | }
84 |
85 |
86 | public static string OSPlatform()
87 | {
88 | if (Environment.OSVersion.Platform == PlatformID.Unix ||
89 | Environment.OSVersion.Platform == PlatformID.MacOSX) return "unix";
90 | return "windows";
91 | }
92 |
93 | ///
94 | /// Return the directory of the current executing assembly
95 | ///
96 | ///
97 | private static string CurrentAssemblyDirectory()
98 | {
99 | var location = Assembly.GetExecutingAssembly().Location;
100 | location = Path.GetDirectoryName(location);
101 | return location;
102 | }
103 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/Discover.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | namespace Majorsilence.Media.Videos;
6 |
7 | public interface Discover : IDisposable
8 | {
9 | int VideoBitrate { get; }
10 |
11 | int AudioBitrate { get; }
12 |
13 | int AudioSampleRate { get; }
14 |
15 | int Width { get; }
16 |
17 | int Height { get; }
18 |
19 | int FPS { get; }
20 |
21 | int Length { get; }
22 |
23 | string AspectRatioString { get; }
24 | float AspectRatio { get; }
25 |
26 | List AudioList { get; }
27 |
28 | List AudioTracks { get; }
29 |
30 | bool Video { get; }
31 |
32 | bool Audio { get; }
33 |
34 | List SubtitleList { get; }
35 |
36 | void Execute();
37 |
38 | Task ExecuteAsync();
39 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/DiscoverFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Majorsilence.Media.Videos;
4 |
5 | public static class DiscoverFactory
6 | {
7 | ///
8 | /// Attempt to auto detect prefered backends.
9 | ///
10 | /// The multimedia file to discover
11 | /// Path to mplayer executable or mpv library
12 | public static Discover Get(string file, string path)
13 | {
14 | if (PlatformCheck.RunningPlatform() == Platform.Windows)
15 | return Windows(file, path);
16 | if (PlatformCheck.RunningPlatform() == Platform.Linux)
17 | return Linux(file, path);
18 | if (PlatformCheck.RunningPlatform() == Platform.Mac)
19 | return Mac(file, path);
20 | throw new NotImplementedException();
21 | }
22 |
23 | private static Discover Windows(string file, string path)
24 | {
25 | if (path.Contains("mplayer"))
26 | return new MPlayerDiscover(file, path);
27 | if (path.Contains("mpv")) return new MpvDiscover(file, path);
28 |
29 | return null;
30 | }
31 |
32 | private static Discover Linux(string file, string path)
33 | {
34 | if (path.Contains("mplayer"))
35 | return new MPlayerDiscover(file, path);
36 | if (path.Contains("libmpv")) return new MpvDiscover(file, path);
37 |
38 | return null;
39 | }
40 |
41 | private static Discover Mac(string file, string path)
42 | {
43 | if (path.Contains("mplayer"))
44 | return new MPlayerDiscover(file, path);
45 | if (path.Contains("libmpv")) return new MpvDiscover(file, path);
46 |
47 | return null;
48 | }
49 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/Exceptions/MPlayerControlException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Majorsilence.Media.Videos.Exceptions;
4 |
5 | public class MPlayerControlException : Exception
6 | {
7 | public int ErrorCode;
8 |
9 | public MPlayerControlException(string msg)
10 | : base(msg)
11 | {
12 | }
13 |
14 | public MPlayerControlException(string msg, int errorCode)
15 | : base(msg)
16 | {
17 | ErrorCode = errorCode;
18 | }
19 |
20 | public MPlayerControlException(string msg, Exception ex)
21 | : base(msg, ex)
22 | {
23 | }
24 |
25 | public MPlayerControlException(string msg, Exception ex, int errorCode)
26 | : base(msg, ex)
27 | {
28 | ErrorCode = errorCode;
29 | }
30 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/Globals.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2010 (C) Peter Gill
4 |
5 | This file is part of Majorsilence.Media.Videos.
6 |
7 | Majorsilence.Media.Videos is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | Majorsilence.Media.Videos is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | using System;
23 | using System.Globalization;
24 | using System.IO;
25 |
26 | namespace Majorsilence.Media.Videos;
27 |
28 | public class Globals
29 | {
30 | private Globals()
31 | {
32 | }
33 |
34 | public static string MajorSilenceLocalAppDataDirectory
35 | {
36 | get
37 | {
38 | string msDir = null;
39 | msDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
40 | msDir = Path.Combine(msDir, "MajorSilence");
41 | return msDir;
42 | }
43 | }
44 |
45 | public static string MajorSilenceMPlayerLocalAppDataDirectory =>
46 | Path.Combine(MajorSilenceLocalAppDataDirectory, "MPlayer");
47 |
48 | public static string MajorSilenceMEncoderLocalAppDataDirectory =>
49 | Path.Combine(MajorSilenceLocalAppDataDirectory, "MEncoder");
50 |
51 | public static int IntParse(string input)
52 | {
53 | return int.Parse(input.Replace(",", "."), CultureInfo.InvariantCulture);
54 | }
55 |
56 | public static float FloatParse(string input)
57 | {
58 | input = input.Trim();
59 | if (input.Equals("nan", StringComparison.OrdinalIgnoreCase) ||
60 | input.Equals("-nan", StringComparison.OrdinalIgnoreCase)) return float.NaN;
61 | var outValue = 0f;
62 | float.TryParse(input.Replace(",", "."), out outValue);
63 | return outValue;
64 | }
65 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/IVideoEncoder.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2012 (C) Peter Gill
4 |
5 | This file is part of Majorsilence.Media.Videos.
6 |
7 | Majorsilence.Media.Videos is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | Majorsilence.Media.Videos is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | using System.Threading;
23 | using System.Threading.Tasks;
24 |
25 | namespace Majorsilence.Media.Videos;
26 |
27 | public interface IVideoEncoder
28 | {
29 | void Convert(string cmd, string workingDirectory = "");
30 | Task ConvertAsync(string cmd, string workingDirectory, CancellationToken stoppingToken);
31 | void Convert(VideoType vidType, AudioType audType, string videoToConvertFilePath, string outputFilePath);
32 |
33 | void Convert(VideoType vidType, AudioType audType, VideoAspectRatios aspectRatios,
34 | string videoToConvertFilePath,
35 | string outputFilePath);
36 |
37 | Task ConvertAsync(VideoType vidType, AudioType audType, VideoAspectRatios aspectRatios,
38 | string videoToConvertFilePath,
39 | string outputFilePath, CancellationToken stoppingToken);
40 |
41 | void Convert2WebM(string videoToConvertFilePath, string outputFilePath);
42 | void Convert2X264(string videoToConvertFilePath, string outputFilePath);
43 | void Convert2X265(string videoToConvertFilePath, string outputFilePath);
44 | void Convert2Av1(string videoToConvertFilePath, string outputFilePath);
45 | Task ThumbnailAsync(string videoToConvertFilePath, string outputFilePath, CancellationToken stoppingToken);
46 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/Logging.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2010 (C) Peter Gill
4 |
5 | This file is part of Majorsilence.Media.Videos.
6 |
7 | Majorsilence.Media.Videos is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | Majorsilence.Media.Videos is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | using System;
23 | using System.Diagnostics;
24 | using System.IO;
25 |
26 | namespace Majorsilence.Media.Videos;
27 |
28 | public class Logging
29 | {
30 | // TODO: replace with real logging framework
31 |
32 | private static volatile Logging instance;
33 | private static readonly object syncRoot = new();
34 |
35 | private readonly string filePath;
36 |
37 |
38 | private Logging()
39 | {
40 | filePath = Path.Combine(Globals.MajorSilenceMPlayerLocalAppDataDirectory, "MajorSilence-Debug.txt");
41 | Trace.Listeners.Add(new TextWriterTraceListener(filePath));
42 | Trace.AutoFlush = true;
43 | }
44 |
45 | public static Logging Instance
46 | {
47 | get
48 | {
49 | if (instance == null)
50 | lock (syncRoot)
51 | {
52 | if (instance == null) instance = new Logging();
53 | }
54 |
55 | if (Directory.Exists(Globals.MajorSilenceMPlayerLocalAppDataDirectory) == false)
56 | Directory.CreateDirectory(Globals.MajorSilenceMPlayerLocalAppDataDirectory);
57 |
58 | return instance;
59 | }
60 | }
61 |
62 | public void WriteLine(string msg)
63 | {
64 | WriteLine(msg, "UNKNOWN");
65 | }
66 |
67 | public void WriteLine(string msg, string category)
68 | {
69 | var output = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + Environment.NewLine;
70 | output += msg + Environment.NewLine;
71 | output += Environment.NewLine + Environment.NewLine;
72 |
73 | Trace.WriteLine(output, category);
74 | }
75 |
76 | public void WriteLine(Exception value)
77 | {
78 | WriteLine(value, "UNKNOWN");
79 | }
80 |
81 | public void WriteLine(Exception value, string category)
82 | {
83 | WriteLine(value.Message + Environment.NewLine + value.StackTrace, category);
84 | }
85 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/Majorsilence.Media.Videos.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Majorsilence.Media.Videos
4 | net6.0;net8.0;net9.0
5 | Majorsilence.Media.Videos
6 | Majorsilence.Media.Videos
7 | True
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/MediaStatus.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.Videos;
2 |
3 | ///
4 | /// Status of the mplayer.exe instance.
5 | ///
6 | public enum MediaStatus
7 | {
8 | Paused,
9 | Playing,
10 | Stopped
11 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/MplayerBackends.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.Videos;
2 |
3 | ///
4 | /// The video output backend that mplayer is using.
5 | ///
6 | public enum MplayerBackends
7 | {
8 | ///
9 | /// This may be the recommened backend on Mac OSX.
10 | ///
11 | OpenGL = 1,
12 |
13 | ///
14 | /// Simple Version
15 | ///
16 | GL = 2,
17 |
18 | ///
19 | /// Simple Version. Variant of the OpenGL video output driver.
20 | /// Supports videos larger than the maximum texture size but lacks
21 | /// many of the ad‐vanced features and optimizations of the gl driver
22 | /// and is un‐likely to be extended further.
23 | ///
24 | GL2 = 3,
25 |
26 | ///
27 | /// Windows. This is the recommened backend on windows.
28 | ///
29 | Direct3D = 4,
30 |
31 | ///
32 | /// Windows
33 | ///
34 | DirectX = 5,
35 |
36 | ///
37 | /// Linux
38 | ///
39 | X11 = 6,
40 | VESA = 7,
41 |
42 | ///
43 | /// Mac OS X
44 | ///
45 | Quartz = 8,
46 |
47 | ///
48 | /// Mac OS X
49 | ///
50 | CoreVideo = 9,
51 |
52 | ///
53 | /// Cross Platform
54 | ///
55 | SDL = 10,
56 |
57 | ///
58 | /// Linux
59 | ///
60 | Vdpau = 11,
61 |
62 | ///
63 | /// ASCII art video output driver that works on a text console.
64 | ///
65 | ASCII = 12,
66 |
67 | ///
68 | /// Color ASCII art video output driver that works on a text console.
69 | ///
70 | ColorASCII = 13,
71 |
72 | ///
73 | /// Linux. Play video using the DirectFB library.
74 | ///
75 | Directfb = 14,
76 |
77 | ///
78 | /// Linux. Nintendo Wii/GameCube specific video output driver.
79 | ///
80 | Wii = 15,
81 |
82 | ///
83 | /// Linux. requires Linux 2.6.22+ kernel, Video output driver for
84 | // V4L2 compliant cards with built-in hardware MPEG decoder.
85 | ///
86 | V4l2 = 16,
87 |
88 | ///
89 | /// Linux
90 | ///
91 | XV = 17
92 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/MplayerEvent.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2010 (C) Peter Gill
4 |
5 | This file is part of Majorsilence.Media.Videos.
6 |
7 | Majorsilence.Media.Videos is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | Majorsilence.Media.Videos is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 |
23 | using System;
24 |
25 | namespace Majorsilence.Media.Videos;
26 |
27 | ///
28 | /// Delegatefor use with mplayer control events. Uses MplayerEvent.
29 | ///
30 | ///
31 | ///
32 | public delegate void MplayerEventHandler(object sender, MplayerEvent e);
33 |
34 | ///
35 | /// Event class that is used with the mplayer control. Can send String or Integer messages.
36 | ///
37 | public class MplayerEvent : EventArgs
38 | {
39 | public MplayerEvent(string m)
40 | {
41 | Message = m;
42 | Value = 0;
43 | }
44 |
45 | public MplayerEvent(float v)
46 | {
47 | Message = "";
48 | Value = v;
49 | }
50 |
51 | ///
52 | /// Event Message.
53 | ///
54 | public string Message { get; }
55 |
56 | public float Value { get; }
57 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/PlatformCheck.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Majorsilence.Media.Videos;
5 |
6 | public enum Platform
7 | {
8 | Windows,
9 | Linux,
10 | Mac
11 | }
12 |
13 | public static class PlatformCheck
14 | {
15 | public static Platform RunningPlatform()
16 | {
17 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
18 | return Platform.Windows;
19 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
20 | return Platform.Linux;
21 | if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return Platform.Mac;
22 |
23 | throw new PlatformNotSupportedException();
24 | }
25 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/Player.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Majorsilence.Media.Videos;
4 |
5 | public interface Player : IDisposable
6 | {
7 | bool FullScreen { get; set; }
8 |
9 | MediaStatus CurrentStatus { get; set; }
10 |
11 | string CurrentFilePath { get; }
12 | event MplayerEventHandler VideoExited;
13 | event MplayerEventHandler CurrentPosition;
14 |
15 | void ToggleFullScreen();
16 |
17 | void Stop();
18 |
19 | void Pause();
20 |
21 | void Mute();
22 |
23 | ///
24 | /// The window id that the video will play in
25 | ///
26 | /// Wid.
27 | void SetHandle(long wid);
28 |
29 | void MovePosition(int timePosition);
30 |
31 | void Play(string filePath);
32 |
33 | void Seek(int value, Seek type);
34 |
35 | void SetSize(int width, int height);
36 |
37 | void SwitchAudioTrack(int track);
38 |
39 | void SwitchSubtitle(int sub);
40 |
41 | int CurrentPlayingFileLength();
42 |
43 | void Volume(int volume);
44 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/PlayerFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Majorsilence.Media.Videos;
4 |
5 | public static class PlayerFactory
6 | {
7 | ///
8 | /// Attempt to auto detect prefered backends.
9 | ///
10 | /// Handle.
11 | /// Path to mplayer executable or mpv library
12 | public static Player Get(long handle, string path)
13 | {
14 | // -path "/usr/lib/x86_64-linux-gnu/libmpv.so.1"
15 |
16 | if (PlatformCheck.RunningPlatform() == Platform.Windows)
17 | return Windows(handle, path);
18 | if (PlatformCheck.RunningPlatform() == Platform.Linux)
19 | return Linux(handle, path);
20 | if (PlatformCheck.RunningPlatform() == Platform.Mac)
21 | return Mac(handle, path);
22 | throw new NotImplementedException();
23 | }
24 |
25 | private static Player Windows(long handle, string path)
26 | {
27 | if (path.Contains("mplayer"))
28 | return new MPlayer(handle, MplayerBackends.Direct3D, path);
29 | if (path.Contains("mpv")) return new MpvPlayer(handle, path);
30 |
31 | return null;
32 | }
33 |
34 | private static Player Linux(long handle, string path)
35 | {
36 | if (path.Contains("mplayer"))
37 | return new MPlayer(handle, MplayerBackends.XV, path);
38 | if (path.Contains("libmpv")) return new MpvPlayer(handle, path);
39 |
40 | return null;
41 | }
42 |
43 | private static Player Mac(long handle, string path)
44 | {
45 | if (path.Contains("mplayer"))
46 | return new MPlayer(handle, MplayerBackends.OpenGL, path);
47 | if (path.Contains("libmpv")) return new MpvPlayer(handle, path);
48 |
49 | return null;
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/RegionType.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.Videos;
2 |
3 | ///
4 | /// The region type used in the video.
5 | ///
6 | public enum RegionType
7 | {
8 | NTSC,
9 | PAL
10 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/Seek.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.Videos;
2 |
3 | ///
4 | /// The seek type that is used when seeking a new position in the video stream.
5 | ///
6 | public enum Seek
7 | {
8 | Relative = 0,
9 | Percentage = 1,
10 | Absolute = 2
11 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/TimeConversion.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2010 (C) Peter Gill
4 |
5 | This file is part of Majorsilence.Media.Videos.
6 |
7 | Majorsilence.Media.Videos is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | Majorsilence.Media.Videos is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | using Majorsilence.Media.Videos.Exceptions;
23 |
24 | namespace Majorsilence.Media.Videos;
25 |
26 | public class TimeConversion
27 | {
28 | ///
29 | /// return time in Hours:Minutes:Seconds format.
30 | ///
31 | ///
32 | ///
33 | public static string ConvertTimeHHMMSS(int timeInSeconds)
34 | {
35 | if (timeInSeconds < 0)
36 | throw new MPlayerControlException(
37 | "Invalid time. Seconds must be greated then >= 0. Seconds passed in was: " + timeInSeconds);
38 |
39 | var hours = 0;
40 | var minutes = 0;
41 | var seconds = 0;
42 | var time_string = "";
43 |
44 | if (timeInSeconds >= 3600)
45 | {
46 | hours = timeInSeconds / 3600;
47 | timeInSeconds = timeInSeconds - hours * 3600;
48 | }
49 |
50 | if (timeInSeconds >= 60)
51 | {
52 | minutes = timeInSeconds / 60;
53 | timeInSeconds = timeInSeconds - minutes * 60;
54 | }
55 |
56 | //remaining time is seconds
57 | seconds = timeInSeconds;
58 |
59 | time_string = time_string + hours.ToString().PadLeft(2, '0') + ":" +
60 | minutes.ToString().PadLeft(2, '0') + ":" + seconds.ToString().PadLeft(2, '0');
61 |
62 | //return time in Hours:Minutes:Seconds format
63 | return time_string;
64 | }
65 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Videos/VideoType.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.Videos;
2 |
3 | public enum VideoType
4 | {
5 | xvid,
6 | av1,
7 | vp9,
8 | x264,
9 | x265,
10 | wmv1,
11 | wmv2,
12 | mpeg4
13 | }
14 |
15 | public enum VideoAspectRatios
16 | {
17 | original,
18 | p7680,
19 | p2160,
20 | p1440,
21 | p1080,
22 | p720,
23 | p480,
24 | p360,
25 | p240
26 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32630.192
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Images", "Majorsilence.Media.Images\Majorsilence.Media.Images.csproj", "{C859FA27-7882-4814-9202-9C9D807C2CE5}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Videos", "Majorsilence.Media.Videos\Majorsilence.Media.Videos.csproj", "{5D3616D0-160D-4601-AB67-E1ED9111C676}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.NunitTests", "Majorsilence.Media.NunitTests\Majorsilence.Media.NunitTests.csproj", "{5E050A99-68E9-4F34-82BD-4E04EAF64CA7}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Web", "Majorsilence.Media.Web\Majorsilence.Media.Web.csproj", "{D99A13FE-8E34-4AA7-96A6-5120159220FE}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Majorsilence.Media.WorkerService", "Majorsilence.Media.WorkerService\Majorsilence.Media.WorkerService.csproj", "{701173C2-C7D4-4ECD-B6FE-663424B0BAD7}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Majorsilence.Media.WorkerService.Tests", "Majorsilence.Media.WorkerService.Tests\Majorsilence.Media.WorkerService.Tests.csproj", "{E6FC85A6-15F5-4404-A7D2-6B9AE3D44DAD}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Release|Any CPU = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {5E050A99-68E9-4F34-82BD-4E04EAF64CA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {5E050A99-68E9-4F34-82BD-4E04EAF64CA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {5E050A99-68E9-4F34-82BD-4E04EAF64CA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {5E050A99-68E9-4F34-82BD-4E04EAF64CA7}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {D99A13FE-8E34-4AA7-96A6-5120159220FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {D99A13FE-8E34-4AA7-96A6-5120159220FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {D99A13FE-8E34-4AA7-96A6-5120159220FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {D99A13FE-8E34-4AA7-96A6-5120159220FE}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {701173C2-C7D4-4ECD-B6FE-663424B0BAD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {701173C2-C7D4-4ECD-B6FE-663424B0BAD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {701173C2-C7D4-4ECD-B6FE-663424B0BAD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {701173C2-C7D4-4ECD-B6FE-663424B0BAD7}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {E6FC85A6-15F5-4404-A7D2-6B9AE3D44DAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {E6FC85A6-15F5-4404-A7D2-6B9AE3D44DAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {E6FC85A6-15F5-4404-A7D2-6B9AE3D44DAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {E6FC85A6-15F5-4404-A7D2-6B9AE3D44DAD}.Release|Any CPU.Build.0 = Release|Any CPU
48 | EndGlobalSection
49 | GlobalSection(SolutionProperties) = preSolution
50 | HideSolutionNode = FALSE
51 | EndGlobalSection
52 | GlobalSection(ExtensibilityGlobals) = postSolution
53 | SolutionGuid = {5238B2E8-5295-47DF-B781-F6760E906214}
54 | EndGlobalSection
55 | EndGlobal
56 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/Controllers/ConvertController.cs:
--------------------------------------------------------------------------------
1 | using Asp.Versioning;
2 | using Microsoft.AspNetCore.Mvc;
3 | using UUIDNext;
4 |
5 | namespace Majorsilence.Media.Web.Controllers;
6 |
7 | [Route("api/v{version:apiVersion}/[controller]")]
8 | [ApiController]
9 | [ApiVersion("1.0")]
10 | public class ConvertController : ControllerBase
11 | {
12 | private readonly ILogger _logger;
13 | private readonly Settings _settings;
14 |
15 | public ConvertController(ILogger logger,
16 | Settings settings)
17 | {
18 | _logger = logger;
19 | _settings = settings;
20 | }
21 |
22 | ///
23 | /// Initiate a new file id. This most be called before uploading a file. The returned value
24 | /// must be sent in the Post method as a header with the name "FileId".
25 | ///
26 | ///
27 | public string Get()
28 | {
29 | // The purpose of this method is to permit the client to get a file id
30 | // to track the file upload. This is to prevent a client from uploading
31 | // a file and then not sending the file to be processed. This method
32 | // will create a file in the upload folder with the file id as the name
33 | // and the contents will be the token. The client must send the token
34 | // in the header of the Post method. The token is the bearer token
35 | // from the client.
36 | // The WorkerService will then process the file and delete the file
37 | // after processing. If the file is not processed then the file will
38 | // remain in the upload folder and the client can try again.
39 | var id = Uuid.NewDatabaseFriendly(Database.Other).ToString();
40 | var startRequestPath = Path.Combine(_settings.UploadFolder, $"{id}.startrequest");
41 | System.IO.File.WriteAllText(startRequestPath, GetBearerToken());
42 | return id;
43 | }
44 |
45 | ///
46 | /// Upload a file and return its id.
47 | ///
48 | ///
49 | [HttpPost]
50 | [RequestSizeLimit(107374182400)] // 100 GB
51 | [RequestFormLimits(MultipartBodyLengthLimit = 107374182400)] // 100 GB
52 | public async Task Post(IFormFile file)
53 | {
54 | if (file.Length <= 0) return BadRequest("File is empty");
55 |
56 | var fileid = Request.Headers["FileId"].ToString();
57 | if (string.IsNullOrWhiteSpace(fileid))
58 | {
59 | return BadRequest("The file id must be sent in the header with the name 'FileId'");
60 | }
61 |
62 | if (fileid.Trim().Length != 36)
63 | {
64 | return BadRequest("Invalid file id. Must be retrieved by calling GET.");
65 | }
66 |
67 | var token = GetBearerToken();
68 | var startRequestPath = Path.Combine(_settings.UploadFolder, $"{fileid}.startrequest");
69 | if (!System.IO.File.Exists(startRequestPath))
70 | {
71 | return BadRequest("Invalid file id. Must be retrieved by calling Get.");
72 | }
73 | string startRequestToken = System.IO.File.ReadAllText(startRequestPath);
74 | if (!string.Equals(startRequestToken, token))
75 | {
76 | return BadRequest("Invalid token. Tokens must match between GET and POST requests.");
77 | }
78 |
79 | var ext = Path.GetExtension(file.FileName);
80 | await using var inputStream = new FileStream(Path.Combine(_settings.UploadFolder,
81 | $"{fileid}"),
82 | FileMode.Create);
83 |
84 | var uploadDetailFilePath = Path.Combine(_settings.UploadFolder, $"{fileid}.txt");
85 | await file.CopyToAsync(inputStream);
86 | await System.IO.File.WriteAllTextAsync(uploadDetailFilePath, $"{fileid}{Environment.NewLine}{ext}");
87 |
88 | return Ok(fileid);
89 | }
90 |
91 | private string GetBearerToken()
92 | {
93 | string authorizationHeader = Request.Headers["Authorization"];
94 | string[] parts = authorizationHeader.Split(' ');
95 | string scheme = parts[0];
96 | string token = parts[1];
97 | return token;
98 | }
99 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/Dockerfile:
--------------------------------------------------------------------------------
1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
2 |
3 | FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
4 | WORKDIR /app
5 | EXPOSE 8080
6 | EXPOSE 8443
7 |
8 | FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
9 | WORKDIR /src
10 | COPY ["Majorsilence.Media.Web/Majorsilence.Media.Web.csproj", "Majorsilence.Media.Web/"]
11 | COPY ["Majorsilence.Media.Videos/Majorsilence.Media.Videos.csproj", "Majorsilence.Media.Videos/"]
12 | COPY ["Majorsilence.Media.Images/Majorsilence.Media.Images.csproj", "Majorsilence.Media.Images/"]
13 | RUN dotnet restore "Majorsilence.Media.Web/Majorsilence.Media.Web.csproj"
14 | COPY . .
15 | WORKDIR "/src/Majorsilence.Media.Web"
16 | RUN dotnet build "Majorsilence.Media.Web.csproj" -c Release -o /app/build
17 |
18 | FROM build AS publish
19 | RUN dotnet publish "Majorsilence.Media.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false
20 |
21 | FROM base AS final
22 | WORKDIR /app
23 | COPY --from=publish /app/publish .
24 | # USER app is the default starting with aspnet:8.0 images
25 | # See https://devblogs.microsoft.com/dotnet/running-nonroot-kubernetes-with-dotnet/ and
26 | # https://devblogs.microsoft.com/dotnet/securing-containers-with-rootless/
27 | USER $APP_UID
28 | ENTRYPOINT ["dotnet", "Majorsilence.Media.Web.dll"]
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/JwtSecrets.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.Web;
2 |
3 | public class JwtSettings
4 | {
5 | public string Audience { get; init; }
6 | public string Issuer { get; init; }
7 | public string Secret { get; init; }
8 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/Majorsilence.Media.Web.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 | 261ca7b9-2ec9-4aad-953d-4c84831f78f1
8 | Linux
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Asp.Versioning;
3 | using Majorsilence.Media.Web;
4 | using Microsoft.AspNetCore.Authentication.JwtBearer;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.IdentityModel.Tokens;
7 | using Microsoft.OpenApi.Models;
8 |
9 | var builder = WebApplication.CreateBuilder(args);
10 | builder.Services.AddScoped(s => { return builder.Configuration.GetSection("ApiSettings").Get(); });
11 |
12 | builder.Services.AddCors(options =>
13 | {
14 | options.AddPolicy("AllowSpecificOrigin",
15 | b => b.WithOrigins(builder.Configuration.GetSection("ApiSettings:PermittedCORS").Get())
16 | .AllowAnyHeader()
17 | .AllowAnyMethod());
18 | });
19 | builder.Services.AddControllers();
20 | builder.Services.AddApiVersioning(config =>
21 | {
22 | config.DefaultApiVersion = new ApiVersion(1, 0);
23 | config.AssumeDefaultVersionWhenUnspecified = true;
24 | config.ReportApiVersions = true;
25 | });
26 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
27 | builder.Services.AddEndpointsApiExplorer();
28 | builder.Services.AddSwaggerGen(c =>
29 | {
30 | c.SwaggerDoc("v1", new OpenApiInfo { Title = "Majorsilence.Media.Web", Version = "v1" });
31 | });
32 |
33 | var symmetricSecurityKey =
34 | new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["ApiSettings:Jwt:Secret"]));
35 | builder.Services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; })
36 | .AddJwtBearer(options =>
37 | {
38 | options.SaveToken = true;
39 | options.TokenValidationParameters = new TokenValidationParameters()
40 | {
41 | ValidIssuer = builder.Configuration["ApiSettings:Jwt:Issuer"],
42 | ValidAudience = builder.Configuration["ApiSettings:Jwt:Audience"],
43 | IssuerSigningKey = symmetricSecurityKey
44 | };
45 | });
46 |
47 | builder.Services.AddAuthorization(options =>
48 | {
49 | options.AddPolicy("FileUpload", policy =>
50 | {
51 | policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
52 | policy.RequireAuthenticatedUser();
53 | });
54 | options.DefaultPolicy = options.GetPolicy("FileUpload");
55 | options.FallbackPolicy = options.DefaultPolicy;
56 | });
57 | builder.Services.AddHealthChecks();
58 |
59 | var app = builder.Build();
60 |
61 | // Configure the HTTP request pipeline.
62 | if (app.Environment.IsDevelopment())
63 | {
64 | app.UseSwagger();
65 | app.UseSwaggerUI();
66 | }
67 | app.UseCors("AllowSpecificOrigin");
68 | app.UseHttpsRedirection();
69 |
70 | app.UseAuthentication();
71 | app.UseAuthorization();
72 |
73 | app.MapControllers();
74 | app.MapHealthChecks("/healthz").AllowAnonymous();
75 | app.Run();
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Majorsilence.Media.Web": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "launchUrl": "swagger",
7 | "environmentVariables": {
8 | "ASPNETCORE_ENVIRONMENT": "Development"
9 | },
10 | "dotnetRunMessages": true,
11 | "applicationUrl": "https://localhost:7079;http://localhost:5079"
12 | },
13 | "IIS Express": {
14 | "commandName": "IISExpress",
15 | "launchBrowser": true,
16 | "launchUrl": "swagger",
17 | "environmentVariables": {
18 | "ASPNETCORE_ENVIRONMENT": "Development"
19 | }
20 | },
21 | "Docker": {
22 | "commandName": "Docker",
23 | "launchBrowser": true,
24 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
25 | "publishAllPorts": true,
26 | "useSSL": true
27 | }
28 | },
29 | "$schema": "https://json.schemastore.org/launchsettings.json",
30 | "iisSettings": {
31 | "windowsAuthentication": false,
32 | "anonymousAuthentication": true,
33 | "iisExpress": {
34 | "applicationUrl": "http://localhost:18143",
35 | "sslPort": 44326
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/Settings.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.Web;
2 |
3 | public class Settings
4 | {
5 | public string UploadFolder { get; init; }
6 | public JwtSettings Jwt { get; init; }
7 | public string[] PermittedCORSOrigins { get; init; }
8 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "ApiSettings": {
9 | "UploadFolder": "/home/peter/Downloads/web/uploads",
10 | "PermittedCORS": [
11 | "https://*.majorsilence.com",
12 | "https://localhost:7090",
13 | "http://localhost:5142",
14 | "http://*.majorsilence.local"
15 | ],
16 | "Jwt": {
17 | "Secret": "PLACEHOLDER",
18 | "Issuer": "PLACEHOLDER",
19 | "Audience": "PLACEHOLDER"
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.Web/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*",
9 | "ApiSettings": {
10 | "UploadFolder": "PLACEHOLDER",
11 | "PermittedCORS": [
12 | "https://*.majorsilence.com"
13 | ],
14 | "Jwt":{
15 | "Secret": "PLACEHOLDER",
16 | "Issuer": "PLACEHOLDER",
17 | "Audience": "PLACEHOLDER"
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService.Tests/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using NUnit.Framework;
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService.Tests/Majorsilence.Media.WorkerService.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | PreserveNewest
32 |
33 |
34 |
35 | PreserveNewest
36 |
37 |
38 |
39 | PreserveNewest
40 |
41 |
42 |
43 | PreserveNewest
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/Dockerfile:
--------------------------------------------------------------------------------
1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
2 |
3 | FROM mcr.microsoft.com/dotnet/runtime:9.0 AS base
4 | WORKDIR /app
5 |
6 | FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
7 | WORKDIR /src
8 | COPY ["Majorsilence.Media.WorkerService/Majorsilence.Media.WorkerService.csproj", "Majorsilence.Media.WorkerService/"]
9 | RUN dotnet restore "Majorsilence.Media.WorkerService/Majorsilence.Media.WorkerService.csproj"
10 | COPY . .
11 | WORKDIR "/src/Majorsilence.Media.WorkerService"
12 | RUN dotnet build "Majorsilence.Media.WorkerService.csproj" -c Release -o /app/build
13 |
14 | FROM build AS publish
15 | RUN dotnet publish "Majorsilence.Media.WorkerService.csproj" -c Release -o /app/publish /p:UseAppHost=false
16 |
17 | FROM base AS final
18 | WORKDIR /app
19 | COPY --from=publish /app/publish .
20 | # USER app is the default starting with aspnet:8.0 images
21 | # See https://devblogs.microsoft.com/dotnet/running-nonroot-kubernetes-with-dotnet/ and
22 | # https://devblogs.microsoft.com/dotnet/securing-containers-with-rootless/
23 | USER $APP_UID
24 | ENTRYPOINT ["dotnet", "Majorsilence.Media.WorkerService.dll"]
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/Majorsilence.Media.WorkerService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 | dotnet-Majorsilence.Media.WorkerService-52B482C9-8D3F-4035-B060-C4C8FD36EE67
8 | Linux
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/Program.cs:
--------------------------------------------------------------------------------
1 | using Majorsilence.Media.Videos;
2 | using Majorsilence.Media.WorkerService;
3 |
4 | var host = Host.CreateDefaultBuilder(args)
5 | .ConfigureServices(services =>
6 | {
7 | services.AddSingleton(s =>
8 | {
9 | return s.GetService()
10 | .GetSection("ApiSettings")
11 | .Get();
12 | });
13 |
14 | services.AddSingleton(s => { return new Ffmpeg(s.GetService().FfmpegPath); });
15 |
16 | services.AddHostedService();
17 | })
18 | .Build();
19 |
20 | await host.RunAsync();
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Majorsilence.Media.WorkerService": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | },
8 | "dotnetRunMessages": true
9 | },
10 | "Docker": {
11 | "commandName": "Docker"
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/Settings.cs:
--------------------------------------------------------------------------------
1 | using Majorsilence.Media.Videos;
2 |
3 | namespace Majorsilence.Media.WorkerService;
4 |
5 | public class Settings
6 | {
7 | public string UploadFolder { get; init; }
8 | public string MEncoderPath { get; init; }
9 | public string ConvertedFolder { get; init; }
10 | public string FfmpegPath { get; init; }
11 | ///
12 | /// Valid ConversionType values are "streaming", "download", "all"
13 | ///
14 | public string ConversionType { get; init; }
15 | public VideoAspectRatios[] AspectRatios { get; init; }
16 | public Dictionary VideoAudioConverters { get; init; }
17 | public Dictionary VideoFileExtension { get; init; }
18 | public StreamTypes StreamTypes { get; init; }
19 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/StreamTypes.cs:
--------------------------------------------------------------------------------
1 | namespace Majorsilence.Media.WorkerService;
2 |
3 | public class StreamTypes
4 | {
5 | public string MpegDash { get; init; }
6 | public string Hls { get; init; }
7 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/Worker.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Majorsilence.Media.Videos;
3 |
4 | namespace Majorsilence.Media.WorkerService;
5 |
6 | public class Worker : BackgroundService
7 | {
8 | private readonly ILogger _logger;
9 | private readonly Settings _settings;
10 | private readonly IVideoEncoder _videoEncoder;
11 |
12 | public Worker(ILogger logger, IVideoEncoder videoEncoder, Settings settings)
13 | {
14 | _logger = logger;
15 | _videoEncoder = videoEncoder;
16 | _settings = settings;
17 | }
18 |
19 | protected override async Task ExecuteAsync(CancellationToken stoppingToken)
20 | {
21 | int countNothingToDo = 0;
22 | while (!stoppingToken.IsCancellationRequested)
23 | {
24 | _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
25 | string extraConvertedSubFolder = System.IO.Path.Combine(_settings.ConvertedFolder,
26 | DateTime.UtcNow.Year.ToString(),
27 | DateTime.UtcNow.Month.ToString(), DateTime.UtcNow.Day.ToString());
28 | var x = new TranscodingManager(_videoEncoder, _settings);
29 | int transcodingCount = await x.Transcode(extraConvertedSubFolder, stoppingToken);
30 | if (transcodingCount == 0)
31 | {
32 | countNothingToDo++;
33 | if (countNothingToDo > 60)
34 | {
35 | await Task.Delay(60000, stoppingToken);
36 | continue;
37 | }
38 |
39 | await Task.Delay(1000 * countNothingToDo, stoppingToken);
40 | }
41 | else
42 | {
43 | countNothingToDo = 0;
44 | }
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.Hosting.Lifetime": "Information"
6 | }
7 | },
8 | "ApiSettings": {
9 | "UploadFolder": "/home/peter/Downloads/web/uploads",
10 | "ConvertedFolder": "/home/peter/Downloads/web/output",
11 | "MEncoderPath": "/usr/bin/mencoder",
12 | "FfmpegPath": "/usr/bin/ffmpeg",
13 | "AspectRatios": [
14 | "original",
15 | "p720",
16 | "p480",
17 | "p360",
18 | "p240"
19 | ],
20 | "VideoAudioConverters": {
21 | "vp9": "opus",
22 | "x264": "aac",
23 | "x265": "aac"
24 | },
25 | "VideoFileExtension": {
26 | "vp9": "webm",
27 | "x264": "mp4",
28 | "x265": "mp4"
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Majorsilence.Media.WorkerService/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.Hosting.Lifetime": "Information"
6 | }
7 | },
8 | "ApiSettings": {
9 | "UploadFolder": "PLACEHOLDER, should match upload folder in Majorsilence.Media.Web",
10 | "ConvertedFolder": "PLACEHOLDER, location that converted videos should be saved",
11 | "MEncoderPath": "mencoder",
12 | "FfmpegPath": "/usr/bin/ffmpeg",
13 | // Valid ConversionTypes are "streaming", "download", or "all"
14 | "ConversionType": "streaming",
15 | "AspectRatios": [
16 | "original",
17 | //"p7680",
18 | //"p2160",
19 | //"p1440,",
20 | "p1080",
21 | "p720",
22 | "p480",
23 | "p360",
24 | "p240"
25 | ],
26 | "VideoAudioConverters": {
27 | //"av1": "opus",
28 | "vp9": "opus",
29 | "x264": "aac"
30 | //"x265": "aac"
31 | },
32 | "VideoFileExtension": {
33 | "av1": "mkv",
34 | "vp9": "webm",
35 | "x264": "mp4",
36 | "x265": "mp4"
37 | },
38 | "StreamingTypes": {
39 | "MpegDash": "-i [PLACEHOLDER_INPUT] -map 0:v -map 0:a -s:v:0 426x240 -c:v:0 libx264 -b:v:0 250k -s:v:1 640x360 -c:v:1 libx264 -b:v:1 800k -s:v:2 854x480 -c:v:2 libx264 -b:v:2 1400k -s:v:3 1280x720 -c:v:3 libx264 -b:v:3 2800k -s:v:4 1920x1080 -c:v:4 libx264 -b:v:4 5000k -s:v:5 3840x2160 -c:v:5 libx264 -b:v:5 14000k -s:v:6 426x240 -c:v:6 libvpx-vp9 -b:v:6 250k -s:v:7 640x360 -c:v:7 libvpx-vp9 -b:v:7 800k -s:v:8 854x480 -c:v:8 libvpx-vp9 -b:v:8 1400k -s:v:9 1280x720 -c:v:9 libvpx-vp9 -b:v:9 2800k -s:v:10 1920x1080 -c:v:10 libvpx-vp9 -b:v:10 5000k -s:v:11 3840x2160 -c:v:11 libvpx-vp9 -b:v:11 14000k -c:a aac -b:a 128k -var_stream_map \"v:0,a:0 v:1,a:0 v:2,a:0 v:3,a:0 v:4,a:0 v:5,a:0 v:6,a:0 v:7,a:0 v:8,a:0 v:9,a:0 v:10,a:0 v:11,a:0\" -f dash -use_template 1 -use_timeline 1 -adaptation_sets \"id=0,streams=v id=1,streams=a\" [PLACEHOLDER_OUTPUT].mpd",
40 | "Hls": "-i [PLACEHOLDER_INPUT] -map 0:v -map 0:a -s:v:0 426x240 -c:v:0 libx264 -b:v:0 250k -s:v:1 640x360 -c:v:1 libx264 -b:v:1 800k -s:v:2 854x480 -c:v:2 libx264 -b:v:2 1400k -s:v:3 1280x720 -c:v:3 libx264 -b:v:3 2800k -s:v:4 1920x1080 -c:v:4 libx264 -b:v:4 5000k -s:v:5 3840x2160 -c:v:5 libx264 -b:v:5 14000k -c:a aac -b:a 128k -hls_time 4 -hls_playlist_type vod -hls_segment_filename [PLACEHOLDER_OUTPUT]_%03d.ts [PLACEHOLDER_OUTPUT].m3u8"
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Majorsilence.Winforms.MPlayerControl.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32630.192
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Videos", "Majorsilence.Media.Videos\Majorsilence.Media.Videos.csproj", "{5D3616D0-160D-4601-AB67-E1ED9111C676}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.NunitTests", "Majorsilence.Media.NunitTests\Majorsilence.Media.NunitTests.csproj", "{F8A7EE08-6BEA-4CB4-A0BA-22169133289A}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaPlayer", "MediaPlayer\MediaPlayer.csproj", "{AFF738E9-1179-4E9D-A803-1CA5CB5499D1}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SlideShow", "SlideShow\SlideShow.csproj", "{6B5C1B79-1CDF-409C-8CAF-B3D2F25E27B5}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Images", "Majorsilence.Media.Images\Majorsilence.Media.Images.csproj", "{C859FA27-7882-4814-9202-9C9D807C2CE5}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibMPlayerWinform", "LibMPlayerWinform\LibMPlayerWinform.csproj", "{994F562F-B694-4799-B1D6-C90A290FEF2B}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{FAF8DCB0-403C-4120-A70C-89DD942564A9}"
19 | EndProject
20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Majorsilence.Media.Desktop.UI", "Majorsilence.Media.Desktop.UI\Majorsilence.Media.Desktop.UI.csproj", "{E8077661-DF84-4373-8D69-32F1684EEFA3}"
21 | EndProject
22 | Global
23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
24 | Debug|Any CPU = Debug|Any CPU
25 | Release|Any CPU = Release|Any CPU
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {5D3616D0-160D-4601-AB67-E1ED9111C676}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {F8A7EE08-6BEA-4CB4-A0BA-22169133289A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {F8A7EE08-6BEA-4CB4-A0BA-22169133289A}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {F8A7EE08-6BEA-4CB4-A0BA-22169133289A}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {F8A7EE08-6BEA-4CB4-A0BA-22169133289A}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {AFF738E9-1179-4E9D-A803-1CA5CB5499D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {AFF738E9-1179-4E9D-A803-1CA5CB5499D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {AFF738E9-1179-4E9D-A803-1CA5CB5499D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {AFF738E9-1179-4E9D-A803-1CA5CB5499D1}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {6B5C1B79-1CDF-409C-8CAF-B3D2F25E27B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {6B5C1B79-1CDF-409C-8CAF-B3D2F25E27B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {6B5C1B79-1CDF-409C-8CAF-B3D2F25E27B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {6B5C1B79-1CDF-409C-8CAF-B3D2F25E27B5}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {C859FA27-7882-4814-9202-9C9D807C2CE5}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {994F562F-B694-4799-B1D6-C90A290FEF2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {994F562F-B694-4799-B1D6-C90A290FEF2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {994F562F-B694-4799-B1D6-C90A290FEF2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {994F562F-B694-4799-B1D6-C90A290FEF2B}.Release|Any CPU.Build.0 = Release|Any CPU
52 | {FAF8DCB0-403C-4120-A70C-89DD942564A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
53 | {FAF8DCB0-403C-4120-A70C-89DD942564A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
54 | {FAF8DCB0-403C-4120-A70C-89DD942564A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 | {FAF8DCB0-403C-4120-A70C-89DD942564A9}.Release|Any CPU.Build.0 = Release|Any CPU
56 | {E8077661-DF84-4373-8D69-32F1684EEFA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
57 | {E8077661-DF84-4373-8D69-32F1684EEFA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
58 | {E8077661-DF84-4373-8D69-32F1684EEFA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
59 | {E8077661-DF84-4373-8D69-32F1684EEFA3}.Release|Any CPU.Build.0 = Release|Any CPU
60 | EndGlobalSection
61 | GlobalSection(SolutionProperties) = preSolution
62 | HideSolutionNode = FALSE
63 | EndGlobalSection
64 | GlobalSection(ExtensibilityGlobals) = postSolution
65 | SolutionGuid = {581875EC-8089-45E4-853B-789F5E7991E9}
66 | EndGlobalSection
67 | GlobalSection(MonoDevelopProperties) = preSolution
68 | StartupItem = MediaPlayer\MediaPlayer.csproj
69 | EndGlobalSection
70 | EndGlobal
71 |
--------------------------------------------------------------------------------
/src/MediaPlayer/MediaPlayer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 | net6.0-windows;net8.0-windows;net9.0-windows
5 | enable
6 | true
7 | enable
8 | MediaPlayer.Program
9 | MediaPlayer
10 |
11 |
12 | bin\$(Configuration)\
13 | Full
14 | True
15 |
16 |
17 | bin\$(Configuration)\
18 | None
19 |
20 |
21 | -path "/usr/bin/mplayer"
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | -path "/usr/bin/mplayer"
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Form
39 |
40 |
41 | PlayerProperties.cs
42 |
43 |
44 | Form
45 |
46 |
47 | Player.cs
48 |
49 |
50 | True
51 | True
52 | Resources.resx
53 |
54 |
55 | True
56 | True
57 | Settings.settings
58 |
59 |
60 |
61 |
62 | Player.cs
63 |
64 |
65 | PlayerProperties.cs
66 |
67 |
68 | ResXFileCodeGenerator
69 | Resources.Designer.cs
70 | Designer
71 |
72 |
73 |
74 |
75 | SettingsSingleFileGenerator
76 | Settings.Designer.cs
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/src/MediaPlayer/PlayerProperties.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MediaPlayer
2 | {
3 | partial class PlayerProperties
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.label1 = new System.Windows.Forms.Label();
32 | this.textBox1 = new System.Windows.Forms.TextBox();
33 | this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
34 | this.btnMPlayerPath = new System.Windows.Forms.Button();
35 | this.statusStrip1 = new System.Windows.Forms.StatusStrip();
36 | this.lblStatus = new System.Windows.Forms.ToolStripStatusLabel();
37 | this.btnSave = new System.Windows.Forms.Button();
38 | this.statusStrip1.SuspendLayout();
39 | this.SuspendLayout();
40 | //
41 | // label1
42 | //
43 | this.label1.AutoSize = true;
44 | this.label1.Location = new System.Drawing.Point(14, 15);
45 | this.label1.Name = "label1";
46 | this.label1.Size = new System.Drawing.Size(73, 13);
47 | this.label1.TabIndex = 0;
48 | this.label1.Text = "MPlayer/libmpv Path:";
49 | //
50 | // textBox1
51 | //
52 | this.textBox1.Location = new System.Drawing.Point(93, 12);
53 | this.textBox1.Name = "textBox1";
54 | this.textBox1.Size = new System.Drawing.Size(403, 20);
55 | this.textBox1.TabIndex = 1;
56 | //
57 | // openFileDialog1
58 | //
59 | this.openFileDialog1.FileName = "openFileDialog1";
60 | //
61 | // btnMPlayerPath
62 | //
63 | this.btnMPlayerPath.Location = new System.Drawing.Point(504, 9);
64 | this.btnMPlayerPath.Name = "btnMPlayerPath";
65 | this.btnMPlayerPath.Size = new System.Drawing.Size(114, 23);
66 | this.btnMPlayerPath.TabIndex = 2;
67 | this.btnMPlayerPath.Text = "Select MPlayer/libmpv Path";
68 | this.btnMPlayerPath.UseVisualStyleBackColor = true;
69 | this.btnMPlayerPath.Click += new System.EventHandler(this.btnMPlayerPath_Click);
70 | //
71 | // statusStrip1
72 | //
73 | this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[]
74 | {
75 | this.lblStatus
76 | });
77 | this.statusStrip1.Location = new System.Drawing.Point(0, 106);
78 | this.statusStrip1.Name = "statusStrip1";
79 | this.statusStrip1.Size = new System.Drawing.Size(630, 22);
80 | this.statusStrip1.TabIndex = 3;
81 | this.statusStrip1.Text = "statusStrip1";
82 | //
83 | // lblStatus
84 | //
85 | this.lblStatus.Name = "lblStatus";
86 | this.lblStatus.Size = new System.Drawing.Size(0, 17);
87 | //
88 | // btnSave
89 | //
90 | this.btnSave.Location = new System.Drawing.Point(504, 80);
91 | this.btnSave.Name = "btnSave";
92 | this.btnSave.Size = new System.Drawing.Size(114, 23);
93 | this.btnSave.TabIndex = 4;
94 | this.btnSave.Text = "Save";
95 | this.btnSave.UseVisualStyleBackColor = true;
96 | this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
97 | //
98 | // PlayerProperties
99 | //
100 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
101 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
102 | this.ClientSize = new System.Drawing.Size(630, 128);
103 | this.Controls.Add(this.btnSave);
104 | this.Controls.Add(this.statusStrip1);
105 | this.Controls.Add(this.btnMPlayerPath);
106 | this.Controls.Add(this.textBox1);
107 | this.Controls.Add(this.label1);
108 | this.Name = "PlayerProperties";
109 | this.Text = "Player Properties";
110 | this.Load += new System.EventHandler(this.PlayerProperties_Load);
111 | this.statusStrip1.ResumeLayout(false);
112 | this.statusStrip1.PerformLayout();
113 | this.ResumeLayout(false);
114 | this.PerformLayout();
115 |
116 | }
117 |
118 | #endregion
119 |
120 | private System.Windows.Forms.Label label1;
121 | private System.Windows.Forms.TextBox textBox1;
122 | private System.Windows.Forms.OpenFileDialog openFileDialog1;
123 | private System.Windows.Forms.Button btnMPlayerPath;
124 | private System.Windows.Forms.StatusStrip statusStrip1;
125 | private System.Windows.Forms.ToolStripStatusLabel lblStatus;
126 | private System.Windows.Forms.Button btnSave;
127 | }
128 | }
--------------------------------------------------------------------------------
/src/MediaPlayer/PlayerProperties.cs:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2012 (C) Peter Gill
3 |
4 | This file is part of MediaPlayer.
5 |
6 | MediaPlayer is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | MediaPlayer is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.ComponentModel;
23 | using System.Data;
24 | using System.Drawing;
25 | using System.Linq;
26 | using System.Text;
27 | using System.Windows.Forms;
28 |
29 | namespace MediaPlayer
30 | {
31 | public partial class PlayerProperties : Form
32 | {
33 | public PlayerProperties()
34 | {
35 | InitializeComponent();
36 | }
37 |
38 | private void PlayerProperties_Load(object sender, EventArgs e)
39 | {
40 | textBox1.Text = MediaPlayer.Properties.Settings.Default.MPlayerPath;
41 | }
42 |
43 | private void btnMPlayerPath_Click(object sender, EventArgs e)
44 | {
45 | if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
46 | {
47 | textBox1.Text = openFileDialog1.FileName;
48 | }
49 | }
50 |
51 | private void btnSave_Click(object sender, EventArgs e)
52 | {
53 | MediaPlayer.Properties.Settings.Default.MPlayerPath = textBox1.Text.Trim();
54 | MediaPlayer.Properties.Settings.Default.Save();
55 | }
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/MediaPlayer/Program.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2010 (C) Peter Gill
4 |
5 | This file is part of MediaPlayer.
6 |
7 | MediaPlayer is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | MediaPlayer is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 |
23 | using System;
24 | using System.Windows.Forms;
25 |
26 | namespace MediaPlayer
27 | {
28 | ///
29 | /// Class with program entry point.
30 | ///
31 | internal sealed class Program
32 | {
33 | ///
34 | /// Program entry point.
35 | ///
36 | [STAThread]
37 | private static void Main(string[] args)
38 | {
39 |
40 | string path = "";
41 | for (int i = 0; i <= Environment.GetCommandLineArgs().Length - 1; i++)
42 | {
43 | if (Environment.GetCommandLineArgs()[i] == "-path")
44 | {
45 | path = Environment.GetCommandLineArgs()[i + 1].Trim();
46 | }
47 | }
48 |
49 | if (!string.IsNullOrWhiteSpace(path))
50 | {
51 | MediaPlayer.Properties.Settings.Default.MPlayerPath = path;
52 | MediaPlayer.Properties.Settings.Default.Save();
53 | }
54 |
55 | Application.EnableVisualStyles();
56 | Application.SetCompatibleTextRenderingDefault(false);
57 | Application.Run(new Player("", false, false));
58 | }
59 |
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/MediaPlayer/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.1
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace MediaPlayer.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.UserScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("")]
29 | public string MPlayerPath {
30 | get {
31 | return ((string)(this["MPlayerPath"]));
32 | }
33 | set {
34 | this["MPlayerPath"] = value;
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/MediaPlayer/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/audio-volume-medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/audio-volume-medium.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/audio-volume-muted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/audio-volume-muted.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/config.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/document-open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/document-open.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/fastforward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/fastforward.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/pause.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/play.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/rewind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/rewind.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/stop.png
--------------------------------------------------------------------------------
/src/MediaPlayer/Resources/volume-down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majorsilence/MPlayerControl/ce94a55853a4f16a89e9090a1dacddcb03851324/src/MediaPlayer/Resources/volume-down.png
--------------------------------------------------------------------------------
/src/MediaPlayer/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/SlideShow/Program.cs:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright 2011 (C) Peter Gill
4 |
5 | This file is part of SlideShow.
6 |
7 | SlideShow is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation; either version 2 of the License, or
10 | (at your option) any later version.
11 |
12 | SlideShow is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | */
21 |
22 | using System;
23 | using System.Collections.Generic;
24 | using System.Linq;
25 | using System.Windows.Forms;
26 |
27 | namespace SlideShow
28 | {
29 | static class Program
30 | {
31 | ///
32 | /// The main entry point for the application.
33 | ///
34 | [STAThread]
35 | static void Main()
36 | {
37 | Application.EnableVisualStyles();
38 | Application.SetCompatibleTextRenderingDefault(false);
39 | Application.Run(new MainForm());
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/SlideShow/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace SlideShow.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SlideShow.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/SlideShow/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/SlideShow/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.235
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace SlideShow.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/SlideShow/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/SlideShow/SlideShow.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | x86
4 | WinExe
5 | net6.0-windows;net8.0-windows;net9.0-windows
6 | enable
7 | true
8 | enable
9 | SlideShow.Program
10 | SlideShow
11 |
12 |
13 | full
14 |
15 |
16 | pdbonly
17 |
18 |
19 | full
20 | bin\Debug\SlideShow.exe.CodeAnalysisLog.xml
21 | true
22 | GlobalSuppressions.cs
23 | MinimumRecommendedRules.ruleset
24 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
25 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
26 | false
27 |
28 |
29 | pdbonly
30 | bin\Release\SlideShow.exe.CodeAnalysisLog.xml
31 | true
32 | GlobalSuppressions.cs
33 | MinimumRecommendedRules.ruleset
34 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
35 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
36 | false
37 |
38 |
39 |
40 | Form
41 |
42 |
43 | MainForm.cs
44 |
45 |
46 | MainForm.cs
47 |
48 |
49 | ResXFileCodeGenerator
50 | Resources.Designer.cs
51 | Designer
52 |
53 |
54 | True
55 | Resources.resx
56 | True
57 |
58 |
59 | SettingsSingleFileGenerator
60 | Settings.Designer.cs
61 |
62 |
63 | True
64 | Settings.settings
65 | True
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/src/SlideShow/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Test/Form1.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Test
2 | {
3 | partial class Form1
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.winFormMPlayerControl1 = new LibMPlayerWinform.WinFormMPlayerControl();
32 | this.SuspendLayout();
33 | //
34 | // winFormMPlayerControl1
35 | //
36 | this.winFormMPlayerControl1.Dock = System.Windows.Forms.DockStyle.Fill;
37 | this.winFormMPlayerControl1.Location = new System.Drawing.Point(0, 0);
38 | this.winFormMPlayerControl1.MPlayerPath = null;
39 | this.winFormMPlayerControl1.Name = "winFormMPlayerControl1";
40 | this.winFormMPlayerControl1.Size = new System.Drawing.Size(944, 572);
41 | this.winFormMPlayerControl1.TabIndex = 0;
42 | this.winFormMPlayerControl1.VideoPath = null;
43 | this.winFormMPlayerControl1.Load += new System.EventHandler(this.winFormMPlayerControl1_Load);
44 | //
45 | // Form1
46 | //
47 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
49 | this.ClientSize = new System.Drawing.Size(944, 572);
50 | this.Controls.Add(this.winFormMPlayerControl1);
51 | this.Name = "Form1";
52 | this.Text = "Form1";
53 | this.ResumeLayout(false);
54 |
55 | }
56 |
57 | #endregion
58 |
59 | private LibMPlayerWinform.WinFormMPlayerControl winFormMPlayerControl1;
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/src/Test/Form1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Windows.Forms;
9 |
10 | namespace Test
11 | {
12 | public partial class Form1 : Form
13 | {
14 | public Form1()
15 | {
16 | InitializeComponent();
17 | }
18 |
19 | private void winFormMPlayerControl1_Load(object sender, EventArgs e)
20 | {
21 | var player = Majorsilence.Media.Videos.PlayerFactory.Get(winFormMPlayerControl1.Handle, "/usr/bin/mplayer");
22 | winFormMPlayerControl1.SetPlayer(player);
23 | winFormMPlayerControl1.MPlayerPath = @"/usr/bin/mplayer";
24 | winFormMPlayerControl1.VideoPath = @"/home/peter/Downloads/20200717_183033.mp4";
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Test/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Windows.Forms;
5 |
6 | namespace Test
7 | {
8 | static class Program
9 | {
10 | ///
11 | /// The main entry point for the application.
12 | ///
13 | [STAThread]
14 | static void Main()
15 | {
16 | Application.EnableVisualStyles();
17 | Application.SetCompatibleTextRenderingDefault(false);
18 | Application.Run(new Form1());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Test/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Test.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Test.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Test/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/Test/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.239
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Test.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Test/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Test/Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | x86
4 | WinExe
5 | net6.0-windows;net8.0-windows;net9.0-windows
6 | enable
7 | true
8 | enable
9 | Test
10 |
11 |
12 | full
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | pdbonly
21 |
22 |
23 | Test.Test2
24 |
25 |
26 | full
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | pdbonly
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Form1.cs
45 |
46 |
47 | Form1.cs
48 |
49 |
50 | ResXFileCodeGenerator
51 | Resources.Designer.cs
52 | Designer
53 |
54 |
55 | True
56 | Resources.resx
57 |
58 |
59 | SettingsSingleFileGenerator
60 | Settings.Designer.cs
61 |
62 |
63 | True
64 | Settings.settings
65 | True
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/Test/Test2.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Windows.Forms;
4 | using Majorsilence.Media.Videos;
5 |
6 |
7 | namespace Test
8 | {
9 | static class Test2
10 | {
11 | [STAThread]
12 | static void Main()
13 | {
14 |
15 | var player = Majorsilence.Media.Videos.PlayerFactory.Get(-1, "/usr/lib/x86_64-linux-gnu/libmpv.so.1");
16 |
17 |
18 | System.Windows.Forms.Form frm = new System.Windows.Forms.Form();
19 | frm.Height = 600;
20 | frm.Width = 800;
21 |
22 | var playerControl = new LibMPlayerWinform.WinFormMPlayerControl(player);
23 | player.SetHandle(playerControl.Handle);
24 | playerControl.Dock = DockStyle.Fill;
25 |
26 | //playerControl.MPlayerPath = @"C:\path\to\mplayer.exe";
27 | playerControl.VideoPath = @"/home/peter/Downloads/Die Hard 2 (1990) [1080p] {5.1}/Die.Hard.2.BluRay.1080p.x264.5.1.Judas.mp4";
28 |
29 | frm.Controls.Add(playerControl);
30 |
31 | Application.Run(frm);
32 | }
33 | }
34 |
35 |
36 | }
--------------------------------------------------------------------------------