├── .clang-format ├── .gitattributes ├── .github └── workflows │ └── msbuild.yml ├── .gitignore ├── .gitmodules ├── Anime4KCPPCore.vcxproj ├── Anime4KCPPCore.vcxproj.filters ├── Dlls └── Dlls.csproj ├── HttpDownload ├── HttpDownload.cpp ├── HttpDownload.vcxproj ├── HttpDownload.vcxproj.filters ├── ReadMe.txt ├── stdafx.cpp ├── stdafx.h └── targetver.h ├── LICENSE ├── Player.sln ├── Player ├── AsyncGetUrlUnderMouseCursor.cpp ├── AsyncGetUrlUnderMouseCursor.h ├── ByteStreamBuffer.h ├── D3DFONT.CPP ├── D3DFONT.H ├── DialogBarPlayerControl.cpp ├── DialogBarPlayerControl.h ├── DialogBarRange.cpp ├── DialogBarRange.h ├── DialogOpenURL.cpp ├── DialogOpenURL.h ├── EditTime.cpp ├── EditTime.h ├── FrameToHglobal.cpp ├── FrameToHglobal.h ├── GetClipboardText.h ├── HandleFilesSequence.cpp ├── HandleFilesSequence.h ├── I420Effect.cpp ├── I420Effect.h ├── I420Effect_PS.hlsl ├── IEraseableArea.h ├── ImageUpscale.cpp ├── ImageUpscale.h ├── MainFrm.cpp ├── MainFrm.h ├── MakeDelegate.h ├── MemoryMappedFile.h ├── OpenSubtitlesFile.cpp ├── OpenSubtitlesFile.h ├── Player.cpp ├── Player.h ├── Player.rc ├── Player.vcxproj ├── Player.vcxproj.filters ├── PlayerDoc.cpp ├── PlayerDoc.h ├── PlayerView.cpp ├── PlayerView.h ├── PlayerViewD2D.cpp ├── PlayerViewD2D.h ├── ReadMe.txt ├── SecondsToString.h ├── StringDifference.cpp ├── StringDifference.h ├── YouTuber.cpp ├── YouTuber.h ├── res │ ├── Player.ico │ ├── Player.rc2 │ ├── PlayerDoc.ico │ ├── Toolbar.bmp │ ├── audio.ico │ ├── audio_off.ico │ ├── full_screen.ico │ ├── launch.mkv │ ├── pause.ico │ └── play.ico ├── resource.h ├── stdafx.cpp ├── stdafx.h ├── targetver.h └── update_version.cmd ├── QtPlayer ├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── customdockwidget.cpp ├── customdockwidget.h ├── ffmpegdecoder.cpp ├── ffmpegdecoder.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── mousehoverbutton.cpp ├── mousehoverbutton.h ├── opengldisplay.cpp ├── opengldisplay.h ├── portaudioplayer.cpp ├── portaudioplayer.h ├── resources │ ├── images │ │ ├── control │ │ │ ├── icodelete.png │ │ │ ├── icoplay.png │ │ │ ├── player___btn_globe___click___(31x31).png │ │ │ ├── player___btn_globe___default___(31x31).png │ │ │ ├── player___btn_globe___hover___(31x31).png │ │ │ ├── player___btn_pause___clicked___(40x31).png │ │ │ ├── player___btn_pause___default___(40x31).png │ │ │ ├── player___btn_pause___hover___(40x31).png │ │ │ ├── player___btn_play___clicked___(40x31).png │ │ │ ├── player___btn_play___default___(40x31).png │ │ │ ├── player___btn_play___hover___(40x31).png │ │ │ ├── player___btn_sound_off___clicked___(31x31).png │ │ │ ├── player___btn_sound_off___default___(31x31).png │ │ │ ├── player___btn_sound_off___hover___(31x31).png │ │ │ ├── player___btn_sound_on___clicked___(31x31).png │ │ │ ├── player___btn_sound_on___default___(31x31).png │ │ │ ├── player___btn_sound_on___hover___(31x31).png │ │ │ ├── player___btn_stop___clicked___(31x31).png │ │ │ ├── player___btn_stop___default___(31x31).png │ │ │ ├── player___btn_stop___hover___(31x31).png │ │ │ ├── player_bg___(230x41).png │ │ │ └── player_bg_fs___(230x41).png │ │ ├── help41.png │ │ ├── play_transparent.png │ │ ├── spinner.gif │ │ ├── style │ │ │ ├── box-shadow.png │ │ │ ├── busy.png │ │ │ ├── button-blank.png │ │ │ ├── button_disable.png │ │ │ ├── button_down.png │ │ │ ├── button_hover.png │ │ │ ├── button_normal.png │ │ │ ├── circle-shadow.png │ │ │ ├── down_arrow.png │ │ │ ├── down_arrow_grey.png │ │ │ ├── floatpanel.png │ │ │ ├── header_arrow_down.png │ │ │ ├── header_line.png │ │ │ ├── lineedit.png │ │ │ ├── progress_dropdown.png │ │ │ ├── scroll-button-down-hover.png │ │ │ ├── scroll-button-down.png │ │ │ ├── scroll-button-left-hover.png │ │ │ ├── scroll-button-left.png │ │ │ ├── scroll-button-right-hover.png │ │ │ ├── scroll-button-right.png │ │ │ ├── scroll-button-up-hover.png │ │ │ ├── scroll-button-up.png │ │ │ ├── scroll-hhandle-hover.png │ │ │ ├── scroll-hhandle.png │ │ │ ├── scroll-vhandle-hover.png │ │ │ ├── scroll-vhandle.png │ │ │ └── tooltip-background.png │ │ ├── triangle_down.png │ │ ├── triangle_right.png │ │ ├── video___btn_play___clicked___(94x94).png │ │ ├── video___btn_play___default___(94x94).png │ │ ├── video___btn_play___hover___(94x94).png │ │ └── video_seek_cursor.png │ ├── qt.conf │ ├── resources.qrc │ ├── style.css │ ├── win7.manifest │ └── winres.rc.in ├── videocontrol.cpp ├── videocontrol.h ├── videocontrol.ui ├── videodisplay.cpp ├── videodisplay.h ├── videoplayer.cpp ├── videoplayer.h ├── videoplayerwidget.cpp ├── videoplayerwidget.h ├── videoprogressbar.cpp ├── videoprogressbar.h ├── videowidget.cpp ├── videowidget.h ├── volumeprogressbar.cpp ├── volumeprogressbar.h ├── widgetdisplay.cpp └── widgetdisplay.h ├── README.md ├── Setup ├── Setup.vdproj └── python-embed-win32.7z ├── ThirdParty └── include │ ├── cmdline │ └── cmdline.hpp │ ├── ini17 │ └── ini17.hpp │ └── opencl │ └── CL │ └── opencl.hpp ├── ToUTF8 ├── ToUTF8.cpp ├── ToUTF8.vcxproj └── ToUTF8.vcxproj.filters ├── audio ├── AudioPitchDecorator.cpp ├── AudioPitchDecorator.h ├── AudioPlayerImpl.cpp ├── AudioPlayerImpl.h ├── AudioPlayerWasapi.cpp ├── AudioPlayerWasapi.h ├── ReadMe.txt ├── audio.vcxproj ├── audio.vcxproj.filters ├── smbPitchShift.cpp └── smbPitchShift.h ├── core └── ac_export.h ├── edit_git_subst_cfg.cmd ├── ffmpeg-3.3.3-experimental-patch ├── common.before.h ├── common.h ├── hevcdsp_template.before.c └── hevcdsp_template.c ├── ffmpeg-4.3.2-experimental-patch ├── common.before.h ├── common.h ├── hevcdsp_template.before.c └── hevcdsp_template.c ├── networking ├── ReadMe.txt ├── crypt.h ├── http_download.cpp ├── http_download.h ├── http_get.cpp ├── http_get.h ├── httpioapi.cpp ├── httprequest_h.h ├── httprequest_i.c ├── ioapi.h ├── networking.vcxproj ├── networking.vcxproj.filters ├── unzip.c └── unzip.h ├── remove_pytube.cmd ├── remove_youtube_transcript_api.cmd └── video ├── audioparserunnable.cpp ├── audioplayer.h ├── decoderinterface.h ├── decoderiocontext.cpp ├── decoderiocontext.h ├── displayrunnable.cpp ├── ffmpeg_dxva2.cpp ├── ffmpeg_dxva2.h ├── ffmpegdecoder.cpp ├── ffmpegdecoder.h ├── fqueue.h ├── interlockedadd.h ├── makeguard.h ├── parserunnable.cpp ├── subtitles.cpp ├── subtitles.h ├── video.vcxproj ├── video.vcxproj.filters ├── videoframe.h ├── videoparserunnable.cpp └── vqueue.h /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | UseTab: Never 3 | IndentWidth: 4 4 | BreakBeforeBraces: Allman 5 | AllowShortIfStatementsOnASingleLine: false 6 | IndentCaseLabels: false 7 | ColumnLimit: 99 8 | IndentAccessModifiers: false 9 | AccessModifierOffset: -4 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: MSBuild 7 | 8 | on: 9 | workflow_dispatch: 10 | 11 | env: 12 | # Path to the solution file relative to the root of the project. 13 | SOLUTION_FILE_PATH: ./Player.sln 14 | 15 | # Configuration type to build. 16 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 17 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 18 | BUILD_CONFIGURATION: Release 19 | # https://learn.microsoft.com/en-us/vcpkg/consume/binary-caching-github-actions-cache?source=recommendations 20 | VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" 21 | 22 | 23 | jobs: 24 | build: 25 | runs-on: windows-latest 26 | 27 | strategy: 28 | matrix: 29 | platform: [x86, x64] 30 | 31 | steps: 32 | - uses: actions/checkout@v4 33 | with: 34 | submodules: true # Ensure submodules are checked out 35 | 36 | - name: Create Directory.Build.props 37 | run: | 38 | $content = "10.0.22621.0v4.6.2v143" 39 | $filePath = "./Directory.Build.props" 40 | Set-Content -Path $filePath -Value $content 41 | 42 | - name: Add MSBuild to PATH 43 | id: setup-msbuild 44 | uses: microsoft/setup-msbuild@v2 45 | 46 | - name: Export GitHub Actions cache environment variables 47 | uses: actions/github-script@v7 48 | with: 49 | script: | 50 | core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); 51 | core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); 52 | 53 | # see https://github.com/microsoft/vcpkg/issues/43802 54 | - name: Install vcpkg 55 | run: | 56 | git clone https://github.com/microsoft/vcpkg.git 57 | cd vcpkg 58 | git checkout 62aa44929954469878eb8fc562af706a8f5615a5 59 | ./bootstrap-vcpkg.bat 60 | ./vcpkg integrate install 61 | 62 | - name: Install dependencies 63 | run: ./vcpkg/vcpkg install boost boost-log dtl ffmpeg[ffmpeg,x264,nonfree,gpl,vpx,webp,zlib,xml2] opencv4 python3 boost-python opencl --triplet=${{matrix.platform}}-windows 64 | 65 | - name: Restore NuGet packages 66 | working-directory: ${{env.GITHUB_WORKSPACE}} 67 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 68 | 69 | - name: Find OpenCV Header 70 | run: | 71 | $opencvHeader = Get-ChildItem -Path "./vcpkg/" -Recurse -Filter "opencv.hpp" | Where-Object { $_.FullName -match "opencv2\\opencv.hpp" } 72 | if ($opencvHeader) { 73 | Write-Output "Found OpenCV header at: $($opencvHeader.FullName)" 74 | } else { 75 | Write-Error "OpenCV header not found" 76 | } 77 | 78 | - name: Build 79 | working-directory: ${{env.GITHUB_WORKSPACE}} 80 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 81 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 82 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} /p:Platform=${{matrix.platform == 'x86' && 'Win32' || matrix.platform}} /t:Player:Rebuild ${{env.SOLUTION_FILE_PATH}} 83 | 84 | - name: Complete build artifacts 85 | run: | 86 | $CRT_path = Get-ChildItem -Path "${{ steps.setup-msbuild.outputs.msbuildPath }}/../../../VC/Redist/MSVC/*/${{matrix.platform}}/Microsoft.VC143.CRT" | Select-Object -First 1 -ExpandProperty FullName 87 | $MFC_path = Get-ChildItem -Path "${{ steps.setup-msbuild.outputs.msbuildPath }}/../../../VC/Redist/MSVC/*/${{matrix.platform}}/Microsoft.VC143.MFC" | Select-Object -First 1 -ExpandProperty FullName 88 | Write-Output "CRT PATH=$CRT_path" 89 | Write-Output "MFC PATH=$MFC_path" 90 | ./vcpkg/scripts/buildsystems/msbuild/applocal.ps1 -targetBinary "./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/Player.exe" -installedDir "$CRT_path" -OutVariable out 91 | ./vcpkg/scripts/buildsystems/msbuild/applocal.ps1 -targetBinary "./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/Player.exe" -installedDir "$MFC_path" -OutVariable out 92 | 93 | - name: Copy FFmpeg tools 94 | run: Copy-Item -Path "./vcpkg/installed/${{matrix.platform}}-windows/tools/ffmpeg/*" -Destination "./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/" -Recurse -Force -ErrorAction SilentlyContinue 95 | 96 | - name: Delete .pdb files 97 | run: Remove-Item -Path "./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/*.pdb" -Force 98 | 99 | - name: Delete .lib files 100 | run: Remove-Item -Path "./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/*.lib" -Force 101 | 102 | - name: Upload build artifacts 103 | uses: actions/upload-artifact@v4 104 | with: 105 | name: build-artifacts-${{matrix.platform}} 106 | path: ./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release 107 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | *.publishproj 131 | 132 | # NuGet Packages Directory 133 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 134 | #packages/ 135 | 136 | # Windows Azure Build Output 137 | csx 138 | *.build.csdef 139 | 140 | # Windows Store app package directory 141 | AppPackages/ 142 | 143 | # Others 144 | sql/ 145 | *.Cache 146 | ClientBin/ 147 | [Ss]tyle[Cc]op.* 148 | ~$* 149 | *~ 150 | *.dbmdl 151 | *.[Pp]ublish.xml 152 | *.pfx 153 | *.publishsettings 154 | 155 | # RIA/Silverlight projects 156 | Generated_Code/ 157 | 158 | # Backup & report files from converting an old project file to a newer 159 | # Visual Studio version. Backup files are not needed, because we have git ;-) 160 | _UpgradeReport_Files/ 161 | Backup*/ 162 | UpgradeLog*.XML 163 | UpgradeLog*.htm 164 | 165 | # SQL Server files 166 | App_Data/*.mdf 167 | App_Data/*.ldf 168 | 169 | ############# 170 | ## Windows detritus 171 | ############# 172 | 173 | # Windows image file caches 174 | Thumbs.db 175 | ehthumbs.db 176 | 177 | # Folder config file 178 | Desktop.ini 179 | 180 | # Recycle Bin used on file shares 181 | $RECYCLE.BIN/ 182 | 183 | # Mac crap 184 | .DS_Store 185 | 186 | 187 | ############# 188 | ## Python 189 | ############# 190 | 191 | *.py[cod] 192 | 193 | # Packages 194 | *.egg 195 | *.egg-info 196 | dist/ 197 | build/ 198 | eggs/ 199 | parts/ 200 | var/ 201 | sdist/ 202 | develop-eggs/ 203 | .installed.cfg 204 | 205 | # Installer logs 206 | pip-log.txt 207 | 208 | # Unit test / coverage reports 209 | .coverage 210 | .tox 211 | 212 | #Translations 213 | *.mo 214 | 215 | #Mr Developer 216 | .mr.developer.cfg 217 | 218 | ipch/ 219 | ffmpeg/ 220 | Player/I420Effect_PS.h 221 | Player.VC.db 222 | Player.VC.VC.opendb 223 | *.diagsession 224 | 225 | CMakeLists.txt.user* 226 | 227 | .clang-tidy 228 | 229 | .vs/ 230 | 231 | Player/version.h 232 | 233 | build-*/ 234 | 235 | Directory.Build.props 236 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Anime4KCPP"] 2 | path = Anime4KCPP 3 | url = https://github.com/TianZerL/Anime4KCPP.git 4 | -------------------------------------------------------------------------------- /Dlls/Dlls.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Release 5 | {BC1BC9F1-893D-4715-818A-F37F74EB5710} 6 | Library 7 | Properties 8 | Dlls 9 | Dlls 10 | 512 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug\ 17 | DEBUG;TRACE 18 | prompt 19 | 4 20 | 21 | 22 | pdbonly 23 | true 24 | bin\Release\ 25 | TRACE 26 | prompt 27 | 4 28 | 29 | 30 | 31 | PreserveNewest 32 | 33 | 34 | 35 | 42 | -------------------------------------------------------------------------------- /HttpDownload/HttpDownload.cpp: -------------------------------------------------------------------------------- 1 | // HttpDownload.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | #include "http_download.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | int _tmain(int argc, TCHAR *argv[]) 13 | { 14 | if (argc != 3) 15 | return EXIT_FAILURE; 16 | try 17 | { 18 | const bool ok = HttpDownload(argv[1], argv[2]); 19 | return ok ? EXIT_SUCCESS : EXIT_FAILURE; 20 | } 21 | catch (const std::exception& ex) 22 | { 23 | std::cerr << ex.what() << '\n'; 24 | return EXIT_FAILURE; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /HttpDownload/HttpDownload.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /HttpDownload/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : HttpDownload Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this HttpDownload application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your HttpDownload application. 9 | 10 | 11 | HttpDownload.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | HttpDownload.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | HttpDownload.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named HttpDownload.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /HttpDownload/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // HttpDownload.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /HttpDownload/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | -------------------------------------------------------------------------------- /HttpDownload/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Player/AsyncGetUrlUnderMouseCursor.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #include "AsyncGetUrlUnderMouseCursor.h" 4 | 5 | namespace { 6 | 7 | class CComUsageScope 8 | { 9 | bool m_bInitialized; 10 | public: 11 | explicit CComUsageScope(DWORD dwCoInit = COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY) 12 | { 13 | m_bInitialized = SUCCEEDED(CoInitializeEx(NULL, dwCoInit)); 14 | } 15 | ~CComUsageScope() 16 | { 17 | if (m_bInitialized) 18 | CoUninitialize(); 19 | } 20 | }; 21 | 22 | bool LinkHandled(const CComPtr& pacc) 23 | { 24 | VARIANT v; 25 | v.vt = VT_I4; 26 | v.lVal = CHILDID_SELF; 27 | 28 | CComVariant vRole; 29 | if (SUCCEEDED(pacc->get_accRole(v, &vRole)) && vRole.vt == VT_I4 && vRole.lVal == ROLE_SYSTEM_LINK) 30 | { 31 | CComBSTR url; 32 | if (SUCCEEDED(pacc->get_accValue(v, &url)) && url != NULL) 33 | { 34 | AfxGetApp()->PostThreadMessage(WM_ON_ASYNC_URL, (WPARAM)url.Detach(), NULL); 35 | return true; 36 | } 37 | } 38 | 39 | return false; 40 | } 41 | 42 | VOID CALLBACK SendAsyncProc( 43 | HWND, 44 | UINT, 45 | ULONG_PTR dwData, 46 | LRESULT lResult) 47 | { 48 | CComUsageScope scope; 49 | 50 | CComPtr pacc_; 51 | if (FAILED(ObjectFromLresult(lResult, __uuidof(IAccessible), 0, (void**)&pacc_))) 52 | return; 53 | 54 | enum { MAX_ITER_NUM = 100 }; 55 | 56 | POINT ptScreen{ LOWORD(dwData), HIWORD(dwData) }; 57 | 58 | for (int i = 0; i < 2; ++i) 59 | { 60 | CComPtr pacc = pacc_; 61 | { 62 | int iter = 0; 63 | CComVariant vtChild; 64 | CComQIPtr paccChild; 65 | for (; SUCCEEDED(pacc->accHitTest(ptScreen.x, ptScreen.y, &vtChild)) 66 | && VT_DISPATCH == vtChild.vt && (paccChild = vtChild.pdispVal) != NULL; 67 | vtChild.Clear()) 68 | { 69 | if (LinkHandled(pacc)) 70 | return; 71 | 72 | if (iter++ >= MAX_ITER_NUM) 73 | return; 74 | pacc.Attach(paccChild.Detach()); 75 | } 76 | } 77 | 78 | int iter = 0; 79 | while (pacc) 80 | { 81 | if (LinkHandled(pacc)) 82 | return; 83 | 84 | if (iter++ >= MAX_ITER_NUM) 85 | return; 86 | 87 | CComPtr spDisp; 88 | if (FAILED(pacc->get_accParent(&spDisp))) 89 | return; 90 | CComQIPtr spParent(spDisp); 91 | pacc.Attach(spParent.Detach()); 92 | } 93 | 94 | if (i == 0) 95 | { 96 | ::Sleep(100); 97 | } 98 | } 99 | } 100 | 101 | } // namespace 102 | 103 | 104 | void AsyncGetUrlUnderMouseCursor() 105 | { 106 | POINT pt; 107 | if (!GetCursorPos(&pt)) 108 | return; 109 | 110 | HWND hWnd = WindowFromPoint(pt); 111 | if (NULL == hWnd) 112 | return; 113 | 114 | TCHAR szBuffer[64]; 115 | 116 | const int classNameLength 117 | = ::GetClassName(hWnd, szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0])); 118 | 119 | szBuffer[sizeof(szBuffer) / sizeof(szBuffer[0]) - 1] = _T('\0'); 120 | 121 | if (_tcscmp(szBuffer, _T("MozillaWindowClass")) != 0 && _tcscmp(szBuffer, _T("Chrome_RenderWidgetHostHWND")) != 0) 122 | return; 123 | 124 | VERIFY(SendMessageCallback(hWnd, WM_GETOBJECT, 0L, OBJID_CLIENT, SendAsyncProc, MAKELONG(pt.x, pt.y))); 125 | } 126 | -------------------------------------------------------------------------------- /Player/AsyncGetUrlUnderMouseCursor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum { WM_ON_ASYNC_URL = 1234 }; 4 | 5 | void AsyncGetUrlUnderMouseCursor(); 6 | -------------------------------------------------------------------------------- /Player/ByteStreamBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class ByteStreamBuffer: public std::streambuf 6 | { 7 | public: 8 | ByteStreamBuffer(char* base, size_t length) 9 | { 10 | setg(base, base, base + length); 11 | } 12 | 13 | protected: 14 | pos_type seekoff( off_type offset, 15 | std::ios_base::seekdir dir, 16 | std::ios_base::openmode ) override 17 | { 18 | char* whence = eback(); 19 | if (dir == std::ios_base::cur) 20 | { 21 | whence = gptr(); 22 | } 23 | else if (dir == std::ios_base::end) 24 | { 25 | whence = egptr(); 26 | } 27 | char* to = whence + offset; 28 | 29 | // check limits 30 | if (to >= eback() && to <= egptr()) 31 | { 32 | setg(eback(), to, egptr()); 33 | return gptr() - eback(); 34 | } 35 | 36 | return -1; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /Player/D3DFONT.H: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // File: D3DFont.h 3 | // 4 | // Desc: Texture-based font class 5 | //----------------------------------------------------------------------------- 6 | #ifndef D3DFONT_H 7 | #define D3DFONT_H 8 | #include 9 | #include 10 | 11 | 12 | // Font creation flags 13 | #define D3DFONT_BOLD 0x0001 14 | #define D3DFONT_ITALIC 0x0002 15 | #define D3DFONT_ZENABLE 0x0004 16 | 17 | // Font rendering flags 18 | #define D3DFONT_CENTERED_X 0x0001 19 | #define D3DFONT_CENTERED_Y 0x0002 20 | #define D3DFONT_TWOSIDED 0x0004 21 | #define D3DFONT_FILTERED 0x0008 22 | 23 | 24 | 25 | 26 | //----------------------------------------------------------------------------- 27 | // Name: class CD3DFont 28 | // Desc: Texture-based font class for doing text in a 3D scene. 29 | //----------------------------------------------------------------------------- 30 | class CD3DFont 31 | { 32 | TCHAR m_strFontName[80]; // Font properties 33 | DWORD m_dwFontHeight; 34 | DWORD m_dwFontFlags; 35 | 36 | LPDIRECT3DDEVICE9 m_pd3dDevice; // A D3DDevice used for rendering 37 | LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font 38 | LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text 39 | DWORD m_dwTexWidth {}; // Texture dimensions 40 | DWORD m_dwTexHeight {}; 41 | FLOAT m_fTextScale {}; 42 | FLOAT m_fTexCoords[128 - 32][4] {}; 43 | DWORD m_dwSpacing; // Character pixel spacing per side 44 | 45 | // Stateblocks for setting and restoring render states 46 | LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved; 47 | LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText; 48 | 49 | public: 50 | // 2D and 3D text drawing functions 51 | HRESULT DrawText( FLOAT x, FLOAT y, DWORD dwColor, 52 | const TCHAR* strText, DWORD dwFlags=0L ); 53 | HRESULT DrawTextScaled( FLOAT x, FLOAT y, FLOAT z, 54 | FLOAT fXScale, FLOAT fYScale, DWORD dwColor, 55 | const TCHAR* strText, DWORD dwFlags=0L ); 56 | HRESULT Render3DText( const TCHAR* strText, DWORD dwFlags=0L ); 57 | 58 | // Function to get extent of text 59 | HRESULT GetTextExtent( const TCHAR* strText, SIZE* pSize ); 60 | 61 | // Initializing and destroying device-dependent objects 62 | HRESULT InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice ); 63 | HRESULT RestoreDeviceObjects(); 64 | HRESULT InvalidateDeviceObjects(); 65 | HRESULT DeleteDeviceObjects(); 66 | 67 | // Constructor / destructor 68 | CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags=0L ); 69 | ~CD3DFont(); 70 | }; 71 | 72 | 73 | 74 | 75 | #endif 76 | 77 | 78 | -------------------------------------------------------------------------------- /Player/DialogBarPlayerControl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "afxcmn.h" 4 | 5 | class CPlayerDoc; 6 | 7 | // CDialogBarPlayerControl 8 | 9 | class CDialogBarPlayerControl 10 | : public CPaneDialog 11 | { 12 | DECLARE_DYNAMIC(CDialogBarPlayerControl) 13 | 14 | public: 15 | CDialogBarPlayerControl(); 16 | virtual ~CDialogBarPlayerControl(); 17 | 18 | // Dialog Data 19 | //{{AFX_DATA(CDialogBarPlayerControl) 20 | enum { IDD = IDD_DIALOGBAR_PLAYER_CONTROL }; 21 | // NOTE: the ClassWizard will add data members here 22 | //}}AFX_DATA 23 | 24 | void setDocument(CPlayerDoc* pDoc); 25 | 26 | // Overrides 27 | // ClassWizard generated virtual function overrides 28 | //{{AFX_VIRTUAL(CDialogBarPlayerControl) 29 | protected: 30 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 31 | //}}AFX_VIRTUAL 32 | 33 | int GetCaptionHeight() const override { return 0; } 34 | 35 | void onFramePositionChanged(long long frame, long long total); 36 | void onTotalTimeUpdated(double secs); 37 | void onCurrentTimeUpdated(double secs); 38 | 39 | void onRangeStartTimeChanged(long long frame, long long total); 40 | void onRangeEndTimeChanged(long long frame, long long total); 41 | 42 | void onDocDetaching(); 43 | 44 | protected: 45 | DECLARE_MESSAGE_MAP() 46 | afx_msg LRESULT HandleInitDialog(WPARAM wParam, LPARAM lParam); 47 | afx_msg LRESULT OnSetTime(WPARAM wParam, LPARAM lParam); 48 | public: 49 | 50 | private: 51 | CPlayerDoc* m_pDoc; 52 | HICON m_hPlay; 53 | HICON m_hPause; 54 | HICON m_hAudio; 55 | HICON m_hAudioOff; 56 | HICON m_hFullScreen; 57 | int m_savedVolume; 58 | volatile int m_oldTotalTime; 59 | volatile int m_oldCurrentTime; 60 | bool m_tracking; 61 | 62 | int m_selStart; 63 | int m_selEnd; 64 | 65 | public: 66 | CSliderCtrl m_progressSlider; 67 | CSliderCtrl m_volumeSlider; 68 | afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); 69 | afx_msg void OnUpdatePlayPause(CCmdUI *pCmdUI); 70 | afx_msg void OnUpdateAudioOnOff(CCmdUI *pCmdUI); 71 | afx_msg void OnClickedPlayPause(); 72 | afx_msg void OnClickedAudioOnOff(); 73 | afx_msg void OnUpdateFrameStep(CCmdUI *pCmdUI); 74 | afx_msg void OnUpdateVolumeSlider(CCmdUI *pCmdUI); 75 | afx_msg void OnUpdateCurrentTime(CCmdUI *pCmdUI); 76 | }; 77 | 78 | 79 | -------------------------------------------------------------------------------- /Player/DialogBarRange.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "EditTime.h" 4 | 5 | class CPlayerDoc; 6 | 7 | // CDialogBarRange 8 | 9 | class CDialogBarRange : public CPaneDialog 10 | { 11 | DECLARE_DYNAMIC(CDialogBarRange) 12 | 13 | public: 14 | CDialogBarRange(); 15 | virtual ~CDialogBarRange(); 16 | 17 | enum { IDD = IDD_DIALOGBAR_RANGE }; 18 | 19 | void setDocument(CPlayerDoc* pDoc); 20 | 21 | // Overrides 22 | // ClassWizard generated virtual function overrides 23 | //{{AFX_VIRTUAL(CDialogBarPlayerControl) 24 | protected: 25 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 26 | //}}AFX_VIRTUAL 27 | 28 | protected: 29 | int GetCaptionHeight() const override { return 0; } 30 | 31 | void onTotalTimeUpdated(double secs); 32 | 33 | void onDocDetaching(); 34 | 35 | protected: 36 | DECLARE_MESSAGE_MAP() 37 | afx_msg LRESULT HandleInitDialog(WPARAM wParam, LPARAM lParam); 38 | private: 39 | CPlayerDoc* m_pDoc; 40 | CFont m_font; 41 | public: 42 | CEditTime m_startTime; 43 | CEditTime m_endTime; 44 | afx_msg void OnStart(); 45 | afx_msg void OnStartReset(); 46 | afx_msg void OnEnd(); 47 | afx_msg void OnEndReset(); 48 | afx_msg void OnUpdateStart(CCmdUI *pCmdUI); 49 | afx_msg void OnUpdateStartReset(CCmdUI *pCmdUI); 50 | afx_msg void OnUpdateEnd(CCmdUI *pCmdUI); 51 | afx_msg void OnUpdateEndReset(CCmdUI *pCmdUI); 52 | afx_msg void OnUpdateSave(CCmdUI *pCmdUI); 53 | afx_msg void OnChangeStart(); 54 | afx_msg void OnChangeEnd(); 55 | afx_msg void OnBnClickedLosslessCut(); 56 | }; 57 | -------------------------------------------------------------------------------- /Player/DialogOpenURL.cpp: -------------------------------------------------------------------------------- 1 | // DialogOpenURL.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "Player.h" 6 | #include "DialogOpenURL.h" 7 | #include "afxdialogex.h" 8 | 9 | 10 | // CDialogOpenURL dialog 11 | 12 | IMPLEMENT_DYNAMIC(CDialogOpenURL, CDialog) 13 | 14 | CDialogOpenURL::CDialogOpenURL(CWnd* pParent /*=NULL*/) 15 | : CDialog(IDD_DIALOG_OPEN_URL, pParent) 16 | , m_URL(_T("")) 17 | , m_bParse(false) 18 | , m_inputFormt(_T("")) 19 | { 20 | 21 | } 22 | 23 | CDialogOpenURL::~CDialogOpenURL() 24 | { 25 | } 26 | 27 | void CDialogOpenURL::DoDataExchange(CDataExchange* pDX) 28 | { 29 | CDialog::DoDataExchange(pDX); 30 | DDX_Text(pDX, IDC_EDIT_URL, m_URL); 31 | DDX_Check(pDX, IDC_PARSE, m_bParse); 32 | DDX_Text(pDX, IDC_EDIT_INPUT_FORMAT, m_inputFormt); 33 | } 34 | 35 | 36 | BEGIN_MESSAGE_MAP(CDialogOpenURL, CDialog) 37 | END_MESSAGE_MAP() 38 | 39 | 40 | // CDialogOpenURL message handlers 41 | -------------------------------------------------------------------------------- /Player/DialogOpenURL.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | // CDialogOpenURL dialog 5 | 6 | class CDialogOpenURL : public CDialog 7 | { 8 | DECLARE_DYNAMIC(CDialogOpenURL) 9 | 10 | public: 11 | explicit CDialogOpenURL(CWnd* pParent = NULL); // standard constructor 12 | virtual ~CDialogOpenURL(); 13 | 14 | // Dialog Data 15 | #ifdef AFX_DESIGN_TIME 16 | enum { IDD = IDD_DIALOG_OPEN_URL }; 17 | #endif 18 | 19 | protected: 20 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 21 | 22 | DECLARE_MESSAGE_MAP() 23 | public: 24 | CString m_URL; 25 | int m_bParse{}; 26 | CString m_inputFormt; 27 | }; 28 | -------------------------------------------------------------------------------- /Player/EditTime.cpp: -------------------------------------------------------------------------------- 1 | // EditTime.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "EditTime.h" 6 | #include "SecondsToString.h" 7 | 8 | #include 9 | 10 | #ifdef _DEBUG 11 | #define new DEBUG_NEW 12 | #undef THIS_FILE 13 | static char THIS_FILE[] = __FILE__; 14 | #endif 15 | 16 | namespace { 17 | 18 | 19 | enum 20 | { 21 | TIME_INVALID = -1000000000 22 | }; 23 | 24 | int ReadUint(const TCHAR*& s) 25 | { 26 | int buf = 0; 27 | for (; *s >= '0' && *s <= '9'; ++s) 28 | buf = buf * 10 + *s - '0'; 29 | 30 | return buf; 31 | } 32 | 33 | double ParseTime(const TCHAR* timeStr) 34 | { 35 | int seconds = 0; 36 | 37 | int numDelims = 0; 38 | 39 | const bool minus = *timeStr == '-'; 40 | if (minus) 41 | ++timeStr; 42 | 43 | for (;;) 44 | { 45 | switch (*timeStr) 46 | { 47 | case '\0': 48 | return minus ? -seconds : seconds; 49 | case ':': 50 | if (++numDelims > 2) 51 | return TIME_INVALID; 52 | seconds *= 60; 53 | ++timeStr; 54 | break; 55 | case '.': 56 | { 57 | ++timeStr; 58 | const auto prevPtr = timeStr; 59 | const auto millis = ReadUint(timeStr); 60 | if (*timeStr != '\0') 61 | return TIME_INVALID; 62 | const int msecStringLen = timeStr - prevPtr; 63 | if (msecStringLen > 3) 64 | return TIME_INVALID; 65 | if (msecStringLen == 0) 66 | return minus ? -seconds : seconds; 67 | const auto absResult = seconds + millis / std::pow(10, msecStringLen); 68 | return minus ? -absResult : absResult; 69 | } 70 | break; 71 | default: 72 | const auto prevPtr = timeStr; 73 | seconds += ReadUint(timeStr); 74 | if (prevPtr == timeStr) 75 | return TIME_INVALID; 76 | } 77 | } 78 | } 79 | 80 | bool Match(const TCHAR* timeStr) 81 | { 82 | return ParseTime(timeStr) != TIME_INVALID; 83 | } 84 | 85 | } // namespace 86 | 87 | 88 | enum { WM_RESET = WM_USER + 101 }; 89 | 90 | ///////////////////////////////////////////////////////////////////////////// 91 | // CEditTime 92 | 93 | CEditTime::CEditTime() 94 | { 95 | } 96 | 97 | CEditTime::~CEditTime() 98 | { 99 | } 100 | 101 | BEGIN_MESSAGE_MAP(CEditTime, CEdit) 102 | //{{AFX_MSG_MAP(CEditTime) 103 | ON_WM_CHAR() 104 | ON_MESSAGE(WM_RESET, &CEditTime::OnReset) 105 | //}}AFX_MSG_MAP 106 | END_MESSAGE_MAP() 107 | 108 | ///////////////////////////////////////////////////////////////////////////// 109 | // CEditTime message handlers 110 | 111 | void CEditTime::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 112 | { 113 | if (nChar >= 32) 114 | { 115 | int iStartIndex = -1; 116 | int iEndIndex = -1; 117 | 118 | GetSel(iStartIndex, iEndIndex); 119 | CString strProposedText; 120 | GetWindowText(strProposedText); 121 | strProposedText.Delete(iStartIndex, iEndIndex - iStartIndex); 122 | strProposedText.Insert(iStartIndex, static_cast(nChar)); 123 | 124 | if (!Match(strProposedText)) 125 | return; 126 | } 127 | CEdit::OnChar(nChar, nRepCnt, nFlags); 128 | } 129 | 130 | void CEditTime::Reset() 131 | { 132 | SendNotifyMessage(WM_RESET, 0, 0); 133 | } 134 | 135 | void CEditTime::SetValue(double fTime) 136 | { 137 | SetWindowText(secondsToString(fTime * 1000, true).c_str()); 138 | } 139 | 140 | double CEditTime::GetValue() const 141 | { 142 | CString strBuf; 143 | GetWindowText(strBuf); 144 | return ParseTime(strBuf); 145 | } 146 | 147 | bool CEditTime::IsEmpty() const 148 | { 149 | CString strBuf; 150 | GetWindowText(strBuf); 151 | return strBuf.IsEmpty(); 152 | } 153 | 154 | LRESULT CEditTime::OnReset(WPARAM, LPARAM) 155 | { 156 | SetWindowText(_T("")); 157 | return 0; 158 | } 159 | -------------------------------------------------------------------------------- /Player/EditTime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | ///////////////////////////////////////////////////////////////////////////// 4 | // CEditTime window 5 | 6 | class CEditTime : public CEdit 7 | { 8 | // Construction 9 | public: 10 | CEditTime(); 11 | 12 | // Attributes 13 | public: 14 | void Reset(); 15 | void SetValue(double fTime); 16 | double GetValue() const; 17 | bool IsEmpty() const; 18 | 19 | // Operations 20 | 21 | // Overrides 22 | // ClassWizard generated virtual function overrides 23 | //{{AFX_VIRTUAL(CEditTime) 24 | //}}AFX_VIRTUAL 25 | 26 | // Implementation 27 | public: 28 | virtual ~CEditTime(); 29 | 30 | // Generated message map functions 31 | protected: 32 | //{{AFX_MSG(CEditTime) 33 | afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); 34 | afx_msg LRESULT OnReset(WPARAM wParam, LPARAM lParam); 35 | //}}AFX_MSG 36 | 37 | DECLARE_MESSAGE_MAP() 38 | 39 | private: 40 | CFont m_Font; 41 | }; 42 | 43 | ///////////////////////////////////////////////////////////////////////////// 44 | 45 | //{{AFX_INSERT_LOCATION}} 46 | // Microsoft Developer Studio will insert additional declarations immediately before the previous line. 47 | 48 | -------------------------------------------------------------------------------- /Player/FrameToHglobal.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "FrameToHglobal.h" 3 | 4 | #include "ffmpeg_dxva2.h" 5 | 6 | extern "C" 7 | { 8 | #include "libavutil/frame.h" 9 | #include "libswscale/swscale.h" 10 | }; 11 | 12 | HGLOBAL FrameToHglobal(IDirect3DSurface9* surface, int width, int height, int allocatedHeight) 13 | { 14 | AVFrame* tmp_frame = av_frame_alloc(); 15 | 16 | int res = dxva2_convert_data(surface, tmp_frame, width, allocatedHeight); 17 | if (res != 0) 18 | { 19 | av_frame_free(&tmp_frame); 20 | return NULL; 21 | } 22 | 23 | const int stride = ((width * 3) + 3) & ~3; 24 | 25 | auto hMem = GlobalAlloc(GMEM_MOVEABLE, sizeof(BITMAPINFOHEADER) + stride * height); 26 | 27 | if (hMem == NULL) { 28 | av_frame_free(&tmp_frame); 29 | return NULL; 30 | } 31 | 32 | auto bmi = static_cast(GlobalLock(hMem)); 33 | if (!bmi) { 34 | GlobalFree(hMem); 35 | av_frame_free(&tmp_frame); 36 | return NULL; 37 | } 38 | 39 | memset(bmi, 0, sizeof(BITMAPINFOHEADER)); 40 | bmi->biSize = sizeof(BITMAPINFOHEADER); 41 | bmi->biWidth = width; 42 | bmi->biHeight = -height; 43 | 44 | bmi->biPlanes = 1; 45 | bmi->biBitCount = 24; 46 | bmi->biCompression = BI_RGB; 47 | 48 | const auto pData = static_cast(static_cast(bmi + 1)); 49 | 50 | auto img_convert_ctx = sws_getContext(tmp_frame->width, tmp_frame->height, (AVPixelFormat)tmp_frame->format, 51 | width, allocatedHeight, AV_PIX_FMT_BGR24, SWS_FAST_BILINEAR, NULL, NULL, NULL); 52 | 53 | sws_scale(img_convert_ctx, tmp_frame->data, tmp_frame->linesize, 0, height, 54 | &pData, &stride); 55 | 56 | sws_freeContext(img_convert_ctx); 57 | 58 | GlobalUnlock(hMem); 59 | av_frame_free(&tmp_frame); 60 | 61 | return hMem; 62 | } 63 | -------------------------------------------------------------------------------- /Player/FrameToHglobal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct IDirect3DSurface9; 4 | 5 | HGLOBAL FrameToHglobal(IDirect3DSurface9* surface, int width, int height, int allocatedHeight); 6 | -------------------------------------------------------------------------------- /Player/GetClipboardText.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | inline std::string GetClipboardText() 6 | { 7 | std::string text; 8 | 9 | // Try opening the clipboard 10 | if (OpenClipboard(nullptr)) 11 | { 12 | // Get handle of clipboard object for ANSI text 13 | if (HANDLE hData = GetClipboardData(CF_TEXT)) 14 | { 15 | // Lock the handle to get the actual text pointer 16 | if (const char* pszText = static_cast(GlobalLock(hData))) 17 | { 18 | // Save text in a string class instance 19 | text = pszText; 20 | } 21 | // Release the lock 22 | GlobalUnlock(hData); 23 | } 24 | 25 | // Release the clipboard 26 | CloseClipboard(); 27 | } 28 | 29 | return text; 30 | } 31 | -------------------------------------------------------------------------------- /Player/HandleFilesSequence.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #include "HandleFilesSequence.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace { 9 | 10 | auto MakeComparableConsideringNumbers(const CString& s) 11 | { 12 | std::vector result; 13 | 14 | unsigned int accum = 0; 15 | for (int i = 0; i < s.GetLength(); ++i) 16 | { 17 | const auto c = s[i]; 18 | if ((c >= _T('0') && accum != 0 || c > _T('0')) && c <= _T('9')) 19 | { 20 | accum = accum * 10 + (c - _T('0')); 21 | } 22 | else 23 | { 24 | if (accum != 0) 25 | { 26 | result.push_back(accum + static_cast(_T('0'))); 27 | accum = 0; 28 | } 29 | result.push_back((static_cast(c) < static_cast(_T('9'))) 30 | ? c : (0xFFFF0000 | c)); 31 | } 32 | } 33 | 34 | if (accum != 0) 35 | { 36 | result.push_back(accum + static_cast(_T('0'))); 37 | } 38 | 39 | return result; 40 | } 41 | 42 | bool CompareConsideringNumbers(CString left, CString right) 43 | { 44 | const auto leftConverted = MakeComparableConsideringNumbers(left.MakeUpper()); 45 | const auto rightConverted = MakeComparableConsideringNumbers(right.MakeUpper()); 46 | 47 | return std::lexicographical_compare( 48 | rightConverted.begin(), rightConverted.end(), leftConverted.begin(), leftConverted.end()); 49 | } 50 | 51 | } 52 | 53 | bool HandleFilesSequence(const CString& pathName, 54 | bool looping, 55 | std::function tryToOpen, 56 | bool invert /*= false*/) 57 | { 58 | const auto extension = PathFindExtension(pathName); 59 | const auto fileName = PathFindFileName(pathName); 60 | if (!extension || !fileName) 61 | return false; 62 | const CString directory(pathName, fileName - pathName); 63 | const CString pattern((directory + _T('*')) + extension); 64 | 65 | WIN32_FIND_DATA ffd{}; 66 | const auto hFind = FindFirstFile(pattern, &ffd); 67 | 68 | if (INVALID_HANDLE_VALUE == hFind) 69 | { 70 | return false; 71 | } 72 | 73 | std::vector filesArr[2]; 74 | const auto extensionLength = pathName.GetLength() - (extension - pathName); 75 | const CString justFileName(fileName, extension - fileName); 76 | 77 | do 78 | { 79 | if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 80 | { 81 | const auto length = _tcslen(ffd.cFileName); 82 | if (length > extensionLength && ffd.cFileName[length - extensionLength] == _T('.')) 83 | { 84 | CString cFileName(ffd.cFileName, length - extensionLength); 85 | const bool beforeOrEqual = !CompareConsideringNumbers(cFileName, justFileName); 86 | filesArr[beforeOrEqual].push_back(cFileName); 87 | } 88 | } 89 | } while (FindNextFile(hFind, &ffd)); 90 | 91 | FindClose(hFind); 92 | 93 | for (int i = 0; i <= looping; ++i) 94 | { 95 | std::vector& files = filesArr[i ^ invert]; 96 | std::make_heap(files.begin(), files.end(), CompareConsideringNumbers); 97 | 98 | while (!files.empty()) 99 | { 100 | const CString path = directory + files.front() + extension; 101 | if (tryToOpen(path)) 102 | { 103 | return true; 104 | } 105 | std::pop_heap(files.begin(), files.end(), CompareConsideringNumbers); 106 | files.pop_back(); 107 | } 108 | } 109 | return false; 110 | } 111 | -------------------------------------------------------------------------------- /Player/HandleFilesSequence.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool HandleFilesSequence(const CString& pathName, 6 | bool looping, 7 | std::function tryToOpen, 8 | bool invert = false); 9 | -------------------------------------------------------------------------------- /Player/I420Effect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // {3AB41678-D4BC-4BE1-8A91-07A63DEEFEA1} 6 | DEFINE_GUID(GUID_I420PixelShader, 0x3ab41678, 0xd4bc, 0x4be1, 0x8a, 0x91, 0x7, 0xa6, 0x3d, 0xee, 0xfe, 0xa1); 7 | // {DA637E40-44D4-4617-A3D3-A28344549EEA} 8 | DEFINE_GUID(CLSID_CustomI420Effect, 0xda637e40, 0x44d4, 0x4617, 0xa3, 0xd3, 0xa2, 0x83, 0x44, 0x54, 0x9e, 0xea); 9 | 10 | class I420Effect : public ID2D1EffectImpl, public ID2D1DrawTransform 11 | { 12 | public: 13 | // Declare effect registration methods. 14 | static HRESULT Register(_In_ ID2D1Factory1* pFactory); 15 | static HRESULT __stdcall CreateRippleImpl(_Outptr_ IUnknown** ppEffectImpl); 16 | 17 | // Declare ID2D1EffectImpl implementation methods. 18 | IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext* pContextInternal, _In_ ID2D1TransformGraph* pTransformGraph); 19 | IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE changeType); 20 | IFACEMETHODIMP SetGraph(_In_ ID2D1TransformGraph* pGraph); 21 | 22 | // Declare ID2D1DrawTransform implementation methods. 23 | IFACEMETHODIMP SetDrawInfo(_In_ ID2D1DrawInfo* pRenderInfo); 24 | 25 | // Declare ID2D1Transform implementation methods. 26 | IFACEMETHODIMP MapOutputRectToInputRects( 27 | _In_ const D2D1_RECT_L* pOutputRect, 28 | _Out_writes_(inputRectCount) D2D1_RECT_L* pInputRects, 29 | UINT32 inputRectCount 30 | ) const; 31 | 32 | IFACEMETHODIMP MapInputRectsToOutputRect( 33 | _In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputRects, 34 | _In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputOpaqueSubRects, 35 | UINT32 inputRectCount, 36 | _Out_ D2D1_RECT_L* pOutputRect, 37 | _Out_ D2D1_RECT_L* pOutputOpaqueSubRect 38 | ); 39 | 40 | IFACEMETHODIMP MapInvalidRect( 41 | UINT32 inputIndex, 42 | D2D1_RECT_L invalidInputRect, 43 | _Out_ D2D1_RECT_L* pInvalidOutputRect 44 | ) const; 45 | 46 | // Declare ID2D1TransformNode implementation methods. 47 | IFACEMETHODIMP_(UINT32) GetInputCount() const; 48 | 49 | // Declare IUnknown implementation methods. 50 | IFACEMETHODIMP_(ULONG) AddRef(); 51 | IFACEMETHODIMP_(ULONG) Release(); 52 | IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppOutput); 53 | private: 54 | 55 | I420Effect(); 56 | 57 | CComPtr m_drawInfo; 58 | 59 | LONG m_refCount; 60 | D2D1_RECT_L m_inputRect; 61 | D2D1_SIZE_U m_originalFrame; 62 | }; 63 | -------------------------------------------------------------------------------- /Player/I420Effect_PS.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D yTexture : register(t0); 2 | Texture2D uTexture : register(t1); 3 | Texture2D vTexture : register(t2); 4 | 5 | SamplerState ySampler : register(s0); 6 | SamplerState uSampler : register(s1); 7 | SamplerState vSampler : register(s2); 8 | 9 | float4 main( 10 | float4 pos : SV_POSITION, 11 | float4 posScene : SCENE_POSITION, 12 | float4 uv0 : TEXCOORD0 13 | ) : SV_Target 14 | { 15 | float Y = yTexture.Sample(ySampler, uv0).a * 255; 16 | float U = uTexture.Sample(uSampler, uv0).a * 255; 17 | float V = vTexture.Sample(vSampler, uv0).a * 255; 18 | 19 | float4 color = float4(0, 0, 0, 1.0f); 20 | 21 | color.b = clamp(1.164383561643836*(Y - 16) + 2.017232142857142*(U - 128), 0, 255) / 255.0f; 22 | color.g = clamp(1.164383561643836*(Y - 16) - 0.812967647237771*(V - 128) - 0.391762290094914*(U - 128), 0, 255) / 255.0f; 23 | color.r = clamp(1.164383561643836*(Y - 16) + 1.596026785714286*(V - 128), 0, 255) / 255.0f; 24 | 25 | return color; 26 | } -------------------------------------------------------------------------------- /Player/IEraseableArea.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CWnd; 4 | class CDC; 5 | 6 | class IEraseableArea 7 | { 8 | public: 9 | virtual void OnErase(CWnd* pInitiator, CDC* pDC, BOOL isFullScreen) = 0; 10 | }; 11 | -------------------------------------------------------------------------------- /Player/ImageUpscale.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #include "ImageUpscale.h" 4 | 5 | #if __has_include("AC.hpp") 6 | 7 | #include"AC.hpp" 8 | #include"ACCreator.hpp" 9 | #include"ACProcessor.hpp" 10 | #include "Anime4KCPP.hpp" 11 | 12 | 13 | const int currPlatformID = 0; 14 | const int currDeviceID = 0; 15 | 16 | bool CanUpscaleImage() 17 | { 18 | static const bool ok = LoadLibrary(_T("opencl.dll")) != NULL 19 | && Anime4KCPP::OpenCL::checkGPUSupport(currPlatformID, currDeviceID); 20 | return ok; 21 | } 22 | 23 | bool EnableImageUpscale() 24 | { 25 | static Anime4KCPP::ACInitializer initializer; 26 | 27 | static const auto ok = [] { 28 | const int OpenCLQueueNum = 1; 29 | const bool OpenCLParallelIO = false; 30 | 31 | initializer.pushManager>( 32 | currPlatformID, currDeviceID, 33 | Anime4KCPP::CNNType::Default, 34 | OpenCLQueueNum, 35 | OpenCLParallelIO); 36 | 37 | return initializer.init() == initializer.size(); 38 | }(); 39 | return ok; 40 | } 41 | 42 | void ImageUpscale(uint8_t* input, int inputStride, int inputWidth, int inputHeight, std::vector& output, int& outputWidth, int& outputHeight) 43 | { 44 | Anime4KCPP::Parameters param{}; 45 | auto ac = Anime4KCPP::ACCreator::createUP(param, Anime4KCPP::Processor::Type::OpenCL_ACNet); 46 | 47 | const cv::Mat y_image(inputHeight, inputWidth, CV_8UC1, input, inputStride); 48 | const cv::Mat uv_image(inputHeight / 2, inputWidth / 2, CV_8UC2, input + inputHeight * inputStride, inputStride); 49 | cv::Mat cbcr_channels[2]; 50 | split(uv_image, cbcr_channels); 51 | 52 | ac->loadImage(y_image, cbcr_channels[0], cbcr_channels[1]); 53 | 54 | ac->process(); 55 | 56 | cv::Mat out_y_image; 57 | std::vector out_cbcr_channels(2); 58 | 59 | ac->saveImage(out_y_image, out_cbcr_channels[0], out_cbcr_channels[1]); 60 | 61 | outputWidth = out_y_image.cols; 62 | outputHeight = out_y_image.rows; 63 | 64 | cv::Mat CrCb; 65 | merge(out_cbcr_channels, CrCb); 66 | 67 | output.assign(out_y_image.datastart, out_y_image.dataend); 68 | output.insert(output.end(), CrCb.datastart, CrCb.dataend); 69 | } 70 | 71 | #else 72 | 73 | bool CanUpscaleImage() 74 | { 75 | return false; 76 | } 77 | 78 | bool EnableImageUpscale() 79 | { 80 | return false; 81 | } 82 | 83 | void ImageUpscale(uint8_t*, int, int, int, std::vector&, int&, int&) 84 | { 85 | } 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /Player/ImageUpscale.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | bool CanUpscaleImage(); 7 | 8 | bool EnableImageUpscale(); 9 | 10 | void ImageUpscale(uint8_t* input, int inputStride, int inputWidth, int inputHeight, std::vector& output, int& outputWidth, int& outputHeight); 11 | -------------------------------------------------------------------------------- /Player/MainFrm.h: -------------------------------------------------------------------------------- 1 | 2 | // MainFrm.h : interface of the CMainFrame class 3 | // 4 | 5 | #pragma once 6 | 7 | #include "DialogBarPlayerControl.h" 8 | #include "DialogBarRange.h" 9 | 10 | struct ITaskbarList3; 11 | 12 | class CMainFrame : public CFrameWndEx 13 | { 14 | 15 | protected: // create from serialization only 16 | CMainFrame(); 17 | DECLARE_DYNCREATE(CMainFrame) 18 | 19 | // Attributes 20 | public: 21 | 22 | // Operations 23 | private: 24 | void pauseResume(); 25 | void onPauseResume(bool paused); 26 | 27 | 28 | // Overrides 29 | public: 30 | BOOL OnCommand(WPARAM wParam, LPARAM lParam) override; 31 | BOOL PreCreateWindow(CREATESTRUCT& cs) override; 32 | 33 | BOOL Create(LPCTSTR lpszClassName, 34 | LPCTSTR lpszWindowName, 35 | DWORD dwStyle = WS_OVERLAPPEDWINDOW, 36 | const RECT& rect = rectDefault, 37 | CWnd* pParentWnd = NULL, // != NULL for popups 38 | LPCTSTR lpszMenuName = NULL, 39 | DWORD dwExStyle = 0, 40 | CCreateContext* pContext = NULL) override; 41 | 42 | BOOL PreTranslateMessage(MSG* pMsg) override; 43 | 44 | 45 | // Implementation 46 | public: 47 | virtual ~CMainFrame(); 48 | #ifdef _DEBUG 49 | virtual void AssertValid() const; 50 | virtual void Dump(CDumpContext& dc) const; 51 | #endif 52 | 53 | protected: // control bar embedded members 54 | CMFCMenuBar m_wndMenuBar; 55 | //CMFCToolBar m_wndToolBar; 56 | //CMFCStatusBar m_wndStatusBar; 57 | CDialogBarPlayerControl m_wndPlayerControl; 58 | CDialogBarRange m_wndRange; 59 | 60 | BOOL m_bFullScreen; 61 | 62 | CComPtr m_pTaskbarList; 63 | 64 | HICON m_hPlay; 65 | HICON m_hPause; 66 | 67 | // Generated message map functions 68 | protected: 69 | afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 70 | afx_msg void OnClose(); 71 | afx_msg LRESULT CreateThumbnailToolbar(WPARAM wParam, LPARAM lParam); 72 | afx_msg void OnFullScreen(); 73 | afx_msg BOOL OnEraseBkgnd(CDC* pDC); 74 | afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); 75 | afx_msg void OnNcPaint(); 76 | afx_msg UINT OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData); 77 | afx_msg LRESULT OnNcHitTest(CPoint point); 78 | DECLARE_MESSAGE_MAP() 79 | public: 80 | afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); 81 | }; 82 | -------------------------------------------------------------------------------- /Player/MakeDelegate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | class Delegate 7 | { 8 | public: 9 | explicit Delegate(T* callee) 10 | : fpCallee(callee) 11 | {} 12 | template 13 | decltype(auto) operator()(Args&&... xs) const 14 | { 15 | return (fpCallee->*TMethod)(std::forward(xs)...); 16 | } 17 | 18 | bool operator == (const Delegate& other) const 19 | { 20 | return fpCallee == other.fpCallee; 21 | } 22 | 23 | bool operator != (const Delegate& other) const 24 | { 25 | return fpCallee != other.fpCallee; 26 | } 27 | 28 | private: 29 | T* fpCallee; 30 | }; 31 | 32 | 33 | template 34 | inline auto MakeDelegate(T* ptr) 35 | { 36 | return Delegate(ptr); 37 | } 38 | 39 | #define MAKE_DELEGATE(foo, thisPtr) (MakeDelegate(thisPtr)) 40 | -------------------------------------------------------------------------------- /Player/MemoryMappedFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class MemoryMappedFile 4 | { 5 | public: 6 | MemoryMappedFile() 7 | : hFile(INVALID_HANDLE_VALUE) 8 | , hFileMapping(NULL) 9 | , pData(NULL) 10 | {} 11 | ~MemoryMappedFile() 12 | { 13 | if (pData) 14 | UnmapViewOfFile(pData); 15 | if (hFileMapping) 16 | CloseHandle(hFileMapping); 17 | if (INVALID_HANDLE_VALUE != hFile) 18 | CloseHandle(hFile); 19 | } 20 | MemoryMappedFile(const MemoryMappedFile&) = delete; 21 | MemoryMappedFile& operator=(const MemoryMappedFile&) = delete; 22 | 23 | bool MapFlie(LPCTSTR szFile) 24 | { 25 | hFile = CreateFile( 26 | szFile, // pointer to name of the file 27 | GENERIC_READ, // access (read-write) mode 28 | FILE_SHARE_READ, // share mode 29 | NULL, // pointer to security attributes 30 | OPEN_EXISTING, // how to create 31 | FILE_ATTRIBUTE_NORMAL, // file attributes 32 | NULL // handle to file with attributes to copy 33 | ); 34 | if (INVALID_HANDLE_VALUE != hFile && GetFileSizeEx(hFile, &fileSize) && fileSize.HighPart == 0) 35 | { 36 | hFileMapping = CreateFileMapping( 37 | hFile, // handle to file to map 38 | NULL, // optional security attributes 39 | PAGE_READONLY, // protection for mapping object 40 | fileSize.HighPart, // high-order 32 bits of object size 41 | fileSize.LowPart, // low-order 32 bits of object size 42 | NULL // name of file-mapping object 43 | ); 44 | if (NULL != hFileMapping) 45 | { 46 | pData = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, (SIZE_T)fileSize.QuadPart); 47 | return pData != NULL; 48 | } 49 | } 50 | 51 | return false; 52 | } 53 | 54 | LPVOID data() const { return pData; } 55 | LONGLONG size() const { return fileSize.QuadPart; } 56 | 57 | private: 58 | HANDLE hFile; 59 | LARGE_INTEGER fileSize; 60 | HANDLE hFileMapping; 61 | LPVOID pData; 62 | }; 63 | -------------------------------------------------------------------------------- /Player/OpenSubtitlesFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | typedef std::function AddIntervalCallback; 8 | 9 | 10 | bool OpenSubtitlesFile(const TCHAR* videoPathName, 11 | bool& unicodeSubtitles, 12 | AddIntervalCallback addIntervalCallback); 13 | 14 | bool OpenMatchingSubtitlesFile(const TCHAR* videoPathName, 15 | bool& unicodeSubtitles, 16 | AddIntervalCallback addIntervalCallback); 17 | -------------------------------------------------------------------------------- /Player/Player.h: -------------------------------------------------------------------------------- 1 | 2 | // Player.h : main header file for the Player application 3 | // 4 | #pragma once 5 | 6 | #ifndef __AFXWIN_H__ 7 | #error "include 'stdafx.h' before including this file for PCH" 8 | #endif 9 | 10 | #include "resource.h" // main symbols 11 | 12 | class CPlayerDoc; 13 | 14 | // CPlayerApp: 15 | // See Player.cpp for the implementation of this class 16 | // 17 | 18 | class CPlayerApp : public CWinAppEx 19 | { 20 | public: 21 | CPlayerApp(); 22 | 23 | 24 | // Overrides 25 | public: 26 | BOOL InitInstance() override; 27 | 28 | CString GetMappedAudioFile(LPCTSTR key); 29 | void SetMappedAudioFile(LPCTSTR key, LPCTSTR value); 30 | 31 | // Implementation 32 | afx_msg void OnAppAbout(); 33 | afx_msg void OnAsyncUrl(WPARAM wParam, LPARAM lParam); 34 | DECLARE_MESSAGE_MAP() 35 | 36 | CPlayerDoc* GetPlayerDocument(); 37 | 38 | private: 39 | bool GetMappedAudioFiles(CMapStringToString& map); 40 | void SetMappedAudioFiles(CMapStringToString& map); 41 | 42 | void HandleMruList(); 43 | }; 44 | 45 | extern CPlayerApp theApp; 46 | 47 | enum { ID_FIRST_SUBTITLE = 7000, ID_TRACK1 = 7100 }; 48 | -------------------------------------------------------------------------------- /Player/Player.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/Player.rc -------------------------------------------------------------------------------- /Player/PlayerView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IEraseableArea.h" 4 | 5 | #include 6 | 7 | struct IFrameListener; 8 | 9 | struct IDirect3D9; 10 | struct IDirect3DDevice9; 11 | struct IDirect3DSurface9; 12 | struct IDirectXVideoProcessorService; 13 | struct IDirectXVideoProcessor; 14 | 15 | //class CD3DFont; 16 | 17 | class CPlayerDoc; 18 | 19 | //#define USE_DXVA2 20 | 21 | // CPlayerView view 22 | 23 | class CPlayerView : public CView, public IEraseableArea 24 | { 25 | friend class FrameListener; 26 | 27 | DECLARE_DYNCREATE(CPlayerView) 28 | 29 | protected: 30 | CPlayerView(); // protected constructor used by dynamic creation 31 | virtual ~CPlayerView(); 32 | 33 | public: 34 | virtual void OnDraw(CDC* pDC); // overridden to draw this view 35 | #ifdef _DEBUG 36 | virtual void AssertValid() const; 37 | #ifndef _WIN32_WCE 38 | virtual void Dump(CDumpContext& dc) const; 39 | #endif 40 | #endif 41 | 42 | CPlayerDoc* GetDocument() const; 43 | 44 | void updateFrame(); 45 | 46 | void OnErase(CWnd* pInitiator, CDC* pDC, BOOL isFullScreen) override; 47 | 48 | protected: 49 | DECLARE_MESSAGE_MAP() 50 | private: 51 | bool InitializeD3D9(); 52 | bool InitializeExtra(bool createSurface); 53 | void DestroyExtra(); 54 | void DestroyD3D9(); 55 | #ifdef USE_DXVA2 56 | bool CreateDXVA2VPDevice(REFGUID guid, bool bDXVA2SW, bool createSurface); 57 | #endif 58 | bool ResetDevice(); 59 | bool ProcessVideo(); 60 | 61 | CRect GetScreenPosition(bool swapXY); 62 | 63 | private: 64 | std::unique_ptr m_frameListener; 65 | CSize m_sourceSize; 66 | CSize m_aspectRatio; 67 | 68 | CCriticalSection m_csSurface; 69 | 70 | CComPtr m_pD3D9; 71 | CComPtr m_pD3DD9; 72 | CComPtr m_pD3DRT; 73 | CComPtr m_pMainStream; 74 | 75 | bool m_bUseIMC3 = false; 76 | 77 | #ifdef USE_DXVA2 78 | CComPtr m_pDXVAVPS; 79 | CComPtr m_pDXVAVPD; 80 | 81 | LONG m_ProcAmpValues[4] {}; 82 | LONG m_NFilterValues[6] {}; 83 | LONG m_DFilterValues[6] {}; 84 | #endif 85 | 86 | //std::unique_ptr m_subtitleFont; 87 | 88 | public: 89 | afx_msg void OnPaint(); 90 | virtual BOOL PreCreateWindow(CREATESTRUCT& cs); 91 | afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 92 | afx_msg BOOL OnEraseBkgnd(CDC* pDC); 93 | virtual void OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/); 94 | afx_msg void OnDropFiles(HDROP hDropInfo); 95 | afx_msg void OnEditPaste(); 96 | afx_msg void OnEditCopy(); 97 | }; 98 | -------------------------------------------------------------------------------- /Player/PlayerViewD2D.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | struct IFrameListener; 7 | 8 | struct ID2D1Effect; 9 | 10 | class CPlayerViewD2D : public CView 11 | { 12 | friend class FrameListenerD2D; 13 | 14 | protected: // create from serialization only 15 | CPlayerViewD2D(); 16 | DECLARE_DYNCREATE(CPlayerViewD2D) 17 | 18 | // Attributes 19 | public: 20 | CPlayerDoc* GetDocument() const; 21 | 22 | // Operations 23 | public: 24 | 25 | // Overrides 26 | public: 27 | virtual void OnDraw(CDC* pDC); // overridden to draw this view 28 | virtual BOOL PreCreateWindow(CREATESTRUCT& cs); 29 | protected: 30 | virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); 31 | virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); 32 | virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); 33 | 34 | BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) override; 35 | 36 | // Implementation 37 | public: 38 | virtual ~CPlayerViewD2D(); 39 | #ifdef _DEBUG 40 | virtual void AssertValid() const; 41 | virtual void Dump(CDumpContext& dc) const; 42 | #endif 43 | 44 | protected: 45 | 46 | private: 47 | 48 | // Generated message map functions 49 | protected: 50 | DECLARE_MESSAGE_MAP() 51 | afx_msg LRESULT OnDraw2D(WPARAM wParam, LPARAM lParam); 52 | afx_msg LRESULT DrawFrame(WPARAM wParam, LPARAM lParam); 53 | public: 54 | afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 55 | protected: 56 | void updateFrame(); 57 | 58 | private: 59 | std::unique_ptr m_frameListener; 60 | CSize m_sourceSize; 61 | float m_aspectRatio; 62 | CComPtr m_spEffect; 63 | 64 | CCriticalSection m_csSurface; 65 | 66 | public: 67 | afx_msg void OnDropFiles(HDROP hDropInfo); 68 | afx_msg void OnEditPaste(); 69 | }; 70 | -------------------------------------------------------------------------------- /Player/SecondsToString.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | inline std::basic_string secondsToString(int seconds, bool milli) 8 | { 9 | using std::setfill; 10 | using std::setw; 11 | 12 | std::basic_ostringstream buffer; 13 | if (seconds < (milli? 0 : -999)) 14 | { 15 | buffer << '-'; 16 | seconds = -seconds; 17 | } 18 | int ms = seconds % 1000; 19 | seconds /= 1000; // towards zero 20 | int s = seconds % 60; 21 | int m = (seconds / 60) % 60; 22 | int h = seconds / 3600; 23 | 24 | if (h > 0) 25 | { 26 | buffer << h << ':'; 27 | } 28 | buffer << setfill(_T('0')) << setw(2) << m << ':' << setfill(_T('0')) << setw(2) << s; 29 | if (milli) 30 | { 31 | buffer << '.' << setfill(_T('0')) << setw(3) << ms; 32 | } 33 | 34 | return buffer.str(); 35 | } 36 | -------------------------------------------------------------------------------- /Player/StringDifference.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "StringDifference.h" 3 | 4 | #include 5 | 6 | static auto SafePathString(std::basic_string path) 7 | { 8 | enum 9 | { 10 | MAX_DIFF_SIZE = 2048 11 | }; 12 | path.append(MAX_DIFF_SIZE, _T('\0')); 13 | return path; 14 | } 15 | 16 | 17 | template 18 | T reversed(const T& s) 19 | { 20 | return {s.rbegin(), s.rend()}; 21 | } 22 | 23 | template 24 | int levenshteinDistance(const T& s1, const T& s2) 25 | { 26 | const int len1 = s1.size() + 1; 27 | const int len2 = s2.size() + 1; 28 | std::vector dp(len1 * len2); 29 | 30 | for (int i = 0; i < len1; ++i) 31 | { 32 | dp[i * len2] = i; 33 | } 34 | for (int j = 0; j < len2; ++j) 35 | { 36 | dp[j] = j; 37 | } 38 | 39 | for (int i = 1; i < len1; ++i) 40 | { 41 | for (int j = 1; j < len2; ++j) 42 | { 43 | const int cost = (s1[i - 1] != s2[j - 1]); 44 | dp[i * len2 + j] = (std::min)({dp[(i - 1) * len2 + j] + 1, 45 | dp[i * len2 + j - 1] + 1, dp[(i - 1) * len2 + j - 1] + cost}); 46 | } 47 | } 48 | 49 | return dp.back(); 50 | } 51 | 52 | StringDifference::StringDifference(const Sequence& a, const Sequence& b) 53 | : m_diff(a, b), 54 | m_reversedDiff(reversed(a), reversed(b)), 55 | m_path_b(b), 56 | m_sameNames(m_path_b.has_parent_path() && m_path_b.has_stem() && 57 | m_path_b.stem() == std::filesystem::path(a).stem()) 58 | { 59 | if (!m_sameNames) 60 | { 61 | m_diff.compose(); 62 | m_reversedDiff.compose(); 63 | } 64 | } 65 | 66 | StringDifference::Sequence StringDifference::patch(const Sequence& seq) const 67 | { 68 | if (m_sameNames) 69 | { 70 | return (m_path_b.parent_path() / std::filesystem::path(seq).stem()) += 71 | m_path_b.extension(); 72 | } 73 | 74 | Sequence s = m_reversedDiff.patch(SafePathString(reversed(seq))); 75 | std::reverse(s.begin(), s.begin() + _tcslen(s.c_str())); 76 | if (s.empty() || s[0] == 0 || 0 != _taccess(s.c_str(), 04)) 77 | { 78 | s = m_diff.patch(SafePathString(seq)); 79 | if (s.empty() || s[0] == 0 || 0 != _taccess(s.c_str(), 04)) 80 | { 81 | auto closest = LastResort(seq); 82 | if (!closest.empty()) 83 | return closest; 84 | } 85 | } 86 | s.resize(_tcslen(s.c_str())); 87 | return s; 88 | } 89 | 90 | StringDifference::Sequence StringDifference::LastResort( 91 | const StringDifference::Sequence& seq) const 92 | { 93 | try 94 | { 95 | const auto extension = m_path_b.extension(); 96 | const Sequence name = std::filesystem::path(seq).stem(); 97 | int minDistance = INT_MAX; 98 | std::filesystem::path result_name; 99 | for (auto const& dir_entry : std::filesystem::directory_iterator{m_path_b.parent_path()}) 100 | { 101 | if (dir_entry.is_directory()) 102 | continue; 103 | auto path = dir_entry.path(); 104 | if (_tcsicmp(path.extension().c_str(), extension.c_str()) != 0) 105 | continue; 106 | const auto stem = path.stem(); 107 | const int dist = levenshteinDistance(name, static_cast(stem)); 108 | if (dist < minDistance) 109 | { 110 | minDistance = dist; 111 | result_name = stem; 112 | } 113 | else if (dist == minDistance) 114 | { 115 | result_name.clear(); 116 | } 117 | } 118 | if (!result_name.empty()) 119 | { 120 | auto result = (m_path_b.parent_path() / result_name) += extension; 121 | if (equivalent(m_path_b, result)) 122 | return {}; 123 | return result; 124 | } 125 | return {}; 126 | } 127 | catch (const std::exception& ex) 128 | { 129 | TRACE("Exception in StringDifference: %s: %s\n", typeid(ex).name(), ex.what()); 130 | return {}; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Player/StringDifference.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // vcpkg install dtl 4 | #include 5 | 6 | #include 7 | 8 | 9 | class StringDifference 10 | { 11 | typedef std::basic_string Sequence; 12 | 13 | dtl::Diff> m_diff, m_reversedDiff; 14 | std::filesystem::path m_path_b; 15 | bool m_sameNames; 16 | 17 | Sequence LastResort(const StringDifference::Sequence& seq) const; 18 | 19 | public: 20 | StringDifference(const Sequence& a, const Sequence& b); 21 | Sequence patch(const Sequence& seq) const; 22 | }; 23 | -------------------------------------------------------------------------------- /Player/YouTuber.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void CheckPython(); 8 | 9 | std::vector ParsePlaylist(std::string url, bool force); 10 | 11 | std::vector ParsePlaylistFile(const TCHAR* fileName); 12 | 13 | std::vector ParsePlaylistText(const std::string& text); 14 | 15 | std::pair getYoutubeUrl(std::string url, bool adaptive, bool useSAN); 16 | 17 | // start, duration, text 18 | typedef std::function AddYoutubeTranscriptCallback; 19 | 20 | bool getYoutubeTranscripts(std::string url, AddYoutubeTranscriptCallback cb); 21 | -------------------------------------------------------------------------------- /Player/res/Player.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/Player.ico -------------------------------------------------------------------------------- /Player/res/Player.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/Player.rc2 -------------------------------------------------------------------------------- /Player/res/PlayerDoc.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/PlayerDoc.ico -------------------------------------------------------------------------------- /Player/res/Toolbar.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/Toolbar.bmp -------------------------------------------------------------------------------- /Player/res/audio.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/audio.ico -------------------------------------------------------------------------------- /Player/res/audio_off.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/audio_off.ico -------------------------------------------------------------------------------- /Player/res/full_screen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/full_screen.ico -------------------------------------------------------------------------------- /Player/res/launch.mkv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/launch.mkv -------------------------------------------------------------------------------- /Player/res/pause.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/pause.ico -------------------------------------------------------------------------------- /Player/res/play.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Player/res/play.ico -------------------------------------------------------------------------------- /Player/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Player.rc 4 | // 5 | #define IDD_ABOUTBOX 100 6 | #define IDD_DIALOGBAR_PLAYER_CONTROL 103 7 | #define ID_VIEW_CUSTOMIZE 126 8 | #define IDR_MAINFRAME 128 9 | #define IDS_TOOLBAR_CUSTOMIZE 129 10 | #define IDR_PlayerTYPE 130 11 | #define IDS_PlayerControl 130 12 | #define IDS_PLAYER_CONTROL 130 13 | #define IDS_RANGE 131 14 | #define IDS_PAUSE 132 15 | #define IDS_PLAY 133 16 | #define IDI_PAUSE 311 17 | #define IDI_PLAY 312 18 | #define IDI_AUDIO 313 19 | #define IDI_AUDIO_OFF 314 20 | #define IDI_FULL_SCREEN 315 21 | #define IDD_DIALOG_OPEN_URL 317 22 | #define IDD_DIALOGBAR_RANGE 319 23 | #define IDR_LAUNCH 320 24 | #define IDC_PROGRESS_SLIDER 1000 25 | #define IDC_PLAY_PAUSE 1001 26 | #define IDC_AUDIO_ON_OFF 1002 27 | #define IDC_VOLUME_SLIDER 1003 28 | #define IDC_CURRENT_TIME 1004 29 | #define IDC_TOTAL_TIME 1005 30 | #define IDC_EDIT_URL 1005 31 | #define IDC_FULL_SCREEN 1006 32 | #define IDC_FRAME_STEP 1007 33 | #define IDC_START 1008 34 | #define IDC_EDIT_START 1010 35 | #define IDC_START_RESET 1011 36 | #define IDC_END 1012 37 | #define IDC_EDIT_END 1013 38 | #define IDC_END_RESET 1014 39 | #define IDC_PARSE 1016 40 | #define IDC_VIDEO_PROPERTIES 1017 41 | #define IDC_APP_NAME_VERSION 1018 42 | #define IDC_EDIT_INPUT_FORMAT 1019 43 | #define IDC_LOSSLESS_CUT 1020 44 | #define ID_TRACK1_DUMMY 32771 45 | #define ID_AUTOPLAY 32775 46 | #define ID_LOOPING 32776 47 | #define ID_VIDEO_SPEED1 32777 48 | #define ID_VIDEO_SPEED2 32778 49 | #define ID_VIDEO_SPEED3 32779 50 | #define ID_VIDEO_SPEED4 32780 51 | #define ID_VIDEO_SPEED5 32781 52 | #define ID_VIDEO_SPEED6 32782 53 | #define ID_VIDEO_SPEED7 32783 54 | #define ID_NIGHTCORE 32784 55 | #define ID_OPENSUBTITLESFILE 32785 56 | #define ID_COPY_URL_TO_CLIPBOARD 32786 57 | #define ID_MAXIMALRESOLUTION 32787 58 | #define ID_HW_ACCELERATION 32788 59 | #define ID_AUDIO_OPENSUBTITLES 32789 60 | #define ID_FIRST_SUBTITLE_DUMMY 32790 61 | #define ID_SUPER_RESOLUTION 32791 62 | #define ID_ORIENTATION_MIRRORX 32792 63 | #define ID_ORIENTATION_MIRRORY 32793 64 | #define ID_ORIENTATION_UPEND 32794 65 | #define ID_ORIENTATION_DO_NOTHING 32795 66 | #define ID_ORIENTATION_RORATE_90 32796 67 | #define ID_ORIENTATION_RORATE_180 32797 68 | #define ID_ORIENTATION_RORATE_270 32798 69 | #define ID_FIX_ENCODING 32799 70 | #define ID_CONVERT_VIDEOS_INTO_COMPATIBLE_FORMAT 32800 71 | #define ID_OPEN_AUDIO_FILE 32801 72 | #define ID_USING_SAN_CERTIFICATE 32802 73 | 74 | // Next default values for new objects 75 | // 76 | #ifdef APSTUDIO_INVOKED 77 | #ifndef APSTUDIO_READONLY_SYMBOLS 78 | #define _APS_NEXT_RESOURCE_VALUE 321 79 | #define _APS_NEXT_COMMAND_VALUE 32803 80 | #define _APS_NEXT_CONTROL_VALUE 1021 81 | #define _APS_NEXT_SYMED_VALUE 310 82 | #endif 83 | #endif 84 | -------------------------------------------------------------------------------- /Player/stdafx.cpp: -------------------------------------------------------------------------------- 1 | 2 | // stdafx.cpp : source file that includes just the standard includes 3 | // Player.pch will be the pre-compiled header 4 | // stdafx.obj will contain the pre-compiled type information 5 | 6 | #include "stdafx.h" 7 | 8 | 9 | -------------------------------------------------------------------------------- /Player/stdafx.h: -------------------------------------------------------------------------------- 1 | 2 | // stdafx.h : include file for standard system include files, 3 | // or project specific include files that are used frequently, 4 | // but are changed infrequently 5 | 6 | #pragma once 7 | 8 | #ifndef VC_EXTRALEAN 9 | #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 10 | #endif 11 | 12 | #include "targetver.h" 13 | 14 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit 15 | 16 | // turns off MFC's hiding of some common and often safely ignored warning messages 17 | #define _AFX_ALL_WARNINGS 18 | 19 | #include // MFC core and standard components 20 | #include // MFC extensions 21 | 22 | 23 | 24 | 25 | 26 | #ifndef _AFX_NO_OLE_SUPPORT 27 | #include // MFC support for Internet Explorer 4 Common Controls 28 | #endif 29 | #ifndef _AFX_NO_AFXCMN_SUPPORT 30 | #include // MFC support for Windows Common Controls 31 | #endif // _AFX_NO_AFXCMN_SUPPORT 32 | 33 | #include // MFC support for ribbons and control bars 34 | 35 | 36 | 37 | #ifdef _UNICODE 38 | #if defined _M_IX86 39 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 40 | #elif defined _M_X64 41 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 42 | #else 43 | #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 44 | #endif 45 | #endif 46 | -------------------------------------------------------------------------------- /Player/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | 10 | #define _WIN32_WINNT _WIN32_WINNT_WIN8 11 | #define NTDDI_VERSION NTDDI_WIN8 12 | #define WINVER _WIN32_WINNT_WIN8 13 | #define _WIN32_IE _WIN32_IE_WIN8 14 | 15 | #include 16 | -------------------------------------------------------------------------------- /Player/update_version.cmd: -------------------------------------------------------------------------------- 1 | %~dp0\version.h.tmp 2 | git --work-tree=%~dp0 rev-parse --short HEAD >> %~dp0\version.h.tmp 3 | if %ERRORLEVEL% neq 0 echo #define NO_GIT_COMMIT > %~dp0\version.h.tmp 4 | fc %~dp0\version.h.tmp %~dp0\version.h 5 | if %ERRORLEVEL% neq 0 copy /Y %~dp0\version.h.tmp %~dp0\version.h 6 | del %~dp0\version.h.tmp 7 | -------------------------------------------------------------------------------- /QtPlayer/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /QtPlayer/.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | *.slo 3 | *.lo 4 | *.o 5 | *.a 6 | *.la 7 | *.lai 8 | *.so 9 | *.dll 10 | *.dylib 11 | 12 | # Qt-es 13 | object_script.*.Release 14 | object_script.*.Debug 15 | *_plugin_import.cpp 16 | /.qmake.cache 17 | /.qmake.stash 18 | *.pro.user 19 | *.pro.user.* 20 | *.qbs.user 21 | *.qbs.user.* 22 | *.moc 23 | moc_*.cpp 24 | moc_*.h 25 | qrc_*.cpp 26 | ui_*.h 27 | *.qmlc 28 | *.jsc 29 | Makefile* 30 | *build-* 31 | 32 | # Qt unit tests 33 | target_wrapper.* 34 | 35 | # QtCreator 36 | *.autosave 37 | 38 | # QtCreator Qml 39 | *.qmlproject.user 40 | *.qmlproject.user.* 41 | 42 | # QtCreator CMake 43 | CMakeLists.txt.user* 44 | CMake*Presets.json 45 | -------------------------------------------------------------------------------- /QtPlayer/customdockwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "customdockwidget.h" 2 | #include "mainwindow.h" 3 | #include "videoplayerwidget.h" 4 | #include "videowidget.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | CustomDockWidget::CustomDockWidget(QWidget* widget) : QWidget(widget) 11 | { 12 | } 13 | 14 | void CustomDockWidget::setDisplayForFullscreen(VideoDisplay* display) 15 | { 16 | Q_ASSERT(display != nullptr); 17 | m_display = dynamic_cast(display); 18 | } 19 | 20 | void CustomDockWidget::closeEvent(QCloseEvent* event) 21 | { 22 | event->ignore(); 23 | } 24 | 25 | void CustomDockWidget::keyPressEvent(QKeyEvent* event) 26 | { 27 | // Player fullscreen in 28 | if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && (event->modifiers() & Qt::AltModifier)) 29 | { 30 | setVisibilityState(FullScreen); 31 | event->ignore(); 32 | } 33 | QWidget::keyPressEvent(event); 34 | } 35 | 36 | void CustomDockWidget::setVisibilityState(VisibilityState state) 37 | { 38 | if (state == m_state) 39 | { 40 | return; 41 | } 42 | 43 | switch (state) 44 | { 45 | case ShownDocked: 46 | { 47 | this->setVisible(true); 48 | } 49 | break; 50 | case FullScreen: 51 | { 52 | bool prevIsFullScreen = m_display->isFullScreen(); 53 | m_display->fullScreen(!prevIsFullScreen); 54 | if (m_display->isFullScreen() == prevIsFullScreen) 55 | { 56 | return; 57 | } 58 | // emit enterFullscreen(true); 59 | } 60 | break; 61 | } 62 | m_prevState = m_state; 63 | m_state = state; 64 | } 65 | 66 | void CustomDockWidget::onLeaveFullScreen() 67 | { 68 | if (m_display->isFullScreen()) 69 | { 70 | m_display->fullScreen(false); 71 | } 72 | setVisibilityState(m_prevState); 73 | } 74 | -------------------------------------------------------------------------------- /QtPlayer/customdockwidget.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class VideoDisplay; 6 | class VideoWidget; 7 | 8 | 9 | class CustomDockWidget : public QWidget 10 | { 11 | Q_OBJECT 12 | public: 13 | CustomDockWidget(QWidget* widget = nullptr); 14 | void setDisplayForFullscreen(VideoDisplay* display); 15 | 16 | enum VisibilityState 17 | { 18 | ShownDocked = 0, 19 | FullScreen 20 | }; 21 | 22 | void setVisibilityState(VisibilityState state); 23 | VisibilityState currentState() const { return m_state; } 24 | VisibilityState previousState() const { return m_prevState; } 25 | 26 | protected: 27 | void closeEvent(QCloseEvent* event) override; 28 | void keyPressEvent(QKeyEvent* event) override; 29 | 30 | signals: 31 | bool enterFullscreen(bool f); 32 | 33 | public slots: 34 | void onLeaveFullScreen(); 35 | 36 | private: 37 | VisibilityState m_state{ShownDocked}; 38 | VisibilityState m_prevState{ShownDocked}; 39 | VideoWidget* m_display{}; 40 | }; 41 | -------------------------------------------------------------------------------- /QtPlayer/ffmpegdecoder.cpp: -------------------------------------------------------------------------------- 1 | #include "ffmpegdecoder.h" 2 | 3 | //#include "../audio/AudioPlayerWasapi.h" 4 | 5 | #include "portaudioplayer.h" 6 | 7 | #include "videodisplay.h" 8 | 9 | FFmpegDecoderWrapper::FFmpegDecoderWrapper() 10 | : m_frameDecoder( 11 | GetFrameDecoder(std::make_unique())) 12 | { 13 | m_frameDecoder->setDecoderListener(this); 14 | } 15 | 16 | FFmpegDecoderWrapper::~FFmpegDecoderWrapper() = default; 17 | 18 | void FFmpegDecoderWrapper::setFrameListener(VideoDisplay* listener) 19 | { 20 | m_frameDecoder->setFrameListener(listener); 21 | if (listener != nullptr) { 22 | listener->setDecoderObject(this); 23 | } 24 | } 25 | 26 | bool FFmpegDecoderWrapper::openFile(const QString& file) 27 | { 28 | return m_frameDecoder->openUrls({file.toStdString()}); 29 | } 30 | -------------------------------------------------------------------------------- /QtPlayer/ffmpegdecoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../video/decoderinterface.h" 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | class VideoDisplay; 12 | 13 | class FFmpegDecoderWrapper : public QObject, public FrameDecoderListener 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | FFmpegDecoderWrapper(); 19 | ~FFmpegDecoderWrapper() override; 20 | 21 | FFmpegDecoderWrapper(const FFmpegDecoderWrapper&) = delete; 22 | FFmpegDecoderWrapper& operator=(const FFmpegDecoderWrapper&) = delete; 23 | 24 | void setFrameListener(VideoDisplay* listener); 25 | 26 | bool openFile(const QString& file); 27 | void play(bool isPaused = false) { m_frameDecoder->play(); } 28 | bool pauseResume() { return m_frameDecoder->pauseResume(); } 29 | void close(bool isBlocking = true) { m_frameDecoder->close(); } 30 | void setVolume(double volume) 31 | { 32 | m_frameDecoder->setVolume(volume); 33 | emit volumeChanged(volume); 34 | } 35 | bool seekByPercent(float percent) { return m_frameDecoder->seekByPercent(percent); } 36 | 37 | double volume() const { return m_frameDecoder->volume(); } 38 | bool isPlaying() const { return m_frameDecoder->isPlaying(); } 39 | 40 | void finishedDisplayingFrame(unsigned int generation) { m_frameDecoder->finishedDisplayingFrame(generation); } 41 | 42 | IFrameDecoder* getFrameDecoder() const { return m_frameDecoder.get(); } 43 | 44 | void playingFinished() override { emit onPlayingFinished(); } 45 | void changedFramePosition( 46 | long long start, long long frame, long long total) override 47 | { 48 | emit onChangedFramePosition(frame - start, total - start); 49 | } 50 | 51 | signals: 52 | void onPlayingFinished(); 53 | void onChangedFramePosition(qint64, qint64); 54 | void volumeChanged(double /*unused*/) override; 55 | 56 | private: 57 | std::unique_ptr m_frameDecoder; 58 | }; 59 | -------------------------------------------------------------------------------- /QtPlayer/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | static void init_logging() 18 | { 19 | namespace expr = boost::log::expressions; 20 | 21 | boost::log::add_common_attributes(); 22 | 23 | auto core = boost::log::core::get(); 24 | 25 | #ifdef Q_OS_WIN 26 | // Create the sink. The backend requires synchronization in the frontend. 27 | auto sink(boost::make_shared>()); 28 | #else 29 | auto sink = boost::make_shared>(); 30 | #endif 31 | 32 | sink->set_formatter(expr::stream 33 | //<< '[' << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S.%f") << ']' 34 | << expr::if_(expr::has_attr("Severity")) 35 | [ 36 | expr::stream << '[' << expr::attr< boost::log::trivial::severity_level >("Severity") << ']' 37 | ] 38 | << expr::if_(expr::has_attr("Channel")) 39 | [ 40 | expr::stream << '[' << expr::attr< std::string >("Channel") << ']' 41 | ] 42 | << expr::smessage << '\n'); 43 | 44 | // Set the special filter to the frontend 45 | // in order to skip the sink when no debugger is available 46 | //sink->set_filter(expr::is_debugger_present()); 47 | 48 | core->add_sink(sink); 49 | } 50 | 51 | int main(int argc, char *argv[]) 52 | { 53 | init_logging(); 54 | 55 | QApplication a(argc, argv); 56 | MainWindow w; 57 | w.show(); 58 | return QApplication::exec(); 59 | } 60 | -------------------------------------------------------------------------------- /QtPlayer/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "./ui_mainwindow.h" 3 | 4 | #include "videowidget.h" 5 | 6 | #include 7 | #include 8 | 9 | MainWindow* getMainWindow() 10 | { 11 | for (QWidget* widget : QApplication::topLevelWidgets()) { 12 | if (auto *mainWindow = qobject_cast(widget)) { 13 | return mainWindow; 14 | } 15 | } 16 | return nullptr; 17 | } 18 | 19 | 20 | MainWindow::MainWindow(QWidget *parent) 21 | : QMainWindow(parent) 22 | , ui(new Ui::MainWindow) 23 | { 24 | ui->setupUi(this); 25 | 26 | auto m_player = ui->videoPlayerWidget; 27 | 28 | m_player->setProgressbar(ui->videoProgress); 29 | 30 | ui->dockWidget->installEventFilter(m_player); 31 | ui->dockWidget->setDisplayForFullscreen(m_player->getCurrentDisplay()); 32 | 33 | setCentralWidget(ui->dockWidget); 34 | 35 | connect(m_player->videoWidget(), &VideoWidget::leaveFullScreen, ui->dockWidget, &CustomDockWidget::onLeaveFullScreen); 36 | 37 | connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::onFileOpen); 38 | connect(ui->actionOpenUrl, &QAction::triggered, this, &MainWindow::onUrlOpen); 39 | } 40 | 41 | MainWindow::~MainWindow() 42 | { 43 | delete ui; 44 | } 45 | 46 | CustomDockWidget* MainWindow::dockWidget() 47 | { 48 | return ui->dockWidget; 49 | } 50 | 51 | QWidget* MainWindow::videoControlWidget() 52 | { 53 | return ui->videoControl; 54 | } 55 | 56 | VideoPlayerWidget* MainWindow::getPlayer() 57 | { 58 | return ui->videoPlayerWidget; 59 | } 60 | 61 | void MainWindow::onFileOpen() 62 | { 63 | auto fileName = QFileDialog::getOpenFileName( 64 | this, 65 | tr("Open Video File")); 66 | if (!fileName.isEmpty()) 67 | { 68 | getPlayer()->playFile(fileName); 69 | } 70 | } 71 | 72 | void MainWindow::onUrlOpen() 73 | { 74 | QInputDialog dialog(this); 75 | dialog.setWindowTitle(tr("Open URL")); 76 | dialog.setLabelText(tr("Url to open:")); 77 | if (dialog.exec() == QDialog::Accepted) 78 | { 79 | QString fileName = dialog.textValue(); 80 | if (!fileName.isEmpty()) 81 | { 82 | getPlayer()->playFile(fileName); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /QtPlayer/mainwindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | QT_BEGIN_NAMESPACE 6 | namespace Ui { class MainWindow; } 7 | QT_END_NAMESPACE 8 | 9 | class CustomDockWidget; 10 | class VideoPlayerWidget; 11 | 12 | class MainWindow : public QMainWindow 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | MainWindow(QWidget *parent = nullptr); 18 | ~MainWindow() override; 19 | 20 | 21 | CustomDockWidget* dockWidget(); 22 | QWidget* videoControlWidget(); 23 | VideoPlayerWidget* getPlayer(); 24 | 25 | private: 26 | void onFileOpen(); 27 | void onUrlOpen(); 28 | 29 | private: 30 | Ui::MainWindow *ui; 31 | }; 32 | 33 | MainWindow* getMainWindow(); 34 | -------------------------------------------------------------------------------- /QtPlayer/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 803 10 | 604 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 0 20 | 0 21 | 22 | 23 | 24 | 25 | 16777215 26 | 16777215 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 0 35 | 36 | 37 | 0 38 | 39 | 40 | 41 | 42 | Qt::StrongFocus 43 | 44 | 45 | 46 | 47 | 48 | QFrame::NoFrame 49 | 50 | 51 | QFrame::Plain 52 | 53 | 54 | 0 55 | 56 | 57 | 58 | 59 | 0 60 | 238 61 | 230 62 | 16 63 | 64 | 65 | 66 | 67 | 68 | 69 | 0 70 | 220 71 | 229 72 | 18 73 | 74 | 75 | 76 | 77 | 16777215 78 | 18 79 | 80 | 81 | 82 | 83 | 84 | 85 | 10000 86 | 87 | 88 | 0 89 | 90 | 91 | false 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 0 102 | 0 103 | 803 104 | 21 105 | 106 | 107 | 108 | 109 | File 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | Open 120 | 121 | 122 | 123 | 124 | Open URL 125 | 126 | 127 | 128 | 129 | 130 | VideoControl 131 | QWidget 132 |
videocontrol.h
133 | 1 134 |
135 | 136 | CustomDockWidget 137 | QWidget 138 |
customdockwidget.h
139 | 1 140 |
141 | 142 | VideoPlayerWidget 143 | QFrame 144 |
videoplayerwidget.h
145 | 1 146 |
147 | 148 | VideoProgressBar 149 | QProgressBar 150 |
videoprogressbar.h
151 |
152 |
153 | 154 | 155 | 156 | 157 |
158 | -------------------------------------------------------------------------------- /QtPlayer/mousehoverbutton.cpp: -------------------------------------------------------------------------------- 1 | #include "mousehoverbutton.h" 2 | #include 3 | 4 | MouseHoverButton::MouseHoverButton(QWidget* parent) : QToolButton(parent) 5 | { 6 | } 7 | 8 | 9 | MouseHoverButton::~MouseHoverButton() = default; 10 | 11 | void MouseHoverButton::mousePressEvent(QMouseEvent* event) 12 | { 13 | if (m_defIcon.isNull()) 14 | { 15 | m_defIcon = icon(); 16 | QList normalOnSizes = m_defIcon.availableSizes(QIcon::Normal, QIcon::On); 17 | if (!normalOnSizes.empty()) 18 | { 19 | // use normal/on image as pushed one 20 | m_pushedIcon = m_defIcon.pixmap(*normalOnSizes.begin(), QIcon::Normal, QIcon::On); 21 | } 22 | } 23 | QToolButton::mousePressEvent(event); 24 | if (event->buttons() & Qt::LeftButton) 25 | { 26 | setIcon(m_pushedIcon); 27 | } 28 | } 29 | 30 | void MouseHoverButton::mouseReleaseEvent(QMouseEvent* event) 31 | { 32 | if (event->button() == Qt::LeftButton) 33 | { 34 | setIcon(m_defIcon); 35 | } 36 | QToolButton::mouseReleaseEvent(event); 37 | } 38 | 39 | void MouseHoverButton::keyReleaseEvent(QKeyEvent* e) 40 | { 41 | Q_UNUSED(e) 42 | // do nothing so button won't process key events 43 | } 44 | 45 | void MouseHoverButton::paintEvent(QPaintEvent* event) 46 | { 47 | bool isButtonDown = isDown(); 48 | setDown(false); 49 | QToolButton::paintEvent(event); 50 | setDown(isButtonDown); 51 | } 52 | -------------------------------------------------------------------------------- /QtPlayer/mousehoverbutton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /* 7 | Since Qt tool button pushes icon's image for pressed state, we have own implementation. 8 | To get it properly worked next images should be assigned to 9 | next button states programmatically or in the Qt designer: 10 | Normal Off - default image 11 | Normal On - clicked image 12 | Disabled Off - disabled image 13 | Disabled On - disabled image 14 | Active Off - hover image 15 | Active On - hover image 16 | Selected Off - default image 17 | Selected On - default image 18 | */ 19 | class MouseHoverButton : public QToolButton 20 | { 21 | Q_OBJECT 22 | public: 23 | MouseHoverButton(QWidget* parent); 24 | ~MouseHoverButton() override; 25 | protected: 26 | void mousePressEvent(QMouseEvent* event) override; 27 | void mouseReleaseEvent(QMouseEvent* event) override; 28 | void keyReleaseEvent(QKeyEvent* e) override; 29 | void paintEvent(QPaintEvent* event) override; 30 | private: 31 | QIcon m_defIcon; 32 | QIcon m_pushedIcon; 33 | }; 34 | -------------------------------------------------------------------------------- /QtPlayer/opengldisplay.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENGLDISPLAY_H 2 | #define OPENGLDISPLAY_H 3 | 4 | // https://github.com/MasterAler/SampleYUVRenderer 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "videodisplay.h" 12 | 13 | class OpenGLDisplay : public QOpenGLWidget, public QOpenGLFunctions, public VideoDisplay 14 | { 15 | Q_OBJECT 16 | public: 17 | explicit OpenGLDisplay(QWidget* parent = nullptr); 18 | ~OpenGLDisplay() override; 19 | 20 | void InitDrawBuffer(unsigned bsize); 21 | 22 | void showPicture(const QImage& img) override; 23 | void showPicture(const QPixmap& picture) override; 24 | 25 | // decoder->finishedDisplayingFrame() must be called 26 | void updateFrame(IFrameDecoder* decoder, unsigned int generation) override; 27 | void drawFrame(IFrameDecoder* decoder, unsigned int generation) override; 28 | void decoderClosing() override; 29 | 30 | float aspectRatio() const; 31 | 32 | protected: 33 | void initializeGL() override; 34 | void paintGL() override; 35 | 36 | private: 37 | struct OpenGLDisplayImpl; 38 | QScopedPointer impl; 39 | }; 40 | 41 | /***********************************************************************/ 42 | 43 | class OpenGlException: public QException 44 | { 45 | public: 46 | void raise() const override { throw *this; } 47 | OpenGlException *clone() const override { return new OpenGlException(*this); } 48 | }; 49 | 50 | #endif // OPENGLDISPLAY_H 51 | -------------------------------------------------------------------------------- /QtPlayer/portaudioplayer.cpp: -------------------------------------------------------------------------------- 1 | #include "portaudioplayer.h" 2 | 3 | #include 4 | #include 5 | 6 | PortAudioPlayer::PortAudioPlayer() 7 | { 8 | auto err = Pa_Initialize(); 9 | } 10 | 11 | PortAudioPlayer::~PortAudioPlayer() 12 | { 13 | auto err = Pa_Terminate(); 14 | } 15 | 16 | void PortAudioPlayer::InitializeThread() 17 | { 18 | QThread::currentThread()->setPriority(QThread::TimeCriticalPriority); 19 | } 20 | 21 | bool PortAudioPlayer::Open(int bytesPerSample, int channels, int* samplesPerSec) 22 | { 23 | PaStreamParameters params{}; 24 | params.device = Pa_GetDefaultOutputDevice(); 25 | params.suggestedLatency = Pa_GetDeviceInfo(params.device)->defaultLowOutputLatency; 26 | params.channelCount = channels; 27 | 28 | switch (bytesPerSample) 29 | { 30 | case 1: 31 | params.sampleFormat = paInt8; 32 | break; 33 | case 2: 34 | params.sampleFormat = paInt16; 35 | break; 36 | case 4: 37 | params.sampleFormat = paInt32; 38 | break; 39 | } 40 | 41 | auto err{ Pa_OpenStream(&m_stream, nullptr, ¶ms, *samplesPerSec, paFramesPerBufferUnspecified, 42 | paNoFlag, nullptr, nullptr) }; 43 | 44 | if (err != paNoError) { 45 | return false; 46 | } 47 | 48 | err = Pa_StartStream(m_stream); 49 | 50 | m_FrameSize = bytesPerSample * channels; 51 | 52 | *samplesPerSec = m_samplesPerSec = Pa_GetStreamInfo(m_stream)->sampleRate; 53 | 54 | return true; 55 | } 56 | 57 | void PortAudioPlayer::Close() 58 | { 59 | auto err = Pa_CloseStream(m_stream); 60 | m_stream = nullptr; 61 | } 62 | 63 | bool PortAudioPlayer::WriteAudio(uint8_t* write_data, int64_t write_size) 64 | { 65 | if (!m_stream) { 66 | return false; 67 | } 68 | 69 | auto* realData = (int16_t*)write_data; 70 | for (unsigned int i = 0; i < write_size / 2; ++i) { 71 | realData[i] *= m_volume; 72 | } 73 | 74 | const auto framesToWrite = write_size / m_FrameSize; 75 | auto err = Pa_WriteStream(m_stream, write_data, framesToWrite); 76 | if (err == paStreamIsStopped && Pa_StartStream(m_stream) == paNoError) 77 | { 78 | err = Pa_WriteStream(m_stream, write_data, framesToWrite); 79 | } 80 | 81 | // count audio pts 82 | const double frame_clock = (double)framesToWrite / m_samplesPerSec; 83 | m_callback->AppendFrameClock(frame_clock); 84 | 85 | return err == paNoError; 86 | } 87 | 88 | void PortAudioPlayer::WaveOutReset() 89 | { 90 | Pa_AbortStream(m_stream); 91 | } 92 | 93 | void PortAudioPlayer::WaveOutPause() 94 | { 95 | Pa_StopStream(m_stream); 96 | } 97 | 98 | void PortAudioPlayer::WaveOutRestart() 99 | { 100 | Pa_StartStream(m_stream); 101 | } 102 | -------------------------------------------------------------------------------- /QtPlayer/portaudioplayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../video/audioplayer.h" 4 | 5 | 6 | class PortAudioPlayer : 7 | public IAudioPlayer 8 | { 9 | public: 10 | PortAudioPlayer(); 11 | ~PortAudioPlayer() override; 12 | 13 | PortAudioPlayer(const PortAudioPlayer&) = delete; 14 | PortAudioPlayer& operator=(const PortAudioPlayer&) = delete; 15 | 16 | void SetCallback(IAudioPlayerCallback* callback) override 17 | { 18 | m_callback = callback; 19 | } 20 | 21 | void InitializeThread() override; 22 | void DeinitializeThread() override {} 23 | 24 | void WaveOutReset() override; 25 | 26 | void Close() override; 27 | bool Open(int bytesPerSample, int channels, int* samplesPerSec) override; 28 | 29 | void SetVolume(double volume) override { m_volume = volume; } 30 | double GetVolume() const override { return m_volume; } 31 | 32 | void WaveOutPause() override; 33 | void WaveOutRestart() override; 34 | 35 | bool WriteAudio(uint8_t* write_data, int64_t write_size) override; 36 | 37 | private: 38 | IAudioPlayerCallback* m_callback{}; 39 | void* m_stream{}; 40 | 41 | int m_FrameSize{}; 42 | double m_samplesPerSec{}; 43 | double m_volume = 1.; 44 | }; 45 | -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/icodelete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/icodelete.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/icoplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/icoplay.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_globe___click___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_globe___click___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_globe___default___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_globe___default___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_globe___hover___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_globe___hover___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_pause___clicked___(40x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_pause___clicked___(40x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_pause___default___(40x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_pause___default___(40x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_pause___hover___(40x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_pause___hover___(40x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_play___clicked___(40x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_play___clicked___(40x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_play___default___(40x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_play___default___(40x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_play___hover___(40x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_play___hover___(40x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_sound_off___clicked___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_sound_off___clicked___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_sound_off___default___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_sound_off___default___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_sound_off___hover___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_sound_off___hover___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_sound_on___clicked___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_sound_on___clicked___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_sound_on___default___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_sound_on___default___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_sound_on___hover___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_sound_on___hover___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_stop___clicked___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_stop___clicked___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_stop___default___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_stop___default___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player___btn_stop___hover___(31x31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player___btn_stop___hover___(31x31).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player_bg___(230x41).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player_bg___(230x41).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/control/player_bg_fs___(230x41).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/control/player_bg_fs___(230x41).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/help41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/help41.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/play_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/play_transparent.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/spinner.gif -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/box-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/box-shadow.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/busy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/busy.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/button-blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/button-blank.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/button_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/button_disable.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/button_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/button_down.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/button_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/button_hover.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/button_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/button_normal.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/circle-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/circle-shadow.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/down_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/down_arrow.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/down_arrow_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/down_arrow_grey.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/floatpanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/floatpanel.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/header_arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/header_arrow_down.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/header_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/header_line.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/lineedit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/lineedit.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/progress_dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/progress_dropdown.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-button-down-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-button-down-hover.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-button-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-button-down.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-button-left-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-button-left-hover.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-button-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-button-left.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-button-right-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-button-right-hover.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-button-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-button-right.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-button-up-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-button-up-hover.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-button-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-button-up.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-hhandle-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-hhandle-hover.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-hhandle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-hhandle.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-vhandle-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-vhandle-hover.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/scroll-vhandle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/scroll-vhandle.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/style/tooltip-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/style/tooltip-background.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/triangle_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/triangle_down.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/triangle_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/triangle_right.png -------------------------------------------------------------------------------- /QtPlayer/resources/images/video___btn_play___clicked___(94x94).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/video___btn_play___clicked___(94x94).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/video___btn_play___default___(94x94).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/video___btn_play___default___(94x94).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/video___btn_play___hover___(94x94).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/video___btn_play___hover___(94x94).png -------------------------------------------------------------------------------- /QtPlayer/resources/images/video_seek_cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/QtPlayer/resources/images/video_seek_cursor.png -------------------------------------------------------------------------------- /QtPlayer/resources/qt.conf: -------------------------------------------------------------------------------- 1 | [Paths] 2 | Plugins = . -------------------------------------------------------------------------------- /QtPlayer/resources/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | style.css 4 | images/help41.png 5 | images/style/button_disable.png 6 | images/style/button_down.png 7 | images/style/button_hover.png 8 | images/style/button_normal.png 9 | images/style/header_arrow_down.png 10 | images/style/down_arrow.png 11 | images/style/lineedit.png 12 | images/style/down_arrow_grey.png 13 | images/play_transparent.png 14 | images/video___btn_play___default___(94x94).png 15 | images/video___btn_play___hover___(94x94).png 16 | images/video___btn_play___clicked___(94x94).png 17 | images/style/box-shadow.png 18 | images/style/busy.png 19 | images/style/button-blank.png 20 | images/style/floatpanel.png 21 | images/spinner.gif 22 | images/triangle_down.png 23 | images/triangle_right.png 24 | images/style/progress_dropdown.png 25 | images/style/circle-shadow.png 26 | images/style/tooltip-background.png 27 | images/video_seek_cursor.png 28 | 29 | 30 | images/style/header_line.png 31 | images/style/scroll-button-down.png 32 | images/style/scroll-button-down-hover.png 33 | images/style/scroll-button-up.png 34 | images/style/scroll-button-up-hover.png 35 | images/style/scroll-vhandle.png 36 | images/style/scroll-vhandle-hover.png 37 | images/style/scroll-button-left.png 38 | images/style/scroll-button-left-hover.png 39 | images/style/scroll-button-right.png 40 | images/style/scroll-button-right-hover.png 41 | images/style/scroll-hhandle.png 42 | images/style/scroll-hhandle-hover.png 43 | 44 | 45 | images/control/player_bg___(230x41).png 46 | images/control/player_bg_fs___(230x41).png 47 | images/control/player___btn_play___default___(40x31).png 48 | images/control/player___btn_play___clicked___(40x31).png 49 | images/control/player___btn_play___hover___(40x31).png 50 | images/control/player___btn_stop___default___(31x31).png 51 | images/control/player___btn_stop___clicked___(31x31).png 52 | images/control/player___btn_stop___hover___(31x31).png 53 | images/control/player___btn_globe___default___(31x31).png 54 | images/control/player___btn_globe___click___(31x31).png 55 | images/control/player___btn_globe___hover___(31x31).png 56 | images/control/player___btn_sound_on___default___(31x31).png 57 | images/control/player___btn_sound_on___clicked___(31x31).png 58 | images/control/player___btn_sound_on___hover___(31x31).png 59 | images/control/player___btn_sound_off___default___(31x31).png 60 | images/control/player___btn_sound_off___clicked___(31x31).png 61 | images/control/player___btn_sound_off___hover___(31x31).png 62 | images/control/player___btn_pause___default___(40x31).png 63 | images/control/player___btn_pause___clicked___(40x31).png 64 | images/control/player___btn_pause___hover___(40x31).png 65 | images/control/icodelete.png 66 | images/control/icoplay.png 67 | 68 | 69 | -------------------------------------------------------------------------------- /QtPlayer/resources/win7.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /QtPlayer/resources/winres.rc.in: -------------------------------------------------------------------------------- 1 | #include "verrsrc.h" 2 | 3 | IDI_ICON1 ICON "@ICON_FILE@" 4 | 5 | #define VER_FILEVERSION @MAJOR_VER@,@MINOR_VER1@,@MINOR_VER2@,@MINOR_VER3@ 6 | #define VER_FILEVERSION_STR "@MAJOR_VER@.@MINOR_VER1@.@MINOR_VER2@.@MINOR_VER3@\0" 7 | 8 | #define VER_PRODUCTVERSION @MAJOR_VER@,@MINOR_VER1@,@MINOR_VER2@,@MINOR_VER3@ 9 | #define VER_PRODUCTVERSION_STR "@MAJOR_VER@.@MINOR_VER1@.@MINOR_VER2@.@MINOR_VER3@\0" 10 | 11 | 12 | 1 VERSIONINFO 13 | FILEVERSION VER_FILEVERSION 14 | PRODUCTVERSION VER_PRODUCTVERSION 15 | FILEFLAGSMASK 0x3fL 16 | #ifdef _DEBUG 17 | FILEFLAGS 0x1L 18 | #else 19 | FILEFLAGS 0x0L 20 | #endif 21 | FILEOS VOS_NT_WINDOWS32 22 | FILETYPE VFT_APP 23 | FILESUBTYPE 0x0L 24 | BEGIN 25 | BLOCK "StringFileInfo" 26 | BEGIN 27 | BLOCK "040904e4" 28 | BEGIN 29 | VALUE "CompanyName", "@COMPANYNAME@\0" 30 | VALUE "FileDescription", "@PRODUCTNAME@\0" 31 | VALUE "FileVersion", VER_FILEVERSION_STR 32 | VALUE "LegalCopyright", "Copyright (C) 2013 @COMPANYNAME@ All Rights Reserved.\0" 33 | VALUE "ProductName", "@PRODUCTNAME@\0" 34 | VALUE "ProductVersion", VER_PRODUCTVERSION_STR 35 | VALUE "OriginalFilename", "@SHORTPRODUCTNAME@.exe\0" 36 | VALUE "InternalName", "@SHORTPRODUCTNAME@\0" 37 | END 38 | END 39 | BLOCK "VarFileInfo" 40 | BEGIN 41 | /* The following line should only be modified for localized versions. */ 42 | /* It consists of any number of WORD,WORD pairs, with each pair */ 43 | /* describing a language,codepage combination supported by the file. */ 44 | /* */ 45 | /* For example, a file might have values "0x409,1252" indicating that it */ 46 | /* supports English language (0x409) in the Windows ANSI codepage (1252). */ 47 | 48 | VALUE "Translation", 0x409, 1252 49 | END 50 | END 51 | -------------------------------------------------------------------------------- /QtPlayer/videocontrol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class VideoPlayerWidget; 6 | 7 | namespace Ui 8 | { 9 | class VideoControl; 10 | } 11 | 12 | class VideoControl : public QWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit VideoControl(VideoPlayerWidget* parent = nullptr); 18 | ~VideoControl() override; 19 | void setVolume(int volume, bool onlyWidget = false); 20 | void showPlaybutton(bool show = true); 21 | 22 | int getHeight() const { return m_height; }; 23 | int getWidth() const; 24 | 25 | signals: 26 | void download(); 27 | void browse(); 28 | 29 | protected: 30 | bool eventFilter(QObject* obj, QEvent* event) override; 31 | void paintEvent(QPaintEvent* event) override; 32 | void resizeEvent(QResizeEvent* event)override; 33 | void wheelEvent(QWheelEvent* event) override; 34 | 35 | public slots: 36 | void on_btnPlay_clicked(); 37 | void on_btnPause_clicked(); 38 | 39 | private slots: 40 | void onProgramVolumeChange(double volume); 41 | void on_btnVolume_clicked(); 42 | void on_btnStop_clicked(); 43 | void on_btnBrowser_clicked(); 44 | 45 | private: 46 | Ui::VideoControl* ui; 47 | VideoPlayerWidget* videoPlayer; 48 | int m_height; 49 | QPixmap background; 50 | QPixmap backgroundfs; 51 | bool m_isVolumeOn{false}; 52 | int m_prevVolumeValue{0}; 53 | 54 | void switchVolumeButton(bool volumeOn); 55 | }; 56 | -------------------------------------------------------------------------------- /QtPlayer/videodisplay.cpp: -------------------------------------------------------------------------------- 1 | #include "videodisplay.h" 2 | 3 | VideoDisplay::VideoDisplay() = default; 4 | 5 | VideoDisplay::~VideoDisplay() 6 | { 7 | if (m_decoder != nullptr) { 8 | m_decoder->setFrameListener(nullptr); 9 | } 10 | } 11 | 12 | void VideoDisplay::setDecoderObject(FFmpegDecoderWrapper* decoder) 13 | { 14 | Q_ASSERT(decoder != nullptr); 15 | if (m_decoder != decoder) 16 | { 17 | m_decoder = decoder; 18 | m_decoder->setFrameListener(this); 19 | m_decoder->getFrameDecoder()->SetFrameFormat( 20 | #ifdef DEVELOPER_OPENGL 21 | IFrameDecoder::PIX_FMT_YUV420P 22 | #else 23 | IFrameDecoder::PIX_FMT_RGB24 24 | #endif 25 | , false); 26 | } 27 | } 28 | 29 | void VideoDisplay::finishedDisplayingFrame(unsigned int generation) 30 | { 31 | m_decoder->finishedDisplayingFrame(generation); 32 | } 33 | -------------------------------------------------------------------------------- /QtPlayer/videodisplay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "ffmpegdecoder.h" 6 | 7 | class VideoDisplay : public IFrameListener 8 | { 9 | public: 10 | VideoDisplay(); 11 | ~VideoDisplay() override; 12 | void finishedDisplayingFrame(unsigned int generation); 13 | void setDecoderObject(FFmpegDecoderWrapper* decoder); 14 | 15 | virtual void showPicture(const QImage& picture) = 0; 16 | virtual void showPicture(const QPixmap& picture) = 0; 17 | 18 | void setPreferredSize(int scrWidth, int scrHeight) 19 | { 20 | m_scrWidth = scrWidth; 21 | m_scrHeight = scrHeight; 22 | } 23 | 24 | protected: 25 | FFmpegDecoderWrapper* m_decoder{nullptr}; 26 | int m_scrWidth{}; 27 | int m_scrHeight{}; 28 | }; 29 | -------------------------------------------------------------------------------- /QtPlayer/videoplayer.cpp: -------------------------------------------------------------------------------- 1 | #include "videoplayer.h" 2 | #include "widgetdisplay.h" 3 | 4 | #include 5 | 6 | VideoPlayer::VideoPlayer() = default; 7 | 8 | VideoPlayer::~VideoPlayer() 9 | { 10 | delete m_display; 11 | } 12 | 13 | FFmpegDecoderWrapper* VideoPlayer::getDecoder() 14 | { 15 | return &m_decoder; 16 | } 17 | 18 | VideoDisplay* VideoPlayer::getCurrentDisplay() 19 | { 20 | return m_display; 21 | } 22 | 23 | void VideoPlayer::setDisplay(VideoDisplay* display) 24 | { 25 | Q_ASSERT(display); 26 | delete m_display; 27 | 28 | m_display = display; 29 | m_decoder.setFrameListener(m_display); 30 | } 31 | 32 | void VideoPlayer::setState(VideoState newState) 33 | { 34 | qDebug() << __FUNCTION__ << "newState:" << newState; 35 | m_state = newState; 36 | } 37 | -------------------------------------------------------------------------------- /QtPlayer/videoplayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ffmpegdecoder.h" 4 | 5 | 6 | class VideoPlayer 7 | { 8 | public: 9 | enum VideoState 10 | { 11 | InitialState, 12 | Playing, 13 | Paused, 14 | }; 15 | 16 | VideoPlayer(); 17 | virtual ~VideoPlayer(); 18 | 19 | FFmpegDecoderWrapper* getDecoder(); 20 | VideoDisplay* getCurrentDisplay(); 21 | virtual void setDisplay(VideoDisplay* display); 22 | VideoState state() const { return m_state; } 23 | 24 | protected: 25 | void setState(VideoState newState); 26 | 27 | private: 28 | FFmpegDecoderWrapper m_decoder; 29 | VideoDisplay* m_display{nullptr}; 30 | VideoState m_state{InitialState}; 31 | }; 32 | -------------------------------------------------------------------------------- /QtPlayer/videoplayerwidget.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mainwindow.h" 4 | #include "videoplayer.h" 5 | 6 | #include 7 | #include 8 | 9 | class VideoControl; 10 | class VideoProgressBar; 11 | class VideoWidget; 12 | 13 | 14 | class VideoPlayerWidget; 15 | 16 | inline VideoPlayerWidget* VideoPlayerWidgetInstance() 17 | { 18 | if (auto mainWindow = getMainWindow()) { 19 | return mainWindow->getPlayer(); 20 | } 21 | return nullptr; 22 | } 23 | 24 | 25 | class VideoPlayerWidget : public QFrame, public VideoPlayer 26 | { 27 | Q_OBJECT 28 | public: 29 | explicit VideoPlayerWidget(QWidget* parent = nullptr); 30 | ~VideoPlayerWidget() override; 31 | 32 | void pauseVideo(); 33 | void resumeVideo(); 34 | 35 | void stopVideo(bool showDefaultImage = false); 36 | bool isPaused(); 37 | void seekByPercent(float percent); 38 | 39 | VideoDisplay* getCurrentDisplay(); 40 | VideoWidget* videoWidget() {return m_videoWidget;} 41 | 42 | void setProgressbar(VideoProgressBar* progressbar); 43 | void setControl(VideoControl* controlWidget); 44 | 45 | void setDefaultPreviewPicture(); 46 | 47 | QString currentFilename() const; 48 | 49 | void updateLayout(); 50 | 51 | void exitFullScreen(); 52 | 53 | void playFile(const QString& fileName); 54 | 55 | protected: 56 | void resizeEvent(QResizeEvent* event) override; 57 | bool eventFilter(QObject* object, QEvent* event) override; 58 | 59 | public slots: 60 | void playPauseButtonAction(); 61 | 62 | private slots: 63 | void setVideoFilename(const QString& fileName); 64 | 65 | void updateViewOnVideoStop(bool showDefaultImage = true); 66 | 67 | void onPlayingFinished(); 68 | 69 | signals: 70 | void fileReleased(); 71 | 72 | private: 73 | friend class VideoWidget; 74 | 75 | VideoControl* m_controls{nullptr}; 76 | VideoProgressBar* m_progressBar{nullptr}; 77 | QString m_currentFile; 78 | VideoWidget* m_videoWidget; 79 | }; 80 | -------------------------------------------------------------------------------- /QtPlayer/videoprogressbar.cpp: -------------------------------------------------------------------------------- 1 | #include "videoprogressbar.h" 2 | #include "ffmpegdecoder.h" 3 | #include "videoplayerwidget.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | VideoProgressBar::VideoProgressBar(QWidget* parent) : 13 | QProgressBar(parent) 14 | { 15 | m_downloaded = 0; 16 | m_played = 0; 17 | 18 | setWindowTitle("Video Progress Bar"); 19 | resize(500, 200); 20 | installEventFilter(this); 21 | } 22 | 23 | VideoProgressBar::~VideoProgressBar() = default; 24 | 25 | void VideoProgressBar::paintEvent(QPaintEvent* event) 26 | { 27 | Q_UNUSED(event) 28 | QPainter painter(this); 29 | QLinearGradient gradient(0, 0, 0, height()); 30 | 31 | int lineheight = height() / 3; 32 | int margintop = (height() - lineheight) / 2; 33 | 34 | // Draw background line 35 | gradient.setColorAt(0, QColor(67, 67, 67)); 36 | gradient.setColorAt(1, QColor(49, 49, 50)); 37 | painter.setBrush(gradient); 38 | painter.setPen(Qt::NoPen); 39 | painter.drawRect(0, margintop, width(), lineheight); 40 | 41 | // Downloaded line 42 | gradient.setColorAt(0, QColor(235, 235, 235)); 43 | gradient.setColorAt(1, QColor(207, 213, 217)); 44 | painter.setBrush(gradient); 45 | painter.drawRect(0, margintop, (static_cast(m_downloaded) / m_scale) * width(), lineheight); 46 | 47 | // 3 step : playing line 48 | gradient.setColorAt(0, QColor(209, 63, 70)); 49 | gradient.setColorAt(1, QColor(177, 10, 11)); 50 | painter.setBrush(gradient); 51 | painter.drawRect(0, margintop, (static_cast(m_played) / m_scale) * width(), lineheight); 52 | 53 | QPixmap clicker = QPixmap(":/images/video_seek_cursor.png"); 54 | painter.drawPixmap( 55 | QRect((m_played / (m_scale - static_cast(clicker.width())*m_scale / (width()))) * width() - 1 - static_cast(clicker.width())*m_played / m_scale * 1.8 , 1, clicker.width(), clicker.height()), 56 | clicker, 57 | clicker.rect() 58 | ); 59 | } 60 | 61 | void VideoProgressBar::setDownloadedCounter(int downloaded) 62 | { 63 | downloaded = std::clamp(downloaded, 0, m_scale); 64 | 65 | if (m_downloaded == downloaded) 66 | { 67 | return; 68 | } 69 | 70 | m_downloaded = downloaded; 71 | 72 | repaint(); 73 | } 74 | 75 | void VideoProgressBar::setPlayedCounter(int played) 76 | { 77 | if (played < 0) 78 | { 79 | played = 0; 80 | } 81 | 82 | if (m_played == played) 83 | { 84 | return; 85 | } 86 | 87 | m_played = played; 88 | 89 | repaint(); 90 | } 91 | 92 | int VideoProgressBar::getScale() const 93 | { 94 | return m_scale; 95 | } 96 | 97 | void VideoProgressBar::resetProgress() 98 | { 99 | m_downloaded = 0; 100 | m_played = 0; 101 | repaint(); 102 | 103 | setToolTip(QString()); 104 | if (underMouse()) 105 | { 106 | QToolTip::hideText(); 107 | } 108 | } 109 | 110 | bool VideoProgressBar::eventFilter(QObject* obj, QEvent* event) 111 | { 112 | //const FFmpegDecoder* decoder = VideoPlayerWidgetInstance()->getDecoder(); 113 | QEvent::Type eventType = event->type(); 114 | switch (eventType) 115 | { 116 | case QEvent::MouseMove: 117 | { 118 | auto* mevent = static_cast(event); 119 | float percent = (mevent->x() * 1.0) / width(); 120 | 121 | if (m_btn_down) 122 | { 123 | percent = std::clamp(percent, 0.F, 1.F); 124 | 125 | if (!m_seekDisabled) 126 | { 127 | VideoPlayerWidgetInstance()->seekByPercent(percent); 128 | } 129 | } 130 | } 131 | break; 132 | case QEvent::MouseButtonPress: 133 | { 134 | m_btn_down = true; 135 | } 136 | break; 137 | case QEvent::MouseButtonRelease: 138 | { 139 | auto* mevent = static_cast(event); 140 | float percent = (mevent->x() * 1.0) / width(); 141 | 142 | percent = std::clamp(percent, 0.F, 1.F); 143 | 144 | if (!m_seekDisabled) 145 | { 146 | VideoPlayerWidgetInstance()->seekByPercent(percent); 147 | } 148 | m_btn_down = false; 149 | } 150 | break; 151 | default:; 152 | } 153 | 154 | return QWidget::eventFilter(obj, event); 155 | } 156 | 157 | 158 | void VideoProgressBar::displayPlayedProgress(qint64 frame, qint64 total) 159 | { 160 | int progress = (static_cast(frame) / total) * getScale(); 161 | if (!m_seekDisabled) 162 | { 163 | setPlayedCounter(progress); 164 | } 165 | else 166 | { 167 | setPlayedCounter(0); 168 | } 169 | } 170 | 171 | void VideoProgressBar::seekingEnable(bool enable /* = true*/) 172 | { 173 | m_seekDisabled = !enable; 174 | } 175 | -------------------------------------------------------------------------------- /QtPlayer/videoprogressbar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class VideoProgressBar : public QProgressBar 6 | { 7 | Q_OBJECT 8 | public: 9 | explicit VideoProgressBar(QWidget* parent = nullptr); 10 | 11 | ~VideoProgressBar() override; 12 | int getScale() const; 13 | void resetProgress(); 14 | 15 | protected: 16 | void paintEvent(QPaintEvent* event) override; 17 | bool eventFilter(QObject* obj, QEvent* event) override; 18 | 19 | private: 20 | int m_downloaded; 21 | int m_played; 22 | int m_scale{1000}; 23 | bool m_btn_down{false}; 24 | bool m_seekDisabled{false}; 25 | qint64 m_downloadedTotalOriginal{0}; 26 | public slots: 27 | void setDownloadedCounter(int downloaded); 28 | void setPlayedCounter(int played); 29 | void seekingEnable(bool enable = true); 30 | public slots: 31 | void displayPlayedProgress(qint64 frame, qint64 total); 32 | }; 33 | -------------------------------------------------------------------------------- /QtPlayer/videowidget.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef DEVELOPER_OPENGL 8 | #include "opengldisplay.h" 9 | #else 10 | #include "widgetdisplay.h" 11 | #endif 12 | 13 | class VideoPlayerWidget; 14 | 15 | // FIXME: OpenGL full support 16 | #ifdef DEVELOPER_OPENGL 17 | class VideoWidget : public OpenGLDisplay 18 | #else 19 | class VideoWidget : public WidgetDisplay 20 | #endif 21 | { 22 | Q_OBJECT 23 | Q_PROPERTY(QImage m_noPreviewImg READ noPreviewImage WRITE setNoPreviewImage); 24 | public: 25 | explicit VideoWidget(VideoPlayerWidget* parent = nullptr); 26 | ~VideoWidget() override; 27 | 28 | void setDefaultPreviewPicture(); 29 | QSize getPictureSize() const { return m_pictureSize; } 30 | QPixmap originalFrame() const { return m_originalFrame; } 31 | QImage startImageButton() const { return m_startImgButton; } 32 | 33 | QImage noPreviewImage() const { return m_noPreviewImg; } 34 | void setNoPreviewImage(const QImage& noImage) { m_noPreviewImg = noImage; } 35 | 36 | QPixmap drawPreview(const QImage& fromImage); 37 | void hidePlayButton(); 38 | 39 | void updatePlayButton(); 40 | 41 | protected: 42 | void keyPressEvent(QKeyEvent* event) override; 43 | 44 | void mousePressEvent(QMouseEvent* event) override; 45 | void mouseReleaseEvent(QMouseEvent* event) override; 46 | void mouseMoveEvent(QMouseEvent* event) override; 47 | void wheelEvent(QWheelEvent* event) override; 48 | void resizeEvent(QResizeEvent* event) override; 49 | 50 | VideoPlayerWidget* VideoPlayerWidgetInstance(); 51 | 52 | QImage m_startImgButton; 53 | QImage m_noPreviewImg; 54 | QPixmap m_originalFrame; 55 | 56 | private: 57 | bool m_playIndicator{false}; 58 | QSize m_pictureSize; 59 | QImage m_defPlayButton, m_hoverPlayButton, m_clickedPlayButton; 60 | QImage* m_selImage; 61 | QImage m_fromImage; 62 | bool m_isMousePressed{false}; 63 | const int m_playBtnRadius{29}; 64 | #ifdef Q_OS_LINUX 65 | bool m_resizeIndicator = false; 66 | #endif 67 | 68 | qint64 m_lastMouseTime{0}; 69 | 70 | QTimer m_cursorTimer; 71 | 72 | bool pointInButton(const QPoint& point); 73 | 74 | void showElements(); 75 | void hideElements(); 76 | 77 | public Q_SLOTS: 78 | void fullScreen(bool isEnable = true); 79 | 80 | protected Q_SLOTS: 81 | #ifndef DEVELOPER_OPENGL 82 | virtual void currentDisplay(unsigned int generation) override; 83 | #endif 84 | 85 | private Q_SLOTS: 86 | void getImageFinished(const QImage& image); 87 | void onCursorTimer(); 88 | void fullScreenProcess(); 89 | Q_SIGNALS: 90 | void leaveFullScreen(); 91 | void mouseClicked(); 92 | }; 93 | -------------------------------------------------------------------------------- /QtPlayer/volumeprogressbar.cpp: -------------------------------------------------------------------------------- 1 | #include "volumeprogressbar.h" 2 | 3 | #include 4 | 5 | VolumeProgressBar::VolumeProgressBar(QWidget* parent) : QProgressBar(parent), 6 | m_borderBrush(QColor(101, 105, 108)), 7 | m_backBrush(QColor(66, 66, 66)), 8 | m_fillBorderBrush(QColor(176, 180, 183)), 9 | m_fillBrush(QColor(255, 255, 255)) 10 | { 11 | } 12 | 13 | VolumeProgressBar::~VolumeProgressBar() = default; 14 | 15 | void VolumeProgressBar::paintEvent(QPaintEvent* event) 16 | { 17 | Q_UNUSED(event) 18 | QPainter painter(this); 19 | 20 | painter.fillRect(0, 0, width(), height(), m_borderBrush); 21 | painter.fillRect(1, 1, width() - 2, height() - 2, m_backBrush); 22 | 23 | int filledWidth = static_cast(width() / 100.0 * value()); 24 | 25 | painter.fillRect(0, 0, filledWidth, height(), m_fillBorderBrush); 26 | if (filledWidth > 1) 27 | { 28 | painter.fillRect(1, 1, filledWidth - 2, height() - 2, m_fillBrush); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /QtPlayer/volumeprogressbar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class VolumeProgressBar : public QProgressBar 6 | { 7 | Q_OBJECT 8 | public: 9 | VolumeProgressBar(QWidget* parent); 10 | ~VolumeProgressBar() override; 11 | protected: 12 | void paintEvent(QPaintEvent* event) override; 13 | 14 | private: 15 | QBrush m_borderBrush, m_backBrush; 16 | QBrush m_fillBorderBrush, m_fillBrush; 17 | }; 18 | -------------------------------------------------------------------------------- /QtPlayer/widgetdisplay.cpp: -------------------------------------------------------------------------------- 1 | #include "widgetdisplay.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | WidgetDisplay::WidgetDisplay(QWidget* parent) : QLabel(parent) 8 | { 9 | connect(this, &WidgetDisplay::display, this, &WidgetDisplay::currentDisplay); 10 | } 11 | 12 | void WidgetDisplay::currentDisplay(unsigned int generation) 13 | { 14 | m_display = QPixmap::fromImage(m_image); 15 | setPixmap(m_display); 16 | 17 | finishedDisplayingFrame(generation); 18 | } 19 | 20 | 21 | void WidgetDisplay::showPicture(const QImage& picture) 22 | { 23 | showPicture(QPixmap::fromImage(picture)); 24 | } 25 | 26 | void WidgetDisplay::showPicture(const QPixmap& picture) 27 | { 28 | setPixmap(picture); 29 | } 30 | 31 | 32 | void WidgetDisplay::updateFrame(IFrameDecoder* decoder, unsigned int generation) 33 | { 34 | FrameRenderingData data; 35 | if (!decoder->getFrameRenderingData(&data)) 36 | { 37 | return; 38 | } 39 | 40 | m_aspectRatio = float(data.height) / data.width; 41 | 42 | auto image = QImage(data.image[0], data.width, data.height, data.pitch[0], QImage::Format_RGB888); 43 | if (m_scrWidth > 0 && m_scrHeight > 0) { 44 | m_image = image.scaled(m_scrWidth, m_scrHeight); 45 | } else { 46 | m_image = std::move(image); 47 | } 48 | } 49 | 50 | void WidgetDisplay::drawFrame(IFrameDecoder* decoder, unsigned int generation) 51 | { 52 | emit display(generation); 53 | } 54 | 55 | void WidgetDisplay::decoderClosing() 56 | { 57 | } 58 | -------------------------------------------------------------------------------- /QtPlayer/widgetdisplay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "videodisplay.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class WidgetDisplay : public QLabel, public VideoDisplay 10 | { 11 | Q_OBJECT 12 | public: 13 | WidgetDisplay(QWidget* parent = nullptr); 14 | ~WidgetDisplay() override = default; 15 | 16 | void showPicture(const QImage& picture) override; 17 | void showPicture(const QPixmap& picture) override; 18 | 19 | // decoder->finishedDisplayingFrame() must be called 20 | void updateFrame(IFrameDecoder* decoder, unsigned int generation) override; 21 | void drawFrame(IFrameDecoder* decoder, unsigned int generation) override; 22 | void decoderClosing() override; 23 | 24 | float aspectRatio() const { return m_aspectRatio; } 25 | 26 | protected: 27 | QImage m_image; 28 | QPixmap m_display; 29 | float m_aspectRatio { 0.75F }; 30 | 31 | protected slots: 32 | virtual void currentDisplay(unsigned int generation); 33 | signals: 34 | void display(unsigned int generation); 35 | }; 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ℉ℲmpegPlayer 2 | 3 | A simple FFmpeg based player. The player core is generic and made with multiplatformity in mind. UI / video / audio layer is MFC/Win32 specific. It turns out that there is no need to use multimedia libraries. There is also a Qt based demo example included. It offers: 4 | - Basic Playback Controls: Play/Pause, Stop. 5 | - Next/Previous Frame: Step through the video one frame at a time during pause. 6 | - Speed Change: Increase or decrease the playback speed without altering the pitch of the audio. 7 | - Separate Video and Audio Inputs: Ability to load and play video and audio from separate sources. 8 | - Audio Track Selection: Choose between different audio tracks if available. 9 | - Fragment Selection for Export: Mark in and out points to select a part of the video for exporting. 10 | - Repeated Playing: Loop the entire video/playlist or selected fragment continuously. 11 | - Subtitles: Load and display subtitle files in various formats. 12 | - Super Resolution: Enhance the resolution of the video using upscaling techniques. 13 | - Codec Support: Compatibility with a wide range of video and audio codecs. 14 | - Streaming Support: Ability to stream video from online sources. 15 | 16 | [Semi transparent, click through full screen mode introduced.](https://bit.ly/2JLTbQn) It is invokable by holding ctrl+shift while pressing full screen button. 17 | 18 | ## Getting Started 19 | 20 | These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. 21 | 22 | ### Prerequisites 23 | 24 | 25 | - Visual Studio 2017 or higher. 26 | - vcpkg. 27 | 28 | ### Installing 29 | 30 | Be sure to download git submodules. 31 | 32 | To get a development env running: 33 | 34 | Install vcpkg from https://github.com/Microsoft/vcpkg. 35 | ``` 36 | .\vcpkg integrate install 37 | ``` 38 | 39 | Install Boost, FFmpeg, OpenCV etc. Details can be found in .github/workflows/msbuild.yml. 40 | 41 | Create ./Directory.Build.props file in the project folder. It contents depend on you environment, for example: 42 | ``` 43 | 44 | 45 | 10.0.22621.0 46 | v4.6.2 47 | v143 48 | 49 | 50 | ``` 51 | 52 | YouTube view support is turned on by default. It can be turned off by commenting define YOUTUBE_EXPERIMENT in YouTuber.cpp. A special mode has been implemented: Google can use SAN certificates that include multiple domains and subdomains. This allows one certificate to protect multiple services, such as youtube.com, www.youtube.com, and other subdomains. If you have one certificate with multiple SANs, and all domains are served by one certificate, you can do without SNI by using the IP address in the URL and the Host header to identify the content. 53 | 54 | The matching Python version has to be installed for the accessory DLLs to be accessible, except for embedded Python coming with installation. In any case Pytubefix now requires Node.js installed. 55 | 56 | You may need to remove pytube stuff from your profile folder for the player application to set up the latest version, for example, by invoking remove_pytube.cmd. 57 | 58 | You can also "patch" Python stuff by creating %LOCALAPPDATA%\git-subst.cfg mapping file. 59 | 60 | Just in case: "In fact in boost-python, the default behavior is that even when debug boost libraries are created, these libraries are linked to the release pythonX.dll/lib - by intention, according to the docs." https://github.com/pybind/pybind11/issues/1295 61 | 62 | Tiny demos here: https://www.youtube.com/watch?v=dySA4yEGdEc https://www.youtube.com/watch?v=t5iW2ZsEzrA 63 | 64 | Tip: hold Ctrl+Shift while submitting File Open dialog to choose a separate audio file. It works for the file opening from the Windows Explorer as well. 65 | 66 | Please take into account specific Windows 10 behavior while opening Internet shortcuts: https://community.spiceworks.com/topic/1968971-opening-web-links-downloading-1-item-to-zcrksihu You can avoid this by dragging and dropping them. 67 | 68 | Note that the FFmpeg patch speeds up HEVC decoding without GPU support by ~10%: 69 | 70 | ![image](https://user-images.githubusercontent.com/11851670/171165625-3a111046-672c-4a75-8184-c91fde994e00.png) 71 | 72 | ### Bonus tip 73 | 74 | Playing YouTube videos in browsers may result in poor performance on slow hardware. Assign a keyboard shortcut to the FFmpeg player by editing its shortcut. Hover your mouse over the YouTube link in Firefox and bring up the shortcut. A player pop-up window will appear, starting the video playback. The same can be achieved in Chrome with some tweaking. [Start Chrome with this flag: --force-renderer-accessibility](https://www.chromium.org/developers/design-documents/accessibility/) and / or [set up IAccessible2 COM proxy stub DLL](https://github.com/aliakseis/IAccessible2Proxy). 75 | 76 | ![redline](https://user-images.githubusercontent.com/11851670/184552270-73cb8ba4-31f7-47f2-9f50-2b4ceae601e7.gif) 77 | -------------------------------------------------------------------------------- /Setup/python-embed-win32.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakseis/FFmpegPlayer/ecbb1813c983a559d4276e1a5d13a8a5721caf61/Setup/python-embed-win32.7z -------------------------------------------------------------------------------- /ToUTF8/ToUTF8.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /audio/AudioPitchDecorator.cpp: -------------------------------------------------------------------------------- 1 | #include "AudioPitchDecorator.h" 2 | 3 | #include "smbPitchShift.h" 4 | 5 | #include 6 | #include 7 | 8 | AudioPitchDecorator::AudioPitchDecorator(std::unique_ptr player 9 | , std::function getPitchShift) 10 | : m_player(std::move(player)) 11 | , m_getPitchShift(std::move(getPitchShift)) 12 | { 13 | } 14 | 15 | AudioPitchDecorator::~AudioPitchDecorator() = default; 16 | 17 | void AudioPitchDecorator::SetCallback(IAudioPlayerCallback * callback) 18 | { 19 | m_player->SetCallback(callback); 20 | } 21 | 22 | void AudioPitchDecorator::InitializeThread() 23 | { 24 | m_player->InitializeThread(); 25 | } 26 | 27 | void AudioPitchDecorator::DeinitializeThread() 28 | { 29 | m_player->DeinitializeThread(); 30 | } 31 | 32 | void AudioPitchDecorator::WaveOutReset() 33 | { 34 | m_player->WaveOutReset(); 35 | for (auto& v : m_smbPitchShifts) 36 | v.reset(); 37 | } 38 | 39 | void AudioPitchDecorator::Close() 40 | { 41 | m_player->Close(); 42 | } 43 | 44 | bool AudioPitchDecorator::Open(int bytesPerSample, int channels, int * samplesPerSec) 45 | { 46 | if (!m_player->Open(bytesPerSample, channels, samplesPerSec)) 47 | return false; 48 | 49 | m_bytesPerSample = bytesPerSample; 50 | m_samplesPerSec = *samplesPerSec; 51 | m_smbPitchShifts.resize(channels); 52 | for (auto& v : m_smbPitchShifts) 53 | v.reset(); 54 | 55 | return true; 56 | } 57 | 58 | void AudioPitchDecorator::SetVolume(double volume) 59 | { 60 | m_player->SetVolume(volume); 61 | } 62 | 63 | double AudioPitchDecorator::GetVolume() const 64 | { 65 | return m_player->GetVolume(); 66 | } 67 | 68 | void AudioPitchDecorator::WaveOutPause() 69 | { 70 | m_player->WaveOutPause(); 71 | } 72 | 73 | void AudioPitchDecorator::WaveOutRestart() 74 | { 75 | m_player->WaveOutRestart(); 76 | } 77 | 78 | bool AudioPitchDecorator::WriteAudio(uint8_t * write_data, int64_t write_size) 79 | { 80 | const auto pitchShift = m_getPitchShift(); 81 | if (pitchShift != 1. && m_bytesPerSample == 2) 82 | { 83 | const auto numSamples = (write_size / m_bytesPerSample) / m_smbPitchShifts.size(); 84 | if (m_buffer.size() < numSamples) 85 | m_buffer.resize(numSamples); 86 | int16_t* const intData = (int16_t*)write_data; 87 | for (int i = 0; i < m_smbPitchShifts.size(); ++i) 88 | { 89 | for (size_t j = 0; j < numSamples; ++j) 90 | { 91 | m_buffer[j] = intData[j * m_smbPitchShifts.size() + i] / 32768.; 92 | } 93 | m_smbPitchShifts[i].smbPitchShift( 94 | pitchShift, numSamples, 4096, 16, m_samplesPerSec, m_buffer.data(), m_buffer.data()); 95 | for (size_t j = 0; j < numSamples; ++j) 96 | { 97 | // decrease level to avoid clipping distortions 98 | intData[j * m_smbPitchShifts.size() + i] = std::clamp(m_buffer[j], -2.f, 2.f) * (32767. / 2); 99 | } 100 | } 101 | } 102 | else 103 | { 104 | for (auto& v : m_smbPitchShifts) 105 | v.reset(); 106 | } 107 | return m_player->WriteAudio(write_data, write_size); 108 | } 109 | -------------------------------------------------------------------------------- /audio/AudioPitchDecorator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../video/audioplayer.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class CSmbPitchShift; 10 | 11 | class AudioPitchDecorator : 12 | public IAudioPlayer 13 | { 14 | public: 15 | AudioPitchDecorator(std::unique_ptr player, 16 | std::function getPitchShift); 17 | ~AudioPitchDecorator(); 18 | 19 | AudioPitchDecorator(const AudioPitchDecorator&) = delete; 20 | AudioPitchDecorator& operator =(const AudioPitchDecorator&) = delete; 21 | 22 | // Inherited via IAudioPlayer 23 | void SetCallback(IAudioPlayerCallback * callback) override; 24 | void InitializeThread() override; 25 | void DeinitializeThread() override; 26 | void WaveOutReset() override; 27 | void Close() override; 28 | bool Open(int bytesPerSample, int channels, int * samplesPerSec) override; 29 | void SetVolume(double volume) override; 30 | double GetVolume() const override; 31 | void WaveOutPause() override; 32 | void WaveOutRestart() override; 33 | bool WriteAudio(uint8_t * write_data, int64_t write_size) override; 34 | 35 | private: 36 | std::unique_ptr m_player; 37 | std::function m_getPitchShift; 38 | std::vector m_smbPitchShifts; 39 | 40 | std::vector m_buffer; 41 | 42 | int m_bytesPerSample{}; 43 | int m_samplesPerSec{}; 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /audio/AudioPlayerImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../video/audioplayer.h" 4 | 5 | #include 6 | #include 7 | 8 | class AudioPlayerImpl : 9 | public IAudioPlayer 10 | { 11 | public: 12 | AudioPlayerImpl(); 13 | ~AudioPlayerImpl() override; 14 | 15 | AudioPlayerImpl(const AudioPlayerImpl&) = delete; 16 | AudioPlayerImpl& operator=(const AudioPlayerImpl&) = delete; 17 | 18 | void SetCallback(IAudioPlayerCallback* callback) override 19 | { 20 | m_callback = callback; 21 | } 22 | 23 | void InitializeThread() override; 24 | void DeinitializeThread() override; 25 | 26 | void WaveOutReset() override; 27 | 28 | void Close() override; 29 | bool Open(int bytesPerSample, int channels, int* samplesPerSec) override; 30 | 31 | void SetVolume(double volume) override; 32 | double GetVolume() const override; 33 | 34 | void WaveOutPause() override; 35 | void WaveOutRestart() override; 36 | 37 | bool WriteAudio(uint8_t* write_data, int64_t write_size) override; 38 | 39 | private: 40 | IAudioPlayerCallback* m_callback; 41 | 42 | HWAVEOUT m_waveOutput; 43 | 44 | static void CALLBACK waveOutProc(HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR); 45 | 46 | WAVEHDR* m_waveBlocks; 47 | volatile long m_waveFreeBlockCount {}; 48 | HANDLE m_evtHasFreeBlocks; 49 | int m_waveCurrentBlock {}; 50 | 51 | int m_bytesPerSecond; 52 | }; 53 | 54 | -------------------------------------------------------------------------------- /audio/AudioPlayerWasapi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../video/audioplayer.h" 4 | 5 | #include 6 | 7 | struct IAudioClient; 8 | struct IAudioRenderClient; 9 | struct ISimpleAudioVolume; 10 | 11 | class AudioPlayerWasapi : 12 | public IAudioPlayer 13 | { 14 | public: 15 | AudioPlayerWasapi(); 16 | ~AudioPlayerWasapi() override; 17 | 18 | AudioPlayerWasapi(const AudioPlayerWasapi&) = delete; 19 | AudioPlayerWasapi& operator=(const AudioPlayerWasapi&) = delete; 20 | 21 | void SetCallback(IAudioPlayerCallback* callback) override 22 | { 23 | m_callback = callback; 24 | } 25 | 26 | void InitializeThread() override; 27 | void DeinitializeThread() override; 28 | 29 | void WaveOutReset() override; 30 | 31 | void Close() override; 32 | bool Open(int bytesPerSample, int channels, int* samplesPerSec) override; 33 | 34 | void SetVolume(double volume) override; 35 | double GetVolume() const override; 36 | 37 | void WaveOutPause() override; 38 | void WaveOutRestart() override; 39 | 40 | bool WriteAudio(uint8_t* write_data, int64_t write_size) override; 41 | 42 | private: 43 | IAudioPlayerCallback* m_callback; 44 | 45 | HANDLE m_hAudioSamplesRenderEvent; 46 | 47 | CComPtr m_AudioClient; 48 | CComPtr m_RenderClient; 49 | CComPtr m_SimpleAudioVolume; 50 | 51 | unsigned int m_BufferSize; 52 | unsigned int m_FrameSize; 53 | unsigned int m_samplesPerSec; 54 | 55 | HANDLE m_mmcssHandle; 56 | 57 | bool m_coUnitialize; 58 | }; 59 | -------------------------------------------------------------------------------- /audio/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | STATIC LIBRARY : audio Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this audio library project for you. 6 | 7 | No source files were created as part of your project. 8 | 9 | 10 | audio.vcxproj 11 | This is the main project file for VC++ projects generated using an Application Wizard. 12 | It contains information about the version of Visual C++ that generated the file, and 13 | information about the platforms, configurations, and project features selected with the 14 | Application Wizard. 15 | 16 | audio.vcxproj.filters 17 | This is the filters file for VC++ projects generated using an Application Wizard. 18 | It contains information about the association between the files in your project 19 | and the filters. This association is used in the IDE to show grouping of files with 20 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 21 | "Source Files" filter). 22 | 23 | ///////////////////////////////////////////////////////////////////////////// 24 | Other notes: 25 | 26 | AppWizard uses "TODO:" comments to indicate parts of the source code you 27 | should add to or customize. 28 | 29 | ///////////////////////////////////////////////////////////////////////////// 30 | -------------------------------------------------------------------------------- /audio/audio.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | -------------------------------------------------------------------------------- /audio/smbPitchShift.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ 4 | 5 | class CSmbPitchShift 6 | { 7 | enum { MAX_FRAME_LENGTH = 8192 }; 8 | 9 | public: 10 | void reset() 11 | { 12 | gRover = 0; 13 | gInit = false; 14 | } 15 | void smbPitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata); 16 | 17 | private: 18 | float gInFIFO[MAX_FRAME_LENGTH]; 19 | float gOutFIFO[MAX_FRAME_LENGTH]; 20 | float gFFTworksp[2 * MAX_FRAME_LENGTH]; 21 | float gLastPhase[MAX_FRAME_LENGTH / 2 + 1]; 22 | float gSumPhase[MAX_FRAME_LENGTH / 2 + 1]; 23 | float gOutputAccum[2 * MAX_FRAME_LENGTH]; 24 | float gAnaFreq[MAX_FRAME_LENGTH]; 25 | float gAnaMagn[MAX_FRAME_LENGTH]; 26 | float gSynFreq[MAX_FRAME_LENGTH]; 27 | float gSynMagn[MAX_FRAME_LENGTH]; 28 | 29 | float gErrors[MAX_FRAME_LENGTH]; 30 | 31 | long gRover = 0; 32 | bool gInit = false; 33 | }; -------------------------------------------------------------------------------- /core/ac_export.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef AC_EXPORT_H 3 | #define AC_EXPORT_H 4 | 5 | #ifdef AC_STATIC_DEFINE 6 | # define AC_EXPORT 7 | # define AC_NO_EXPORT 8 | #else 9 | # ifndef AC_EXPORT 10 | # ifdef Anime4KCPPCore_EXPORTS 11 | /* We are building this library */ 12 | # define AC_EXPORT 13 | # else 14 | /* We are using this library */ 15 | # define AC_EXPORT 16 | # endif 17 | # endif 18 | 19 | # ifndef AC_NO_EXPORT 20 | # define AC_NO_EXPORT 21 | # endif 22 | #endif 23 | 24 | #ifndef AC_DEPRECATED 25 | # define AC_DEPRECATED __declspec(deprecated) 26 | #endif 27 | 28 | #ifndef AC_DEPRECATED_EXPORT 29 | # define AC_DEPRECATED_EXPORT AC_EXPORT AC_DEPRECATED 30 | #endif 31 | 32 | #ifndef AC_DEPRECATED_NO_EXPORT 33 | # define AC_DEPRECATED_NO_EXPORT AC_NO_EXPORT AC_DEPRECATED 34 | #endif 35 | 36 | #if 0 /* DEFINE_NO_DEPRECATED */ 37 | # ifndef AC_NO_DEPRECATED 38 | # define AC_NO_DEPRECATED 39 | # endif 40 | #endif 41 | 42 | #endif /* AC_EXPORT_H */ 43 | -------------------------------------------------------------------------------- /edit_git_subst_cfg.cmd: -------------------------------------------------------------------------------- 1 | notepad.exe "%LOCALAPPDATA%\git-subst.cfg" 2 | -------------------------------------------------------------------------------- /networking/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | STATIC LIBRARY : unzip Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this unzip library project for you. 6 | 7 | No source files were created as part of your project. 8 | 9 | 10 | unzip.vcxproj 11 | This is the main project file for VC++ projects generated using an Application Wizard. 12 | It contains information about the version of Visual C++ that generated the file, and 13 | information about the platforms, configurations, and project features selected with the 14 | Application Wizard. 15 | 16 | unzip.vcxproj.filters 17 | This is the filters file for VC++ projects generated using an Application Wizard. 18 | It contains information about the association between the files in your project 19 | and the filters. This association is used in the IDE to show grouping of files with 20 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 21 | "Source Files" filter). 22 | 23 | ///////////////////////////////////////////////////////////////////////////// 24 | Other notes: 25 | 26 | AppWizard uses "TODO:" comments to indicate parts of the source code you 27 | should add to or customize. 28 | 29 | ///////////////////////////////////////////////////////////////////////////// 30 | -------------------------------------------------------------------------------- /networking/crypt.h: -------------------------------------------------------------------------------- 1 | /* crypt.h -- base code for crypt/uncrypt ZIPfile 2 | 3 | 4 | Version 1.01e, February 12th, 2005 5 | 6 | Copyright (C) 1998-2005 Gilles Vollant 7 | 8 | This code is a modified version of crypting code in Infozip distribution 9 | 10 | The encryption/decryption parts of this source code (as opposed to the 11 | non-echoing password parts) were originally written in Europe. The 12 | whole source package can be freely distributed, including from the USA. 13 | (Prior to January 2000, re-export from the US was a violation of US law.) 14 | 15 | This encryption code is a direct transcription of the algorithm from 16 | Roger Schlafly, described by Phil Katz in the file appnote.txt. This 17 | file (appnote.txt) is distributed with the PKZIP program (even in the 18 | version without encryption capabilities). 19 | 20 | If you don't need crypting in your application, just define symbols 21 | NOCRYPT and NOUNCRYPT. 22 | 23 | This code support the "Traditional PKWARE Encryption". 24 | 25 | The new AES encryption added on Zip format by Winzip (see the page 26 | http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong 27 | Encryption is not supported. 28 | */ 29 | 30 | 31 | #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) 32 | 33 | /*********************************************************************** 34 | * Return the next byte in the pseudo-random sequence 35 | */ 36 | static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab ) 37 | { 38 | //(void) pcrc_32_tab; /* avoid "unused parameter" warning */ 39 | unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an 40 | * unpredictable manner on 16-bit systems; not a problem 41 | * with any known compiler so far, though */ 42 | 43 | temp = ((unsigned)(*(pkeys + 2)) & 0xffff) | 2; 44 | return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); 45 | } 46 | 47 | /*********************************************************************** 48 | * Update the encryption keys with the next byte of plain text 49 | */ 50 | static int update_keys(unsigned long* pkeys, const unsigned long* pcrc_32_tab, int c) 51 | { 52 | (*(pkeys + 0)) = CRC32((*(pkeys + 0)), c); 53 | (*(pkeys + 1)) += (*(pkeys + 0)) & 0xff; 54 | (*(pkeys + 1)) = (*(pkeys + 1)) * 134775813L + 1; 55 | { 56 | register int keyshift = (int)((*(pkeys + 1)) >> 24); 57 | (*(pkeys + 2)) = CRC32((*(pkeys + 2)), keyshift); 58 | } 59 | return c; 60 | } 61 | 62 | 63 | /*********************************************************************** 64 | * Initialize the encryption keys and the random header according to 65 | * the given password. 66 | */ 67 | static void init_keys(const char* passwd, unsigned long* pkeys, const unsigned long* pcrc_32_tab) 68 | { 69 | *(pkeys + 0) = 305419896L; 70 | *(pkeys + 1) = 591751049L; 71 | *(pkeys + 2) = 878082192L; 72 | while (*passwd != '\0') 73 | { 74 | update_keys(pkeys, pcrc_32_tab, (int)*passwd); 75 | passwd++; 76 | } 77 | } 78 | 79 | #define zdecode(pkeys,pcrc_32_tab,c) \ 80 | (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) 81 | 82 | #define zencode(pkeys,pcrc_32_tab,c,t) \ 83 | (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) 84 | 85 | #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED 86 | 87 | #define RAND_HEAD_LEN 12 88 | /* "last resort" source for second part of crypt seed pattern */ 89 | # ifndef ZCR_SEED2 90 | # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ 91 | # endif 92 | 93 | static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) 94 | const char* passwd; /* password string */ 95 | unsigned char* buf; /* where to write header */ 96 | int bufSize; 97 | unsigned long* pkeys; 98 | const unsigned long* pcrc_32_tab; 99 | unsigned long crcForCrypting; 100 | { 101 | int n; /* index in random header */ 102 | int t; /* temporary */ 103 | int c; /* random byte */ 104 | unsigned char header[RAND_HEAD_LEN - 2]; /* random header */ 105 | static unsigned calls = 0; /* ensure different random header each time */ 106 | 107 | if (bufSize < RAND_HEAD_LEN) 108 | return 0; 109 | 110 | /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the 111 | * output of rand() to get less predictability, since rand() is 112 | * often poorly implemented. 113 | */ 114 | if (++calls == 1) 115 | { 116 | srand((unsigned)(time(NULL) ^ ZCR_SEED2)); 117 | } 118 | init_keys(passwd, pkeys, pcrc_32_tab); 119 | for (n = 0; n < RAND_HEAD_LEN - 2; n++) 120 | { 121 | c = (rand() >> 7) & 0xff; 122 | header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); 123 | } 124 | /* Encrypt random header (last two bytes is high word of crc) */ 125 | init_keys(passwd, pkeys, pcrc_32_tab); 126 | for (n = 0; n < RAND_HEAD_LEN - 2; n++) 127 | { 128 | buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); 129 | } 130 | buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); 131 | buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); 132 | return n; 133 | } 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /networking/http_download.cpp: -------------------------------------------------------------------------------- 1 | #include "http_download.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | //#pragma comment(lib, "Winhttp") 15 | 16 | namespace { 17 | 18 | auto MakeGuard(HINTERNET h) 19 | { 20 | if (!h) 21 | { 22 | const DWORD errorCode = GetLastError(); 23 | throw std::system_error( 24 | errorCode, std::system_category(), "HINTERNET object creation failed."); 25 | } 26 | 27 | return std::unique_ptr, decltype(&WinHttpCloseHandle)> 28 | (h, WinHttpCloseHandle); 29 | } 30 | 31 | } // namespace 32 | 33 | bool HttpDownload(const TCHAR* url, const TCHAR* path) 34 | { 35 | std::wstring wszUrl(url, url + _tcslen(url)); 36 | URL_COMPONENTS urlComp{ sizeof(urlComp) }; 37 | 38 | // Set required component lengths to non-zero 39 | // so that they are cracked. 40 | urlComp.dwSchemeLength = (DWORD)-1; 41 | urlComp.dwHostNameLength = (DWORD)-1; 42 | urlComp.dwUrlPathLength = (DWORD)-1; 43 | urlComp.dwExtraInfoLength = (DWORD)-1; 44 | 45 | if (!WinHttpCrackUrl(wszUrl.c_str(), wszUrl.length(), 0, &urlComp)) 46 | { 47 | fprintf(stderr, "Error %u in WinHttpCrackUrl.\n", GetLastError()); 48 | return false; 49 | } 50 | 51 | // Use WinHttpOpen to obtain a session handle. 52 | auto hSession = MakeGuard(WinHttpOpen(L"HttpDownload/1.0", 53 | WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, 54 | WINHTTP_NO_PROXY_NAME, 55 | WINHTTP_NO_PROXY_BYPASS, 0)); 56 | 57 | // Specify an HTTP server. 58 | std::wstring szHostName( 59 | urlComp.lpszHostName, urlComp.lpszHostName + urlComp.dwHostNameLength); 60 | 61 | auto hConnect = MakeGuard(WinHttpConnect(hSession.get(), szHostName.c_str(), 62 | urlComp.nPort, 0)); 63 | 64 | // Create an HTTP request handle. 65 | auto hRequest = MakeGuard(WinHttpOpenRequest(hConnect.get(), L"GET", 66 | urlComp.lpszUrlPath, 67 | NULL, WINHTTP_NO_REFERER, 68 | WINHTTP_DEFAULT_ACCEPT_TYPES, 69 | (urlComp.nScheme == INTERNET_SCHEME_HTTPS)? WINHTTP_FLAG_SECURE : 0)); 70 | 71 | // Send a request. 72 | BOOL bResults = WinHttpSendRequest(hRequest.get(), 73 | WINHTTP_NO_ADDITIONAL_HEADERS, 0, 74 | WINHTTP_NO_REQUEST_DATA, 0, 75 | 0, 0); 76 | 77 | // End the request. 78 | if (bResults) 79 | bResults = WinHttpReceiveResponse(hRequest.get(), NULL); 80 | 81 | // Keep checking for data until there is nothing left. 82 | if (bResults) 83 | { 84 | std::ofstream f(path, std::ofstream::binary); 85 | std::vector buf; 86 | for (;;) 87 | { 88 | DWORD dwSize = 0; 89 | // Check for available data. 90 | if (!WinHttpQueryDataAvailable(hRequest.get(), &dwSize)) 91 | fprintf(stderr, "Error %u in WinHttpQueryDataAvailable.\n", 92 | GetLastError()); 93 | 94 | if (dwSize == 0) 95 | break; 96 | 97 | // Allocate space for the buffer. 98 | if (buf.size() < dwSize) 99 | buf.resize(dwSize); 100 | 101 | DWORD dwDownloaded = 0; 102 | 103 | if (WinHttpReadData(hRequest.get(), buf.data(), 104 | dwSize, &dwDownloaded)) 105 | { 106 | f.write(buf.data(), dwDownloaded); 107 | } 108 | else 109 | { 110 | fprintf(stderr, "Error %u in WinHttpReadData.\n", GetLastError()); 111 | } 112 | } 113 | } 114 | 115 | 116 | // Report any errors. 117 | if (!bResults) 118 | fprintf(stderr, "Error %d has occurred.\n", GetLastError()); 119 | 120 | return !!bResults; 121 | } 122 | -------------------------------------------------------------------------------- /networking/http_download.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool HttpDownload(const TCHAR* url, const TCHAR* path); 6 | 7 | -------------------------------------------------------------------------------- /networking/http_get.cpp: -------------------------------------------------------------------------------- 1 | #include "http_get.h" 2 | 3 | #include "httprequest_h.h" 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace { 10 | 11 | const wchar_t USER_AGENT[] 12 | = L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36"; 13 | 14 | class CComUsageScope 15 | { 16 | bool m_bInitialized; 17 | public: 18 | explicit CComUsageScope(DWORD dwCoInit = COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY) 19 | { 20 | m_bInitialized = SUCCEEDED(CoInitializeEx(NULL, dwCoInit)); 21 | } 22 | ~CComUsageScope() 23 | { 24 | if (m_bInitialized) 25 | CoUninitialize(); 26 | } 27 | }; 28 | 29 | std::string resolveHostnameToIP(const std::string& hostname) { 30 | addrinfo hints = { 0 }, * res = nullptr; 31 | hints.ai_family = AF_INET; // Allow IPv4 32 | hints.ai_socktype = SOCK_STREAM; 33 | hints.ai_protocol = IPPROTO_TCP; 34 | 35 | if (getaddrinfo(hostname.c_str(), nullptr, &hints, &res) != 0) { 36 | return {}; 37 | } 38 | 39 | char ipStr[INET6_ADDRSTRLEN]; 40 | void* addr; 41 | 42 | if (res->ai_family == AF_INET) { // IPv4 43 | sockaddr_in* sockaddr_ipv4 = reinterpret_cast(res->ai_addr); 44 | addr = &(sockaddr_ipv4->sin_addr); 45 | } 46 | else if (res->ai_family == AF_INET6) { // IPv6 47 | sockaddr_in6* sockaddr_ipv6 = reinterpret_cast(res->ai_addr); 48 | addr = &(sockaddr_ipv6->sin6_addr); 49 | } 50 | else { 51 | freeaddrinfo(res); 52 | return {}; 53 | } 54 | 55 | inet_ntop(res->ai_family, addr, ipStr, sizeof(ipStr)); 56 | freeaddrinfo(res); 57 | 58 | return std::string(ipStr); 59 | } 60 | 61 | } // namespace 62 | 63 | 64 | long HttpGetStatus(std::string& url, bool useSAN) 65 | { 66 | if (useSAN) 67 | { 68 | auto matchEnd = std::mismatch(url.begin(), url.end(), "https://", 69 | [](char c1, char c2) { return tolower(c1) == tolower(c2); }); 70 | if (matchEnd.first == url.end() || *matchEnd.second != '\0') 71 | { 72 | useSAN = false; 73 | } 74 | } 75 | 76 | CComBSTR bstrUrl; 77 | CComBSTR bstrHostname; 78 | 79 | if (useSAN) 80 | { 81 | const auto pos = 8; // Move past "://" 82 | size_t endPos = url.find_first_of(":/", pos); 83 | if (endPos != std::string::npos) 84 | { 85 | std::string hostname = url.substr(pos, endPos - pos); 86 | std::string ip = resolveHostnameToIP(hostname); 87 | if (!ip.empty()) { 88 | bstrUrl = (url.substr(0, pos) + ip + url.substr(endPos)).c_str(); 89 | bstrHostname = hostname.c_str(); 90 | } 91 | else 92 | { 93 | useSAN = false; 94 | } 95 | } 96 | else 97 | { 98 | useSAN = false; 99 | } 100 | } 101 | 102 | if (!useSAN) 103 | { 104 | bstrUrl = url.c_str(); 105 | } 106 | 107 | 108 | VARIANT varFalse{ VT_BOOL }; 109 | VARIANT varEmpty{ VT_ERROR }; 110 | VARIANT varOption{ VT_I4 }; 111 | varOption.intVal = 0x1000; 112 | 113 | HRESULT result = 0; 114 | 115 | CComPtr pIWinHttpRequest; 116 | 117 | CComUsageScope scope; 118 | 119 | if (FAILED(result = pIWinHttpRequest.CoCreateInstance(L"WinHttp.WinHttpRequest.5.1", NULL, CLSCTX_INPROC_SERVER))) 120 | return result; 121 | 122 | if (FAILED(result = pIWinHttpRequest->Open(CComBSTR(L"HEAD"), bstrUrl, varFalse))) 123 | return result; 124 | 125 | if (useSAN && FAILED(result = pIWinHttpRequest->SetRequestHeader(CComBSTR(L"Host"), bstrHostname))) 126 | return result; 127 | 128 | if (FAILED(result = pIWinHttpRequest->SetRequestHeader(CComBSTR(L"User-Agent"), CComBSTR(USER_AGENT)))) 129 | return result; 130 | 131 | if (useSAN && FAILED(result = pIWinHttpRequest->put_Option(WinHttpRequestOption_SslErrorIgnoreFlags, varOption))) // Ignore SSL errors 132 | return result; 133 | 134 | if (FAILED(result = pIWinHttpRequest->put_Option(WinHttpRequestOption_EnableRedirects, varFalse))) 135 | return result; 136 | 137 | if (SUCCEEDED(result = pIWinHttpRequest->Send(varEmpty))) 138 | { 139 | pIWinHttpRequest->get_Status(&result); 140 | if (result == 302) 141 | { 142 | CComBSTR locationHeader; 143 | if (SUCCEEDED(pIWinHttpRequest->GetResponseHeader(CComBSTR(L"Location"), &locationHeader))) 144 | { 145 | url = CW2A(locationHeader); 146 | } 147 | } 148 | } 149 | 150 | return result; 151 | } 152 | 153 | CComVariant HttpGet(const char * url) 154 | { 155 | VARIANT varFalse{ VT_BOOL }; 156 | VARIANT varEmpty{ VT_ERROR }; 157 | 158 | CComVariant varBody; 159 | 160 | CComPtr pIWinHttpRequest; 161 | 162 | CComUsageScope scope; 163 | 164 | if (SUCCEEDED(pIWinHttpRequest.CoCreateInstance(L"WinHttp.WinHttpRequest.5.1", NULL, CLSCTX_INPROC_SERVER)) 165 | && SUCCEEDED(pIWinHttpRequest->Open(CComBSTR(L"GET"), CComBSTR(static_cast(url)), varFalse)) 166 | && SUCCEEDED(pIWinHttpRequest->SetRequestHeader(CComBSTR(L"User-Agent"), CComBSTR(USER_AGENT))) 167 | && SUCCEEDED(pIWinHttpRequest->Send(varEmpty))) 168 | { 169 | pIWinHttpRequest->get_ResponseBody(&varBody); 170 | } 171 | 172 | return varBody; 173 | } 174 | -------------------------------------------------------------------------------- /networking/http_get.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // modifies url if it is a redirect 7 | long HttpGetStatus(std::string& url, bool useSAN = true); 8 | 9 | CComVariant HttpGet(const char* url); 10 | -------------------------------------------------------------------------------- /networking/httpioapi.cpp: -------------------------------------------------------------------------------- 1 | /* ioapi.c -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | 4 | Version 1.01e, February 12th, 2005 5 | 6 | Copyright (C) 1998-2005 Gilles Vollant 7 | 8 | Modified to integrate with WinHttpRequest. 9 | */ 10 | 11 | #include 12 | 13 | #include "zlib.h" 14 | #include "ioapi.h" 15 | 16 | #include "httprequest_h.h" 17 | 18 | #include 19 | 20 | 21 | voidpf ZCALLBACK qiodevice_open_file_func( 22 | voidpf opaque, 23 | voidpf filename, 24 | int mode) 25 | { 26 | VARIANT varFalse{ VT_BOOL }; 27 | VARIANT varEmpty{ VT_ERROR }; 28 | 29 | CComVariant varStream; 30 | 31 | CComPtr pIWinHttpRequest; 32 | 33 | if (SUCCEEDED(pIWinHttpRequest.CoCreateInstance(L"WinHttp.WinHttpRequest.5.1", nullptr, CLSCTX_INPROC_SERVER)) 34 | && SUCCEEDED(pIWinHttpRequest->Open(CComBSTR(L"GET"), CComBSTR(static_cast(filename)), varFalse)) 35 | && SUCCEEDED(pIWinHttpRequest->Send(varEmpty)) 36 | && SUCCEEDED(pIWinHttpRequest->get_ResponseStream(&varStream))) 37 | { 38 | if (CComQIPtr stream = V_UNKNOWN(&varStream)) 39 | { 40 | return stream.Detach(); 41 | } 42 | } 43 | 44 | return nullptr; 45 | } 46 | 47 | 48 | uLong ZCALLBACK qiodevice_read_file_func( 49 | voidpf, // opaque 50 | voidpf pf, 51 | void* buf, 52 | uLong size) 53 | { 54 | auto stream = static_cast(pf); 55 | uLong ret = 0; 56 | HRESULT hr = stream->Read(buf, size, &ret); 57 | return ret; 58 | } 59 | 60 | 61 | uLong ZCALLBACK qiodevice_write_file_func( 62 | voidpf, // opaque 63 | voidpf pf, 64 | const void* buf, 65 | uLong size) 66 | { 67 | auto stream = static_cast(pf); 68 | uLong ret = 0; 69 | stream->Write(buf, size, &ret); 70 | return ret; 71 | } 72 | 73 | uLong ZCALLBACK qiodevice_tell_file_func( 74 | voidpf, // opaque 75 | voidpf pf) 76 | { 77 | auto stream = static_cast(pf); 78 | const LARGE_INTEGER move{}; 79 | ULARGE_INTEGER libNewPosition{}; 80 | stream->Seek(move, STREAM_SEEK_CUR, &libNewPosition); 81 | return libNewPosition.LowPart; 82 | } 83 | 84 | int ZCALLBACK qiodevice_seek_file_func( 85 | voidpf, // opaque 86 | voidpf pf, 87 | uLong offset, 88 | int origin) 89 | { 90 | STREAM_SEEK dwOrigin; 91 | LARGE_INTEGER move; 92 | switch (origin) 93 | { 94 | case ZLIB_FILEFUNC_SEEK_CUR: 95 | dwOrigin = STREAM_SEEK_CUR; 96 | move.QuadPart = (long)offset; 97 | break; 98 | case ZLIB_FILEFUNC_SEEK_END: 99 | dwOrigin = STREAM_SEEK_END; 100 | move.QuadPart = (long)offset; 101 | break; 102 | case ZLIB_FILEFUNC_SEEK_SET: 103 | dwOrigin = STREAM_SEEK_SET; 104 | move.QuadPart = offset; 105 | break; 106 | default: return -1; 107 | } 108 | auto stream = static_cast(pf); 109 | ULARGE_INTEGER libNewPosition{}; 110 | int ret = FAILED(stream->Seek(move, dwOrigin, &libNewPosition)); 111 | return ret; 112 | } 113 | 114 | int ZCALLBACK qiodevice_close_file_func( 115 | voidpf, // opaque 116 | voidpf pf) 117 | { 118 | auto stream = static_cast(pf); 119 | auto cnt = stream->Release(); 120 | assert(cnt == 0); 121 | return 0; 122 | } 123 | 124 | int ZCALLBACK qiodevice_error_file_func( 125 | voidpf, // opaque 126 | voidpf //stream 127 | ) 128 | { 129 | return 0; 130 | } 131 | 132 | void fill_qiodevice_filefunc( 133 | zlib_filefunc_def* pzlib_filefunc_def) 134 | { 135 | pzlib_filefunc_def->zopen_file = qiodevice_open_file_func; 136 | pzlib_filefunc_def->zread_file = qiodevice_read_file_func; 137 | pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; 138 | pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func; 139 | pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func; 140 | pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; 141 | pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; 142 | pzlib_filefunc_def->opaque = nullptr; 143 | } 144 | -------------------------------------------------------------------------------- /networking/httprequest_i.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ 4 | 5 | /* link this file in with the server and any clients */ 6 | 7 | 8 | /* File created by MIDL compiler version 8.00.0603 */ 9 | /* at Wed Jun 06 11:59:31 2018 10 | */ 11 | /* Compiler settings for C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\httprequest.idl: 12 | Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603 13 | protocol : dce , ms_ext, c_ext, robust 14 | error checks: allocation ref bounds_check enum stub_data 15 | VC __declspec() decoration level: 16 | __declspec(uuid()), __declspec(selectany), __declspec(novtable) 17 | DECLSPEC_UUID(), MIDL_INTERFACE() 18 | */ 19 | /* @@MIDL_FILE_HEADING( ) */ 20 | 21 | #pragma warning( disable: 4049 ) /* more than 64k source lines */ 22 | 23 | 24 | #ifdef __cplusplus 25 | extern "C"{ 26 | #endif 27 | 28 | 29 | #include 30 | #include 31 | 32 | #ifdef _MIDL_USE_GUIDDEF_ 33 | 34 | #ifndef INITGUID 35 | #define INITGUID 36 | #include 37 | #undef INITGUID 38 | #else 39 | #include 40 | #endif 41 | 42 | #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ 43 | DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) 44 | 45 | #else // !_MIDL_USE_GUIDDEF_ 46 | 47 | #ifndef __IID_DEFINED__ 48 | #define __IID_DEFINED__ 49 | 50 | typedef struct _IID 51 | { 52 | unsigned long x; 53 | unsigned short s1; 54 | unsigned short s2; 55 | unsigned char c[8]; 56 | } IID; 57 | 58 | #endif // __IID_DEFINED__ 59 | 60 | #ifndef CLSID_DEFINED 61 | #define CLSID_DEFINED 62 | typedef IID CLSID; 63 | #endif // CLSID_DEFINED 64 | 65 | #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ 66 | const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} 67 | 68 | #endif !_MIDL_USE_GUIDDEF_ 69 | 70 | MIDL_DEFINE_GUID(IID, LIBID_WinHttp,0x662901fc,0x6951,0x4854,0x9e,0xb2,0xd9,0xa2,0x57,0x0f,0x2b,0x2e); 71 | 72 | 73 | MIDL_DEFINE_GUID(IID, IID_IWinHttpRequest,0x016fe2ec,0xb2c8,0x45f8,0xb2,0x3b,0x39,0xe5,0x3a,0x75,0x39,0x6b); 74 | 75 | 76 | MIDL_DEFINE_GUID(IID, IID_IWinHttpRequestEvents,0xf97f4e15,0xb787,0x4212,0x80,0xd1,0xd3,0x80,0xcb,0xbf,0x98,0x2e); 77 | 78 | 79 | MIDL_DEFINE_GUID(CLSID, CLSID_WinHttpRequest,0x2087c2f4,0x2cef,0x4953,0xa8,0xab,0x66,0x77,0x9b,0x67,0x04,0x95); 80 | 81 | #undef MIDL_DEFINE_GUID 82 | 83 | #ifdef __cplusplus 84 | } 85 | #endif 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /networking/ioapi.h: -------------------------------------------------------------------------------- 1 | /* ioapi.h -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | 4 | Version 1.01e, February 12th, 2005 5 | 6 | Copyright (C) 1998-2005 Gilles Vollant 7 | 8 | Modified to integrate with WinHttpRequest. 9 | */ 10 | 11 | #ifndef _ZLIBIOAPI_H 12 | #define _ZLIBIOAPI_H 13 | 14 | 15 | #define ZLIB_FILEFUNC_SEEK_CUR (1) 16 | #define ZLIB_FILEFUNC_SEEK_END (2) 17 | #define ZLIB_FILEFUNC_SEEK_SET (0) 18 | 19 | #define ZLIB_FILEFUNC_MODE_READ (1) 20 | #define ZLIB_FILEFUNC_MODE_WRITE (2) 21 | #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) 22 | 23 | #define ZLIB_FILEFUNC_MODE_EXISTING (4) 24 | #define ZLIB_FILEFUNC_MODE_CREATE (8) 25 | 26 | 27 | #ifndef ZCALLBACK 28 | 29 | #if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) 30 | #define ZCALLBACK CALLBACK 31 | #else 32 | #define ZCALLBACK 33 | #endif 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | typedef voidpf(ZCALLBACK* open_file_func) OF((voidpf opaque, voidpf file, int mode)); 41 | typedef uLong(ZCALLBACK* read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); 42 | typedef uLong(ZCALLBACK* write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); 43 | typedef uLong(ZCALLBACK* tell_file_func) OF((voidpf opaque, voidpf stream)); 44 | typedef int (ZCALLBACK* seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); 45 | typedef int (ZCALLBACK* close_file_func) OF((voidpf opaque, voidpf stream)); 46 | typedef int (ZCALLBACK* testerror_file_func) OF((voidpf opaque, voidpf stream)); 47 | 48 | typedef struct zlib_filefunc_def_s 49 | { 50 | open_file_func zopen_file; 51 | read_file_func zread_file; 52 | write_file_func zwrite_file; 53 | tell_file_func ztell_file; 54 | seek_file_func zseek_file; 55 | close_file_func zclose_file; 56 | testerror_file_func zerror_file; 57 | voidpf opaque; 58 | } zlib_filefunc_def; 59 | 60 | 61 | 62 | void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); 63 | 64 | #define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) 65 | #define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) 66 | #define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) 67 | #define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) 68 | #define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) 69 | #define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) 70 | 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif 75 | 76 | #endif 77 | 78 | -------------------------------------------------------------------------------- /networking/networking.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | -------------------------------------------------------------------------------- /remove_pytube.cmd: -------------------------------------------------------------------------------- 1 | RD "%LOCALAPPDATA%\pytube-master" /S /Q 2 | -------------------------------------------------------------------------------- /remove_youtube_transcript_api.cmd: -------------------------------------------------------------------------------- 1 | RD "%LOCALAPPDATA%\youtube-transcript-api-master" /S /Q 2 | -------------------------------------------------------------------------------- /video/audioplayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct IAudioPlayerCallback 6 | { 7 | virtual void AppendFrameClock(double frame_clock) = 0; 8 | }; 9 | 10 | struct IAudioPlayer 11 | { 12 | virtual ~IAudioPlayer() = default; 13 | virtual void SetCallback(IAudioPlayerCallback* callback) = 0; 14 | 15 | virtual void InitializeThread() = 0; 16 | virtual void DeinitializeThread() = 0; 17 | 18 | virtual void Close() = 0; 19 | virtual bool Open(int bytesPerSample, int channels, int* samplesPerSec) = 0; 20 | 21 | virtual void SetVolume(double volume) = 0; 22 | virtual double GetVolume() const = 0; 23 | 24 | // stops playback on the given output device and resets the current position 25 | virtual void WaveOutReset() = 0; 26 | // pauses playback on the given output device 27 | virtual void WaveOutPause() = 0; 28 | // resumes playback on a paused output device 29 | virtual void WaveOutRestart() = 0; 30 | 31 | virtual bool WriteAudio(uint8_t* write_data, int64_t write_size) = 0; 32 | }; 33 | -------------------------------------------------------------------------------- /video/decoderiocontext.cpp: -------------------------------------------------------------------------------- 1 | #include "decoderiocontext.h" 2 | 3 | extern "C" 4 | { 5 | #include 6 | } 7 | 8 | 9 | // static 10 | int DecoderIOContext::IOReadFunc(void *data, uint8_t *buf, int buf_size) 11 | { 12 | auto *hctx = static_cast(data); 13 | try 14 | { 15 | auto len = hctx->stream->sgetn((char*)buf, buf_size); 16 | if (len <= 0) 17 | { 18 | // Let FFmpeg know that we have reached EOF, or do something else 19 | return AVERROR_EOF; 20 | } 21 | return static_cast(len); 22 | } 23 | catch (const std::exception&) 24 | { 25 | // Handle any exceptions that may occur during sgetn 26 | return AVERROR(EIO); 27 | } 28 | } 29 | 30 | // whence: SEEK_SET, SEEK_CUR, SEEK_END (like fseek) and AVSEEK_SIZE 31 | // static 32 | int64_t DecoderIOContext::IOSeekFunc(void *data, int64_t pos, int whence) 33 | { 34 | auto *hctx = static_cast(data); 35 | 36 | if (whence == AVSEEK_SIZE) 37 | { 38 | // return the file size if you wish to 39 | auto current = hctx->stream->pubseekoff(0, std::ios_base::cur, std::ios_base::in); 40 | auto result = hctx->stream->pubseekoff(0, std::ios_base::end, std::ios_base::in); 41 | hctx->stream->pubseekoff(current, std::ios_base::beg, std::ios_base::in); 42 | return result; 43 | } 44 | 45 | std::ios_base::seekdir dir; 46 | switch (whence) 47 | { 48 | case SEEK_SET: 49 | dir = std::ios_base::beg; 50 | break; 51 | case SEEK_CUR: 52 | dir = std::ios_base::cur; 53 | break; 54 | case SEEK_END: 55 | dir = std::ios_base::end; 56 | break; 57 | default: 58 | return -1LL; 59 | } 60 | 61 | return hctx->stream->pubseekoff(pos, dir); 62 | } 63 | 64 | DecoderIOContext::DecoderIOContext(std::unique_ptr s) 65 | : stream(std::move(s)) 66 | { 67 | // allocate buffer 68 | bufferSize = 1024 * 64; // FIXME: not sure what size to use 69 | buffer = static_cast(av_malloc(bufferSize)); // see destructor for details 70 | 71 | // allocate the AVIOContext 72 | ioCtx = 73 | avio_alloc_context(buffer, bufferSize, // internal buffer and its size 74 | 0, // write flag (1=true,0=false) 75 | (void *)this, // user data, will be passed to our callback functions 76 | IOReadFunc, 77 | nullptr, // no writing 78 | IOSeekFunc); 79 | } 80 | 81 | DecoderIOContext::~DecoderIOContext() 82 | { 83 | //CHANNEL_LOG(ffmpeg_closing) << "In DecoderIOContext::~DecoderIOContext()"; 84 | 85 | // NOTE: ffmpeg messes up the buffer 86 | // so free the buffer first then free the context 87 | av_free(ioCtx->buffer); 88 | ioCtx->buffer = nullptr; 89 | av_free(ioCtx); 90 | } 91 | 92 | void DecoderIOContext::initAVFormatContext(AVFormatContext *pCtx) 93 | { 94 | pCtx->pb = ioCtx; 95 | pCtx->flags |= AVFMT_FLAG_CUSTOM_IO; 96 | 97 | // you can specify a format directly 98 | // pCtx->iformat = av_find_input_format("h264"); 99 | 100 | // or read some of the file and let ffmpeg do the guessing 101 | auto len = stream->sgetn((char *)buffer, bufferSize); 102 | if (len <= 0) 103 | { 104 | return; 105 | } 106 | // reset to beginning of file 107 | stream->pubseekoff(0, std::ios_base::beg, std::ios_base::in); 108 | 109 | AVProbeData probeData = {nullptr}; 110 | probeData.buf = buffer; 111 | probeData.buf_size = bufferSize - 1; 112 | probeData.filename = ""; 113 | pCtx->iformat = av_probe_input_format(&probeData, 1); 114 | } 115 | -------------------------------------------------------------------------------- /video/decoderiocontext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct AVIOContext; 8 | struct AVFormatContext; 9 | 10 | class DecoderIOContext 11 | { 12 | private: 13 | AVIOContext *ioCtx; 14 | uint8_t *buffer; // internal buffer for ffmpeg 15 | int bufferSize; 16 | std::unique_ptr stream; 17 | 18 | public: 19 | DecoderIOContext(std::unique_ptr s); 20 | ~DecoderIOContext(); 21 | 22 | void initAVFormatContext(AVFormatContext * /*pCtx*/); 23 | 24 | static int IOReadFunc(void *data, uint8_t *buf, int buf_size); 25 | static int64_t IOSeekFunc(void *data, int64_t pos, int whence); 26 | }; 27 | -------------------------------------------------------------------------------- /video/displayrunnable.cpp: -------------------------------------------------------------------------------- 1 | #include "ffmpegdecoder.h" 2 | 3 | #include 4 | 5 | void FFmpegDecoder::displayRunnable() 6 | { 7 | CHANNEL_LOG(ffmpeg_threads) << "Displaying thread started"; 8 | 9 | #ifdef TRACE_DELAY_STATS 10 | double sumIndications = 0; 11 | double sqSumIndications = 0; 12 | 13 | enum { MAX_INDICATIONS = 200 }; 14 | int numIndications = 0; 15 | #endif 16 | 17 | while (!boost::this_thread::interruption_requested()) 18 | { 19 | { 20 | boost::unique_lock locker(m_videoFramesMutex); 21 | m_videoFramesCV.wait(locker, [this]() 22 | { 23 | return !m_frameDisplayingRequested && 24 | m_videoFramesQueue.canPop(); 25 | }); 26 | } 27 | 28 | VideoFrame& current_frame = m_videoFramesQueue.front(); 29 | m_frameDisplayingRequested = true; 30 | 31 | if (current_frame.m_convert.valid() && !current_frame.m_convert.get()) { 32 | finishedDisplayingFrame(m_generation); 33 | continue; 34 | } 35 | 36 | assert(m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED); 37 | 38 | // Frame skip 39 | if (!m_videoFramesQueue.canPush() 40 | && m_videoStartClock + current_frame.m_pts < GetHiResTime()) 41 | { 42 | CHANNEL_LOG(ffmpeg_threads) << __FUNCTION__ << " Framedrop"; 43 | finishedDisplayingFrame(m_generation); 44 | continue; 45 | } 46 | 47 | const auto pts = current_frame.m_pts; 48 | const auto duration = current_frame.m_duration; 49 | 50 | // Possibly give it time to render frame 51 | if (m_frameListener != nullptr) 52 | { 53 | m_frameListener->updateFrame(this, m_generation); 54 | } 55 | 56 | const auto speed = getSpeedRational(); 57 | 58 | for (;;) 59 | { 60 | const double delay = m_videoStartClock + pts - GetHiResTime(); 61 | if (delay < 0.005) { 62 | break; 63 | } 64 | if (delay > 0.1) 65 | { 66 | boost::this_thread::sleep_for( 67 | boost::chrono::milliseconds(100 * speed.denominator / speed.numerator)); 68 | continue; 69 | } 70 | 71 | boost::this_thread::sleep_for( 72 | boost::chrono::milliseconds(int(delay * 1000. * speed.denominator / speed.numerator))); 73 | break; 74 | } 75 | 76 | // It's time to display converted frame 77 | if (duration != AV_NOPTS_VALUE) 78 | { 79 | m_currentTime = duration; 80 | if ((m_decoderListener != nullptr) && m_seekDuration == AV_NOPTS_VALUE) 81 | { 82 | m_decoderListener->changedFramePosition( 83 | m_startTime, 84 | duration, 85 | m_duration + m_startTime); 86 | } 87 | } 88 | 89 | #ifdef TRACE_DELAY_STATS 90 | const double delay = m_videoStartClock + pts - GetHiResTime(); 91 | sumIndications += delay; 92 | sqSumIndications += delay * delay; 93 | if (++numIndications >= MAX_INDICATIONS) 94 | { 95 | const double avg = sumIndications / numIndications; 96 | CHANNEL_LOG(ffmpeg_threads) << "Average frame delay: " << avg 97 | << "; frame delay deviation: " << sqrt(sqSumIndications / numIndications - avg * avg); 98 | sumIndications = 0; 99 | sqSumIndications = 0; 100 | numIndications = 0; 101 | } 102 | #endif 103 | 104 | if (m_frameListener != nullptr) 105 | { 106 | m_frameListener->drawFrame(this, m_generation); 107 | } 108 | else 109 | { 110 | finishedDisplayingFrame(m_generation); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /video/ffmpeg_dxva2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * This file is part of FFmpeg. 5 | * 6 | * FFmpeg is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * FFmpeg 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 GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with FFmpeg; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifdef _WIN32 22 | 23 | typedef struct AVCodecContext AVCodecContext; 24 | typedef struct AVFrame AVFrame; 25 | 26 | typedef struct IDirect3DDevice9 IDirect3DDevice9; 27 | typedef struct IDirect3DSurface9 IDirect3DSurface9; 28 | 29 | int dxva2_init(AVCodecContext *s); 30 | void dxva2_uninit(void* ist); 31 | int dxva2_convert_data(IDirect3DSurface9* surface, AVFrame *tmp_frame, int width, int height); 32 | int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame); 33 | 34 | IDirect3DDevice9* get_device(AVCodecContext *s); 35 | 36 | #endif // _WIN32 37 | -------------------------------------------------------------------------------- /video/fqueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | class FQueue 10 | { 11 | public: 12 | FQueue() {} 13 | FQueue(const FQueue&) = delete; 14 | FQueue& operator=(const FQueue&) = delete; 15 | 16 | template 17 | bool push(const AVPacket& packet, T abortFunc) 18 | { 19 | const auto pos = packet.pos; 20 | const auto dts = packet.dts; 21 | auto& prev = m_positions[packet.stream_index]; 22 | if ((dts != AV_NOPTS_VALUE) ? dts < prev.m_dts 23 | : (pos != -1 && pos < prev.m_pos)) 24 | { 25 | return false; 26 | } 27 | 28 | bool wasEmpty; 29 | { 30 | boost::unique_lock locker(m_mutex); 31 | while (isPacketsQueueFull()) 32 | { 33 | if (abortFunc()) 34 | { 35 | return false; 36 | } 37 | m_condVar.wait(locker); 38 | } 39 | wasEmpty = m_queue.empty(); 40 | enqueue(packet); 41 | if (pos != -1) 42 | prev.m_pos = pos; 43 | if (dts != AV_NOPTS_VALUE) 44 | prev.m_dts = dts; 45 | } 46 | if (wasEmpty) 47 | { 48 | m_condVar.notify_all(); 49 | } 50 | 51 | return true; 52 | } 53 | 54 | template 55 | bool pop(AVPacket& packet, T abortFunc = T()) 56 | { 57 | bool wasFull; 58 | { 59 | boost::unique_lock locker(m_mutex); 60 | 61 | while (m_queue.empty()) 62 | { 63 | if (abortFunc()) 64 | { 65 | return false; 66 | } 67 | m_condVar.wait(locker); 68 | } 69 | 70 | wasFull = isPacketsQueueFull(); 71 | packet = dequeue(); 72 | } 73 | if (wasFull) 74 | { 75 | m_condVar.notify_all(); 76 | } 77 | 78 | return true; 79 | } 80 | 81 | void clear() 82 | { 83 | for (AVPacket& packet : m_queue) 84 | { 85 | av_packet_unref(&packet); 86 | } 87 | m_packetsSize = 0; 88 | m_positions.clear(); 89 | std::deque().swap(m_queue); 90 | } 91 | 92 | bool empty() 93 | { 94 | boost::lock_guard locker(m_mutex); 95 | return m_queue.empty(); 96 | } 97 | 98 | void notify() 99 | { 100 | m_condVar.notify_all(); 101 | } 102 | 103 | private: 104 | AVPacket dequeue() 105 | { 106 | assert(!m_queue.empty()); 107 | AVPacket packet = m_queue.front(); 108 | m_queue.pop_front(); 109 | m_packetsSize -= packet.size; 110 | assert(m_packetsSize >= 0); 111 | return packet; 112 | } 113 | 114 | void enqueue(const AVPacket& packet) 115 | { 116 | m_packetsSize += packet.size; 117 | assert(m_packetsSize >= 0); 118 | m_queue.push_back(packet); 119 | } 120 | 121 | bool isPacketsQueueFull() const 122 | { 123 | return m_packetsSize > MAX_QUEUE_SIZE || 124 | m_queue.size() > MAX_FRAMES; 125 | } 126 | 127 | private: 128 | struct PositionData 129 | { 130 | int64_t m_pos = -1; 131 | int64_t m_dts = AV_NOPTS_VALUE; 132 | }; 133 | 134 | int64_t m_packetsSize = 0; 135 | std::deque m_queue; 136 | 137 | boost::mutex m_mutex; 138 | boost::condition_variable m_condVar; 139 | 140 | std::map m_positions; 141 | }; 142 | -------------------------------------------------------------------------------- /video/interlockedadd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | inline void InterLockedAdd(boost::atomic& clock, double correction) 6 | { 7 | for (double v = clock; !clock.compare_exchange_weak(v, v + correction);) 8 | { 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /video/makeguard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | inline auto MakeGuard(T* t, D d) 8 | { 9 | return std::unique_ptr(t, std::move(d)); 10 | } 11 | -------------------------------------------------------------------------------- /video/subtitles.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern "C" { 4 | #include 5 | } 6 | 7 | #include 8 | 9 | AVCodecContext* MakeSubtitlesCodecContext(AVCodecParameters* codecpar); 10 | std::string GetSubtitle(AVCodecContext* ctx, const AVPacket& packet); 11 | -------------------------------------------------------------------------------- /video/video.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /video/videoframe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct AVFrameDeleter 7 | { 8 | void operator()(AVFrame *frame) const { av_frame_free(&frame); }; 9 | }; 10 | 11 | typedef std::unique_ptr AVFramePtr; 12 | 13 | struct VideoFrame 14 | { 15 | double m_pts{0}; 16 | int64_t m_duration{0}; 17 | AVFramePtr m_image; 18 | std::future m_convert; 19 | 20 | VideoFrame() 21 | : m_image(av_frame_alloc()) 22 | {} 23 | 24 | VideoFrame(const VideoFrame&) = delete; 25 | VideoFrame& operator=(const VideoFrame&) = delete; 26 | 27 | void free() 28 | { 29 | m_convert = {}; // Finish first 30 | av_frame_unref(m_image.get()); 31 | } 32 | void realloc(AVPixelFormat pix_fmt, int width, int height) 33 | { 34 | if (pix_fmt != m_image->format || width != m_image->width || height != m_image->height) 35 | { 36 | av_frame_unref(m_image.get()); 37 | 38 | m_image->format = pix_fmt; 39 | m_image->width = width; 40 | m_image->height = height; 41 | av_frame_get_buffer(m_image.get(), 16); 42 | } 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /video/vqueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Video frame struct for RGB24 frame (used by displays) 6 | class VQueue 7 | { 8 | public: 9 | VQueue() = default; 10 | VQueue(const VQueue&) = delete; 11 | VQueue& operator=(const VQueue&) = delete; 12 | 13 | void clear() 14 | { 15 | for (auto& frame : m_frames) 16 | { 17 | frame.free(); 18 | } 19 | 20 | // Reset readers 21 | m_write_counter = 0; 22 | m_read_counter = 0; 23 | m_busy = 0; 24 | } 25 | 26 | bool canPush() const { return m_busy < QUEUE_SIZE; } 27 | VideoFrame& back() { return m_frames[m_write_counter]; } 28 | void pushBack() 29 | { 30 | m_write_counter = (m_write_counter + 1) % QUEUE_SIZE; 31 | ++m_busy; 32 | assert(m_busy <= VQueue::QUEUE_SIZE); 33 | } 34 | 35 | bool canPop() const { return m_busy > 0; } 36 | VideoFrame& front() { return m_frames[m_read_counter]; } 37 | void popFront() 38 | { 39 | --m_busy; 40 | assert(m_busy >= 0); 41 | m_read_counter = (m_read_counter + 1) % QUEUE_SIZE; 42 | } 43 | 44 | private: 45 | enum { QUEUE_SIZE = 2 }; // enough for displaying one frame. 46 | 47 | VideoFrame m_frames[QUEUE_SIZE]; 48 | int m_write_counter = 0; 49 | int m_read_counter = 0; 50 | int m_busy = 0; 51 | }; 52 | --------------------------------------------------------------------------------